Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import argparse 

2import sys 

3import textwrap 

4from importlib import import_module 

5 

6from ase import __version__ 

7 

8 

9class CLIError(Exception): 

10 """Error for CLI commands. 

11 

12 A subcommand may raise this. The message will be forwarded to 

13 the error() method of the argument parser.""" 

14 

15 

16# Important: Following any change to command-line parameters, use 

17# python3 -m ase.cli.completion to update autocompletion. 

18commands = [ 

19 ('info', 'ase.cli.info'), 

20 # ('show', 'ase.cli.show'), 

21 ('test', 'ase.test'), 

22 ('gui', 'ase.gui.ag'), 

23 ('db', 'ase.db.cli'), 

24 ('run', 'ase.cli.run'), 

25 ('band-structure', 'ase.cli.band_structure'), 

26 ('build', 'ase.cli.build'), 

27 ('dimensionality', 'ase.cli.dimensionality'), 

28 ('eos', 'ase.eos'), 

29 ('ulm', 'ase.io.ulm'), 

30 ('find', 'ase.cli.find'), 

31 ('nebplot', 'ase.cli.nebplot'), 

32 ('nomad-upload', 'ase.cli.nomad'), 

33 ('nomad-get', 'ase.cli.nomadget'), 

34 ('convert', 'ase.cli.convert'), 

35 ('reciprocal', 'ase.cli.reciprocal'), 

36 ('completion', 'ase.cli.completion'), 

37 ('diff', 'ase.cli.diff'), 

38 ('exec', 'ase.cli.exec') 

39] 

40 

41 

42def main(prog='ase', description='ASE command line tool.', 

43 version=__version__, commands=commands, hook=None, args=None): 

44 parser = argparse.ArgumentParser(prog=prog, 

45 description=description, 

46 formatter_class=Formatter) 

47 parser.add_argument('--version', action='version', 

48 version='%(prog)s-{}'.format(version)) 

49 parser.add_argument('-T', '--traceback', action='store_true') 

50 subparsers = parser.add_subparsers(title='Sub-commands', 

51 dest='command') 

52 

53 subparser = subparsers.add_parser('help', 

54 description='Help', 

55 help='Help for sub-command.') 

56 subparser.add_argument('helpcommand', 

57 nargs='?', 

58 metavar='sub-command', 

59 help='Provide help for sub-command.') 

60 

61 functions = {} 

62 parsers = {} 

63 for command, module_name in commands: 

64 cmd = import_module(module_name).CLICommand 

65 docstring = cmd.__doc__ 

66 if docstring is None: 

67 # Backwards compatibility with GPAW 

68 short = cmd.short_description 

69 long = getattr(cmd, 'description', short) 

70 else: 

71 parts = docstring.split('\n', 1) 

72 if len(parts) == 1: 

73 short = docstring 

74 long = docstring 

75 else: 

76 short, body = parts 

77 long = short + '\n' + textwrap.dedent(body) 

78 subparser = subparsers.add_parser( 

79 command, 

80 formatter_class=Formatter, 

81 help=short, 

82 description=long) 

83 cmd.add_arguments(subparser) 

84 functions[command] = cmd.run 

85 parsers[command] = subparser 

86 

87 if hook: 

88 args = hook(parser, args) 

89 else: 

90 args = parser.parse_args(args) 

91 

92 if args.command == 'help': 

93 if args.helpcommand is None: 

94 parser.print_help() 

95 else: 

96 parsers[args.helpcommand].print_help() 

97 elif args.command is None: 

98 parser.print_usage() 

99 else: 

100 f = functions[args.command] 

101 try: 

102 if f.__code__.co_argcount == 1: 

103 f(args) 

104 else: 

105 f(args, parsers[args.command]) 

106 except KeyboardInterrupt: 

107 pass 

108 except CLIError as x: 

109 parser.error(x) 

110 except Exception as x: 

111 if args.traceback: 

112 raise 

113 else: 

114 l1 = '{}: {}\n'.format(x.__class__.__name__, x) 

115 l2 = ('To get a full traceback, use: {} -T {} ...' 

116 .format(prog, args.command)) 

117 parser.error(l1 + l2) 

118 

119 

120class Formatter(argparse.HelpFormatter): 

121 """Improved help formatter.""" 

122 

123 def _fill_text(self, text, width, indent): 

124 assert indent == '' 

125 out = '' 

126 blocks = text.split('\n\n') 

127 for block in blocks: 

128 if block[0] == '*': 

129 # List items: 

130 for item in block[2:].split('\n* '): 

131 out += textwrap.fill(item, 

132 width=width - 2, 

133 initial_indent='* ', 

134 subsequent_indent=' ') + '\n' 

135 elif block[0] == ' ': 

136 # Indented literal block: 

137 out += block + '\n' 

138 else: 

139 # Block of text: 

140 out += textwrap.fill(block, width=width) + '\n' 

141 out += '\n' 

142 return out[:-1] 

143 

144 

145def old(): 

146 cmd = sys.argv[0].split('-')[-1] 

147 print('Please use "ase {cmd}" instead of "ase-{cmd}"'.format(cmd=cmd)) 

148 sys.argv[:1] = ['ase', cmd] 

149 main()