• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oir / startle / 21801947980

08 Feb 2026 05:03PM UTC coverage: 98.687% (+0.01%) from 98.676%
21801947980

Pull #134

github

web-flow
Merge f96d33c4a into a5d20b7fa
Pull Request #134: Untitled refactor PR

250 of 250 branches covered (100.0%)

Branch coverage included in aggregate %.

1253 of 1273 relevant lines covered (98.43%)

0.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.8
startle/error.py
1
from typing import Any
1✔
2

3

4
class ParserOptionError(Exception):
1✔
5
    """
6
    Exception raised when there is an error providing an option to the parser.
7
    """
8

9
    pass
1✔
10

11

12
class ParserValueError(ValueError):
1✔
13
    """
14
    Exception raised when there is an error parsing a value.
15
    """
16

17
    pass
1✔
18

19

20
class ParserConfigError(Exception):
1✔
21
    """
22
    Exception raised when there is an error in the parser configuration
23
    (during construction of the parser, prior to parsing).
24
    """
25

26
    pass
1✔
27

28

29
# Below are the specific errors derived from one of the above base errors
30

31

32
class ValueParsingError(ParserValueError):
1✔
33
    """
34
    Exception raised when a value cannot be parsed to the expected type.
35
    """
36

37
    def __init__(self, value: str, type_: str) -> None:
1✔
38
        super().__init__(f"Cannot parse {type_} from `{value}`!")
1✔
39

40

41
class UnsupportedValueTypeError(ParserValueError):
1✔
42
    """
43
    Exception raised when a value type is unsupported for parsing.
44
    """
45

46
    def __init__(self, type_: Any) -> None:
1✔
47
        super().__init__(f"Unsupported type `{type_}`!")
×
48

49

50
class MissingOptionNameError(ParserOptionError):
1✔
51
    """
52
    Exception raised when `-` does not have a name following it.
53
    """
54

55
    def __init__(self) -> None:
1✔
56
        super().__init__("Prefix `-` is not followed by an option!")
1✔
57

58

59
class MissingOptionValueError(ParserOptionError):
1✔
60
    """
61
    Exception raised when an option is missing an argument value
62
    (e.g. `--option` is given but no value follows).
63
    """
64

65
    def __init__(self, name: str) -> None:
1✔
66
        super().__init__(f"Option `{name}` is missing argument!")
1✔
67

68

69
class MissingRequiredOptionError(ParserOptionError):
1✔
70
    """
71
    Exception raised when a required option is missing.
72
    """
73

74
    def __init__(self, name: str) -> None:
1✔
75
        super().__init__(f"Required option `{name}` is not provided!")
1✔
76

77

78
class MissingRequiredPositionalArgumentError(ParserOptionError):
1✔
79
    """
80
    Exception raised when a required positional argument is missing.
81
    """
82

83
    def __init__(self, long_name: str) -> None:
1✔
84
        super().__init__(f"Required positional argument <{long_name}> is not provided!")
1✔
85

86

87
class UnexpectedOptionError(ParserOptionError):
1✔
88
    """
89
    Exception raised when an unexpected option is provided to the parser.
90
    """
91

92
    def __init__(self, name: str) -> None:
1✔
93
        super().__init__(f"Unexpected option `{name}`!")
1✔
94

95

96
class UnexpectedPositionalArgumentError(ParserOptionError):
1✔
97
    """
98
    Exception raised when an unexpected positional argument is provided to the parser.
99
    """
100

101
    def __init__(self, value: str) -> None:
1✔
102
        super().__init__(f"Unexpected positional argument: `{value}`!")
1✔
103

104

105
class DuplicateOptionError(ParserOptionError):
1✔
106
    """
107
    Exception raised when a duplicate option is provided to the parser when it is not n-ary.
108
    """
109

110
    def __init__(self, name: str) -> None:
1✔
111
        super().__init__(f"Option `{name}` is multiply given!")
1✔
112

113

114
class DuplicatePositionalArgumentError(ParserOptionError):
1✔
115
    """
116
    Exception raised when a duplicate positional argument is provided to the parser when it is not n-ary.
117
    This is practically impossible to happen via command-line input, but kept for
118
    completeness and programming errors.
119
    """
120

121
    def __init__(self, name: str) -> None:
1✔
122
        super().__init__(f"Positional argument `{name}` is multiply given!")
×
123

124

125
class FlagWithValueError(ParserOptionError):
1✔
126
    """
127
    Exception raised when a flag option is provided with a value via --option=value syntax.
128
    """
129

130
    def __init__(self, name: str) -> None:
1✔
131
        super().__init__(f"Option `{name}` is a flag and cannot be assigned a value!")
1✔
132

133

134
class NonFlagInShortNameCombinationError(ParserOptionError):
1✔
135
    """
136
    Exception raised when a non-flag option is used in a short name combination (e.g. -abc),
137
    not as the last one.
138
    """
139

140
    def __init__(self, name: str) -> None:
1✔
141
        super().__init__(f"Option `{name}` is not a flag and cannot be combined!")
1✔
142

143

144
class MissingCommandError(ParserOptionError):
1✔
145
    """
146
    Exception raised when no command is given and there is no default command.
147
    """
148

