Coverage for /builds/ase/ase/ase/cli/completion.py: 75.47%

53 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-08-02 00:12 +0000

1# fmt: off 

2 

3"""TAB-completion sub-command and update helper funtion. 

4 

5Run this when ever options are changed:: 

6 

7 python3 -m ase.cli.completion 

8""" 

9 

10import sys 

11from pathlib import Path 

12from typing import Dict, List, Tuple 

13 

14# Path of the complete.py script: 

15path = Path(__file__).with_name('complete.py') 

16 

17 

18class CLICommand: 

19 """Add tab-completion for Bash. 

20 

21 Will show the command that needs to be added to your '~/.bashrc file. 

22 """ 

23 cmd = f'complete -o default -C "{sys.executable} {path}" ase' 

24 

25 @staticmethod 

26 def add_arguments(parser): 

27 pass 

28 

29 @staticmethod 

30 def run(args): 

31 cmd = CLICommand.cmd 

32 print(cmd) 

33 

34 

35def update(path: Path, 

36 subcommands: List[Tuple[str, str]], 

37 test: bool = False) -> None: 

38 """Update commands dict in complete.py. 

39 

40 Use test=True to test that no changes are needed. 

41 

42 Refactor with care! This function is also used by GPAW. 

43 """ 

44 

45 import textwrap 

46 from importlib import import_module 

47 

48 dct: Dict[str, List[str]] = {} 

49 

50 class Subparser: 

51 def __init__(self, command): 

52 self.command = command 

53 dct[command] = [] 

54 

55 def add_argument(self, *args, **kwargs): 

56 dct[command].extend(arg for arg in args 

57 if arg.startswith('-')) 

58 

59 def add_argument_group(self, name): 

60 return self 

61 

62 def add_mutually_exclusive_group(self, required=False): 

63 return self 

64 

65 for command, module_name in subcommands: 

66 module = import_module(module_name) 

67 module.CLICommand.add_arguments(Subparser(command)) 

68 

69 txt = 'commands = {' 

70 for command, opts in sorted(dct.items()): 

71 txt += "\n '" + command + "':\n [" 

72 if opts: 

73 txt += '\n'.join(textwrap.wrap("'" + "', '".join(opts) + "'],", 

74 width=65, 

75 break_on_hyphens=False, 

76 subsequent_indent=' ')) 

77 else: 

78 txt += '],' 

79 txt = txt[:-1] + '}\n' 

80 

81 with path.open() as fd: 

82 lines = fd.readlines() 

83 

84 a = lines.index('# Beginning of computer generated data:\n') 

85 b = lines.index('# End of computer generated data\n') 

86 

87 if test: 

88 if ''.join(lines[a + 1:b]) != txt: 

89 raise ValueError( 

90 'Please update ase/cli/complete.py using ' 

91 '"python3 -m ase.cli.completion".') 

92 else: 

93 lines[a + 1:b] = [txt] 

94 new = path.with_name('complete.py.new') 

95 with new.open('w') as fd: 

96 print(''.join(lines), end='', file=fd) 

97 new.rename(path) 

98 path.chmod(0o775) 

99 

100 

101if __name__ == '__main__': 

102 from ase.cli.main import commands 

103 update(path, commands)