Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/face/errors.py: 69%
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
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
1from boltons.iterutils import unique
3import face.utils
5class FaceException(Exception):
6 """The basest base exception Face has. Rarely directly instantiated
7 if ever, but useful for catching.
8 """
9 pass
12class ArgumentParseError(FaceException):
13 """A base exception used for all errors raised during argument
14 parsing.
16 Many subtypes have a ".from_parse()" classmethod that creates an
17 exception message from the values available during the parse
18 process.
19 """
20 pass
23class ArgumentArityError(ArgumentParseError):
24 """Raised when too many or too few positional arguments are passed to
25 the command. See PosArgSpec for more info.
26 """
27 pass
30class InvalidSubcommand(ArgumentParseError):
31 """
32 Raised when an unrecognized subcommand is passed.
33 """
34 @classmethod
35 def from_parse(cls, prs, subcmd_name):
36 # TODO: add edit distance calculation
37 valid_subcmds = unique([path[:1][0] for path in prs.subprs_map.keys()])
38 msg = ('unknown subcommand "%s", choose from: %s'
39 % (subcmd_name, ', '.join(valid_subcmds)))
40 return cls(msg)
43class UnknownFlag(ArgumentParseError):
44 """
45 Raised when an unrecognized flag is passed.
46 """
47 @classmethod
48 def from_parse(cls, cmd_flag_map, flag_name):
49 # TODO: add edit distance calculation
50 valid_flags = unique([face.utils.format_flag_label(flag) for flag in
51 cmd_flag_map.values() if not flag.display.hidden])
52 msg = f"unknown flag \"{flag_name}\", choose from: {', '.join(valid_flags)}"
53 return cls(msg)
56class InvalidFlagArgument(ArgumentParseError):
57 """Raised when the argument passed to a flag (the value directly
58 after it in argv) fails to parse. Tries to automatically detect
59 when an argument is missing.
60 """
61 @classmethod
62 def from_parse(cls, cmd_flag_map, flag, arg, exc=None):
63 if arg is None:
64 return cls(f'expected argument for flag {flag.name}')
66 val_parser = flag.parse_as
67 vp_label = getattr(val_parser, 'display_name', face.utils.FRIENDLY_TYPE_NAMES.get(val_parser))
68 if vp_label is None:
69 vp_label = repr(val_parser)
70 tmpl = 'flag %s converter (%r) failed to parse value: %r'
71 else:
72 tmpl = 'flag %s expected a valid %s value, not %r'
73 msg = tmpl % (flag.name, vp_label, arg)
75 if exc:
76 # TODO: put this behind a verbose flag?
77 msg += f' (got error: {exc!r})'
78 if arg.startswith('-'):
79 msg += '. (Did you forget to pass an argument?)'
81 return cls(msg)
84class InvalidPositionalArgument(ArgumentParseError):
85 """Raised when one of the positional arguments does not
86 parse/validate as specified. See PosArgSpec for more info.
87 """
88 @classmethod
89 def from_parse(cls, posargspec, arg, exc):
90 prep, type_desc = face.utils.get_type_desc(posargspec.parse_as)
91 return cls('positional argument failed to parse %s'
92 ' %s: %r (got error: %r)' % (prep, type_desc, arg, exc))
95class MissingRequiredFlags(ArgumentParseError):
96 """
97 Raised when a required flag is not passed. See Flag for more info.
98 """
99 @classmethod
100 def from_parse(cls, cmd_flag_map, parsed_flag_map, missing_flag_names):
101 flag_names = set(missing_flag_names)
102 labels = []
103 for flag_name in flag_names:
104 flag = cmd_flag_map[flag_name]
105 labels.append(face.utils.format_flag_label(flag))
106 msg = f"missing required arguments for flags: {', '.join(sorted(labels))}"
107 return cls(msg)
110class DuplicateFlag(ArgumentParseError):
111 """Raised when a flag is passed multiple times, and the flag's
112 "multi" setting is set to 'error'.
113 """
114 @classmethod
115 def from_parse(cls, flag, arg_val_list):
116 avl_text = ', '.join([repr(v) for v in arg_val_list])
117 if callable(flag.parse_as):
118 msg = f'more than one value was passed for flag "{flag.name}": {avl_text}'
119 else:
120 msg = f'flag "{flag.name}" was used multiple times, but can be used only once'
121 return cls(msg)
124## Non-parse related exceptions (used primarily in command.py instead of parser.py)
126class CommandLineError(FaceException, SystemExit):
127 """A :exc:`~face.FaceException` and :exc:`SystemExit` subtype that
128 enables safely catching runtime errors that would otherwise cause
129 the process to exit.
131 If instances of this exception are left uncaught, they will exit
132 the process.
134 If raised from a :meth:`~face.Command.run()` call and
135 ``print_error`` is True, face will print the error before
136 reraising. See :meth:`face.Command.run()` for more details.
137 """
138 def __init__(self, msg, code=1):
139 SystemExit.__init__(self, msg)
140 self.code = code
143class UsageError(CommandLineError):
144 """Application developers should raise this :exc:`CommandLineError`
145 subtype to indicate to users that the application user has used
146 the command incorrectly.
148 Instead of printing an ugly stack trace, Face will print a
149 readable error message of your choosing, then exit with a nonzero
150 exit code.
151 """
153 def format_message(self):
154 msg = self.args[0]
155 lines = msg.splitlines()
156 msg = '\n '.join(lines)
157 return 'error: ' + msg