Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/face/errors.py: 42%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

71 statements  

1 

2from boltons.iterutils import unique 

3 

4import face.utils 

5 

6class FaceException(Exception): 

7 """The basest base exception Face has. Rarely directly instantiated 

8 if ever, but useful for catching. 

9 """ 

10 pass 

11 

12 

13class ArgumentParseError(FaceException): 

14 """A base exception used for all errors raised during argument 

15 parsing. 

16 

17 Many subtypes have a ".from_parse()" classmethod that creates an 

18 exception message from the values available during the parse 

19 process. 

20 """ 

21 pass 

22 

23 

24class ArgumentArityError(ArgumentParseError): 

25 """Raised when too many or too few positional arguments are passed to 

26 the command. See PosArgSpec for more info. 

27 """ 

28 pass 

29 

30 

31class InvalidSubcommand(ArgumentParseError): 

32 """ 

33 Raised when an unrecognized subcommand is passed. 

34 """ 

35 @classmethod 

36 def from_parse(cls, prs, subcmd_name): 

37 # TODO: add edit distance calculation 

38 valid_subcmds = unique([path[:1][0] for path in prs.subprs_map.keys()]) 

39 msg = ('unknown subcommand "%s", choose from: %s' 

40 % (subcmd_name, ', '.join(valid_subcmds))) 

41 return cls(msg) 

42 

43 

44class UnknownFlag(ArgumentParseError): 

45 """ 

46 Raised when an unrecognized flag is passed. 

47 """ 

48 @classmethod 

49 def from_parse(cls, cmd_flag_map, flag_name): 

50 # TODO: add edit distance calculation 

51 valid_flags = unique([face.utils.format_flag_label(flag) for flag in 

52 cmd_flag_map.values() if not flag.display.hidden]) 

53 msg = ('unknown flag "%s", choose from: %s' 

54 % (flag_name, ', '.join(valid_flags))) 

55 return cls(msg) 

56 

57 

58class InvalidFlagArgument(ArgumentParseError): 

59 """Raised when the argument passed to a flag (the value directly 

60 after it in argv) fails to parse. Tries to automatically detect 

61 when an argument is missing. 

62 """ 

63 @classmethod 

64 def from_parse(cls, cmd_flag_map, flag, arg, exc=None): 

65 if arg is None: 

66 return cls('expected argument for flag %s' % flag.name) 

67 

68 val_parser = flag.parse_as 

69 vp_label = getattr(val_parser, 'display_name', face.utils.FRIENDLY_TYPE_NAMES.get(val_parser)) 

70 if vp_label is None: 

71 vp_label = repr(val_parser) 

72 tmpl = 'flag %s converter (%r) failed to parse value: %r' 

73 else: 

74 tmpl = 'flag %s expected a valid %s value, not %r' 

75 msg = tmpl % (flag.name, vp_label, arg) 

76 

77 if exc: 

78 # TODO: put this behind a verbose flag? 

79 msg += ' (got error: %r)' % exc 

80 if arg.startswith('-'): 

81 msg += '. (Did you forget to pass an argument?)' 

82 

83 return cls(msg) 

84 

85 

86class InvalidPositionalArgument(ArgumentParseError): 

87 """Raised when one of the positional arguments does not 

88 parse/validate as specified. See PosArgSpec for more info. 

89 """ 

90 @classmethod 

91 def from_parse(cls, posargspec, arg, exc): 

92 prep, type_desc = face.utils.get_type_desc(posargspec.parse_as) 

93 return cls('positional argument failed to parse %s' 

94 ' %s: %r (got error: %r)' % (prep, type_desc, arg, exc)) 

95 

96 

97class MissingRequiredFlags(ArgumentParseError): 

98 """ 

99 Raised when a required flag is not passed. See Flag for more info. 

100 """ 

101 @classmethod 

102 def from_parse(cls, cmd_flag_map, parsed_flag_map, missing_flag_names): 

103 flag_names = set(missing_flag_names) 

104 labels = [] 

105 for flag_name in flag_names: 

106 flag = cmd_flag_map[flag_name] 

107 labels.append(face.utils.format_flag_label(flag)) 

108 msg = ('missing required arguments for flags: %s' 

109 % ', '.join(sorted(labels))) 

110 return cls(msg) 

111 

112 

113class DuplicateFlag(ArgumentParseError): 

114 """Raised when a flag is passed multiple times, and the flag's 

115 "multi" setting is set to 'error'. 

116 """ 

117 @classmethod 

118 def from_parse(cls, flag, arg_val_list): 

119 avl_text = ', '.join([repr(v) for v in arg_val_list]) 

120 if callable(flag.parse_as): 

121 msg = ('more than one value was passed for flag "%s": %s' 

122 % (flag.name, avl_text)) 

123 else: 

124 msg = ('flag "%s" was used multiple times, but can be used only once' % flag.name) 

125 return cls(msg) 

126 

127 

128## Non-parse related exceptions (used primarily in command.py instead of parser.py) 

129 

130class CommandLineError(FaceException, SystemExit): 

131 """A :exc:`~face.FaceException` and :exc:`SystemExit` subtype that 

132 enables safely catching runtime errors that would otherwise cause 

133 the process to exit. 

134 

135 If instances of this exception are left uncaught, they will exit 

136 the process. 

137 

138 If raised from a :meth:`~face.Command.run()` call and 

139 ``print_error`` is True, face will print the error before 

140 reraising. See :meth:`face.Command.run()` for more details. 

141 """ 

142 def __init__(self, msg, code=1): 

143 SystemExit.__init__(self, msg) 

144 self.code = code 

145 

146 

147class UsageError(CommandLineError): 

148 """Application developers should raise this :exc:`CommandLineError` 

149 subtype to indicate to users that the application user has used 

150 the command incorrectly. 

151 

152 Instead of printing an ugly stack trace, Face will print a 

153 readable error message of your choosing, then exit with a nonzero 

154 exit code. 

155 """ 

156 

157 def format_message(self): 

158 msg = self.args[0] 

159 lines = msg.splitlines() 

160 msg = '\n '.join(lines) 

161 return 'error: ' + msg