149
    def __init__(self) -> None:
1✔
150
        super().__init__("No command given!")
1✔
151

152

153
class UnexpectedCommandError(ParserOptionError):
1✔
154
    """
155
    Exception raised when an unknown command is given and there is no default command.
156
    """
157

158
    def __init__(self, cmd: str) -> None:
1✔
159
        super().__init__(f"Unknown command `{cmd}`!")
1✔
160

161

162
class NameCollisionError(ParserConfigError):
1✔
163
    """
164
    Exception raised when there is a name collision in the parser configuration during
165
    recursive parsing with `flat` naming.
166
    """
167

168
    def __init__(self, name: str, obj_name: str) -> None:
1✔
169
        super().__init__(
1✔
170
            f"Option name `{name}` is used multiple times in `{obj_name}`!"
171
            " Recursive parsing with `flat` naming requires unique option names among all levels."
172
        )
173

174

175
class HelpCollisionError(ParserConfigError):
1✔
176
    """
177
    Exception raised when `help` is used as a parameter name.
178
    """
179

180
    def __init__(self, obj_name: str) -> None:
1✔
181
        super().__init__(f"Cannot use `help` as parameter name in `{obj_name}`!")
1✔
182

183

184
class VariadicChildParamError(ParserConfigError):
1✔
185
    """
186
    Exception raised when a variadic parameter is found in child Args during recursive parsing.
187
    """
188

189
    def __init__(self, param_name: str, obj_name: str) -> None:
1✔
190
        super().__init__(
1✔
191
            f"Cannot have variadic parameter `{param_name}` in child Args of `{obj_name}`!"
192
        )
193

194

195
class VariadicNonRecursableParamError(ParserConfigError):
1✔
196
    def __init__(self, param_name: str, obj_name: str) -> None:
1✔
197
        super().__init__(
1✔
198
            f"Cannot recurse into variadic parameter `{param_name}` in `{obj_name}`!"
199
        )
200

201

202
class NaryNonRecursableParamError(ParserConfigError):
1✔
203
    def __init__(self, param_name: str, obj_name: str) -> None:
1✔
204
        super().__init__(
1✔
205
            f"Cannot recurse into n-ary parameter `{param_name}` in `{obj_name}`!"
206
        )
207

208

209
class NonClassNonRecursableParamError(ParserConfigError):
1✔
210
    def __init__(self, param_name: str, annotation: Any, obj_name: str) -> None:
1✔
211
        super().__init__(
1✔
212
            f"Cannot recurse into parameter `{param_name}` of non-class type "
213
            f"`{annotation}` in `{obj_name}`!"
214
        )
215

216

217
class UnsupportedTypeError(ParserConfigError):
1✔
218
    """
219
    Exception raised when an unsupported type is encountered during parser construction.
220
    """
221

222
    def __init__(self, param_name: str, annotation: Any, obj_name: str) -> None:
1✔
223
        super().__init__(
1✔
224
            f"Unsupported type `{annotation}` for parameter `{param_name}` in `{obj_name}`!"
225
        )
226

227

228
class MissingNameError(ParserConfigError):
1✔
229
    """
230
    Exception raised when both long and short names are missing when initializing `Name`.
231
    """
232

233
    def __init__(self) -> None:
1✔
234
        super().__init__("Named arguments should have at least one name!")
1✔
235

236

237
class MissingContainerTypeError(ParserConfigError):
1✔
238
    """
239
    Exception raised when a n-ary parameter is missing a container type.
240
    """
241

242
    def __init__(self) -> None:
1✔
243
        super().__init__("Container type must be specified for n-ary options!")
1✔
244

245

246
class ArgumentKindError(ParserConfigError):
1✔
247
    """
248
    Exception raised when an argument is neither positional nor named.
249
    """
250

251
    def __init__(self) -> None:
1✔
252
        super().__init__("An argument should be either positional or named (or both)!")
1✔
253

254

255
class UnsupportedContainerTypeError(ParserConfigError):
1✔
256
    """
257
    Exception raised when an unsupported container type is used for n-ary options.
258
    """
259

260
    def __init__(self) -> None:
1✔
261
        super().__init__("Unsupported container type!")
1✔
262

263

264
class UnexpectedDefaultCommandError(ParserConfigError):
1✔
265
    """
266
    Exception raised when the default command is not among the subcommands.
267
    """
268

269
    def __init__(self, default: str, available_cmds: list[str]) -> None:
1✔
270
        super().__init__(
1✔
271
            f"Default command `{default}` is not among the subcommands!"
272
            f" Available subcommands: {', '.join(available_cmds)}"
273
        )
274

275

276
class CmdsRecurseError(ParserConfigError):
1✔
277
    """
278
    Exception raised when recurse==True for Cmds, which is not yet supported.
279
    """
280

281
    def __init__(self) -> None:
1✔
282
        super().__init__("Recurse option is not yet supported for multiple functions.")
1✔
283

284

285
class SingleFunctionDefaultCommandError(ParserConfigError):
1✔
286
    """
287
    Exception raised when a default command is given for a single function.
288
    """
289

290
    def __init__(self) -> None:
1✔
291
        super().__init__("Default subcommand is not supported for a single function!")
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc