]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | """ |
2 | This module started out as largely a copy paste from the stdlib's | |
3 | optparse module with the features removed that we do not need from | |
4 | optparse because we implement them in Click on a higher level (for | |
5 | instance type handling, help formatting and a lot more). | |
6 | ||
7 | The plan is to remove more and more from here over time. | |
8 | ||
9 | The reason this is a different module and not optparse from the stdlib | |
10 | is that there are differences in 2.x and 3.x about the error messages | |
11 | generated and optparse in the stdlib uses gettext for no good reason | |
12 | and might cause us issues. | |
13 | ||
14 | Click uses parts of optparse written by Gregory P. Ward and maintained | |
15 | by the Python Software Foundation. This is limited to code in parser.py. | |
16 | ||
17 | Copyright 2001-2006 Gregory P. Ward. All rights reserved. | |
18 | Copyright 2002-2006 Python Software Foundation. All rights reserved. | |
19 | """ | |
20 | # This code uses parts of optparse written by Gregory P. Ward and | |
21 | # maintained by the Python Software Foundation. | |
22 | # Copyright 2001-2006 Gregory P. Ward | |
23 | # Copyright 2002-2006 Python Software Foundation | |
24 | import typing as t | |
25 | from collections import deque | |
26 | from gettext import gettext as _ | |
27 | from gettext import ngettext | |
28 | ||
29 | from .exceptions import BadArgumentUsage | |
30 | from .exceptions import BadOptionUsage | |
31 | from .exceptions import NoSuchOption | |
32 | from .exceptions import UsageError | |
33 | ||
34 | if t.TYPE_CHECKING: | |
35 | import typing_extensions as te | |
36 | from .core import Argument as CoreArgument | |
37 | from .core import Context | |
38 | from .core import Option as CoreOption | |
39 | from .core import Parameter as CoreParameter | |
40 | ||
41 | V = t.TypeVar("V") | |
42 | ||
43 | # Sentinel value that indicates an option was passed as a flag without a | |
44 | # value but is not a flag option. Option.consume_value uses this to | |
45 | # prompt or use the flag_value. | |
46 | _flag_needs_value = object() | |
47 | ||
48 | ||
49 | def _unpack_args( | |
50 | args: t.Sequence[str], nargs_spec: t.Sequence[int] | |
51 | ) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]: | |
52 | """Given an iterable of arguments and an iterable of nargs specifications, | |
53 | it returns a tuple with all the unpacked arguments at the first index | |
54 | and all remaining arguments as the second. | |
55 | ||
56 | The nargs specification is the number of arguments that should be consumed | |
57 | or `-1` to indicate that this position should eat up all the remainders. | |
58 | ||
59 | Missing items are filled with `None`. | |
60 | """ | |
61 | args = deque(args) | |
62 | nargs_spec = deque(nargs_spec) | |
63 | rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] | |
64 | spos: t.Optional[int] = None | |
65 | ||
66 | def _fetch(c: "te.Deque[V]") -> t.Optional[V]: | |
67 | try: | |
68 | if spos is None: | |
69 | return c.popleft() | |
70 | else: | |
71 | return c.pop() | |
72 | except IndexError: | |
73 | return None | |
74 | ||
75 | while nargs_spec: | |
76 | nargs = _fetch(nargs_spec) | |
77 | ||
78 | if nargs is None: | |
79 | continue | |
80 | ||
81 | if nargs == 1: | |
82 | rv.append(_fetch(args)) | |
83 | elif nargs > 1: | |
84 | x = [_fetch(args) for _ in range(nargs)] | |
85 | ||
86 | # If we're reversed, we're pulling in the arguments in reverse, | |
87 | # so we need to turn them around. | |
88 | if spos is not None: | |
89 | x.reverse() | |
90 | ||
91 | rv.append(tuple(x)) | |
92 | elif nargs < 0: | |
93 | if spos is not None: | |
94 | raise TypeError("Cannot have two nargs < 0") | |
95 | ||
96 | spos = len(rv) | |
97 | rv.append(None) | |
98 | ||
99 | # spos is the position of the wildcard (star). If it's not `None`, | |
100 | # we fill it with the remainder. | |
101 | if spos is not None: | |
102 | rv[spos] = tuple(args) | |
103 | args = [] | |
104 | rv[spos + 1 :] = reversed(rv[spos + 1 :]) | |
105 | ||
106 | return tuple(rv), list(args) | |
107 | ||
108 | ||
109 | def split_opt(opt: str) -> t.Tuple[str, str]: | |
110 | first = opt[:1] | |
111 | if first.isalnum(): | |
112 | return "", opt | |
113 | if opt[1:2] == first: | |
114 | return opt[:2], opt[2:] | |
115 | return first, opt[1:] | |
116 | ||
117 | ||
118 | def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str: | |
119 | if ctx is None or ctx.token_normalize_func is None: | |
120 | return opt | |
121 | prefix, opt = split_opt(opt) | |
122 | return f"{prefix}{ctx.token_normalize_func(opt)}" | |
123 | ||
124 | ||
125 | def split_arg_string(string: str) -> t.List[str]: | |
126 | """Split an argument string as with :func:`shlex.split`, but don't | |
127 | fail if the string is incomplete. Ignores a missing closing quote or | |
128 | incomplete escape sequence and uses the partial token as-is. | |
129 | ||
130 | .. code-block:: python | |
131 | ||
132 | split_arg_string("example 'my file") | |
133 | ["example", "my file"] | |
134 | ||
135 | split_arg_string("example my\\") | |
136 | ["example", "my"] | |
137 | ||
138 | :param string: String to split. | |
139 | """ | |
140 | import shlex | |
141 | ||
142 | lex = shlex.shlex(string, posix=True) | |
143 | lex.whitespace_split = True | |
144 | lex.commenters = "" | |
145 | out = [] | |
146 | ||
147 | try: | |
148 | for token in lex: | |
149 | out.append(token) | |
150 | except ValueError: | |
151 | # Raised when end-of-string is reached in an invalid state. Use | |
152 | # the partial token as-is. The quote or escape character is in | |
153 | # lex.state, not lex.token. | |
154 | out.append(lex.token) | |
155 | ||
156 | return out | |
157 | ||
158 | ||
159 | class Option: | |
160 | def __init__( | |
161 | self, | |
162 | obj: "CoreOption", | |
163 | opts: t.Sequence[str], | |
164 | dest: t.Optional[str], | |
165 | action: t.Optional[str] = None, | |
166 | nargs: int = 1, | |
167 | const: t.Optional[t.Any] = None, | |
168 | ): | |
169 | self._short_opts = [] | |
170 | self._long_opts = [] | |
171 | self.prefixes: t.Set[str] = set() | |
172 | ||
173 | for opt in opts: | |
174 | prefix, value = split_opt(opt) | |
175 | if not prefix: | |
176 | raise ValueError(f"Invalid start character for option ({opt})") | |
177 | self.prefixes.add(prefix[0]) | |
178 | if len(prefix) == 1 and len(value) == 1: | |
179 | self._short_opts.append(opt) | |
180 | else: | |
181 | self._long_opts.append(opt) | |
182 | self.prefixes.add(prefix) | |
183 | ||
184 | if action is None: | |
185 | action = "store" | |
186 | ||
187 | self.dest = dest | |
188 | self.action = action | |
189 | self.nargs = nargs | |
190 | self.const = const | |
191 | self.obj = obj | |
192 | ||
193 | @property | |
194 | def takes_value(self) -> bool: | |
195 | return self.action in ("store", "append") | |
196 | ||
197 | def process(self, value: t.Any, state: "ParsingState") -> None: | |
198 | if self.action == "store": | |
199 | state.opts[self.dest] = value # type: ignore | |
200 | elif self.action == "store_const": | |
201 | state.opts[self.dest] = self.const # type: ignore | |
202 | elif self.action == "append": | |
203 | state.opts.setdefault(self.dest, []).append(value) # type: ignore | |
204 | elif self.action == "append_const": | |
205 | state.opts.setdefault(self.dest, []).append(self.const) # type: ignore | |
206 | elif self.action == "count": | |
207 | state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore | |
208 | else: | |
209 | raise ValueError(f"unknown action '{self.action}'") | |
210 | state.order.append(self.obj) | |
211 | ||
212 | ||
213 | class Argument: | |
214 | def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1): | |
215 | self.dest = dest | |
216 | self.nargs = nargs | |
217 | self.obj = obj | |
218 | ||
219 | def process( | |
220 | self, | |
221 | value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], | |
222 | state: "ParsingState", | |
223 | ) -> None: | |
224 | if self.nargs > 1: | |
225 | assert value is not None | |
226 | holes = sum(1 for x in value if x is None) | |
227 | if holes == len(value): | |
228 | value = None | |
229 | elif holes != 0: | |
230 | raise BadArgumentUsage( | |
231 | _("Argument {name!r} takes {nargs} values.").format( | |
232 | name=self.dest, nargs=self.nargs | |
233 | ) | |
234 | ) | |
235 | ||
236 | if self.nargs == -1 and self.obj.envvar is not None and value == (): | |
237 | # Replace empty tuple with None so that a value from the | |
238 | # environment may be tried. | |
239 | value = None | |
240 | ||
241 | state.opts[self.dest] = value # type: ignore | |
242 | state.order.append(self.obj) | |
243 | ||
244 | ||
245 | class ParsingState: | |
246 | def __init__(self, rargs: t.List[str]) -> None: | |
247 | self.opts: t.Dict[str, t.Any] = {} | |
248 | self.largs: t.List[str] = [] | |
249 | self.rargs = rargs | |
250 | self.order: t.List["CoreParameter"] = [] | |
251 | ||
252 | ||
253 | class OptionParser: | |
254 | """The option parser is an internal class that is ultimately used to | |
255 | parse options and arguments. It's modelled after optparse and brings | |
256 | a similar but vastly simplified API. It should generally not be used | |
257 | directly as the high level Click classes wrap it for you. | |
258 | ||
259 | It's not nearly as extensible as optparse or argparse as it does not | |
260 | implement features that are implemented on a higher level (such as | |
261 | types or defaults). | |
262 | ||
263 | :param ctx: optionally the :class:`~click.Context` where this parser | |
264 | should go with. | |
265 | """ | |
266 | ||
267 | def __init__(self, ctx: t.Optional["Context"] = None) -> None: | |
268 | #: The :class:`~click.Context` for this parser. This might be | |
269 | #: `None` for some advanced use cases. | |
270 | self.ctx = ctx | |
271 | #: This controls how the parser deals with interspersed arguments. | |
272 | #: If this is set to `False`, the parser will stop on the first | |
273 | #: non-option. Click uses this to implement nested subcommands | |
274 | #: safely. | |
275 | self.allow_interspersed_args: bool = True | |
276 | #: This tells the parser how to deal with unknown options. By | |
277 | #: default it will error out (which is sensible), but there is a | |
278 | #: second mode where it will ignore it and continue processing | |
279 | #: after shifting all the unknown options into the resulting args. | |
280 | self.ignore_unknown_options: bool = False | |
281 | ||
282 | if ctx is not None: | |
283 | self.allow_interspersed_args = ctx.allow_interspersed_args | |
284 | self.ignore_unknown_options = ctx.ignore_unknown_options | |
285 | ||
286 | self._short_opt: t.Dict[str, Option] = {} | |
287 | self._long_opt: t.Dict[str, Option] = {} | |
288 | self._opt_prefixes = {"-", "--"} | |
289 | self._args: t.List[Argument] = [] | |
290 | ||
291 | def add_option( | |
292 | self, | |
293 | obj: "CoreOption", | |
294 | opts: t.Sequence[str], | |
295 | dest: t.Optional[str], | |
296 | action: t.Optional[str] = None, | |
297 | nargs: int = 1, | |
298 | const: t.Optional[t.Any] = None, | |
299 | ) -> None: | |
300 | """Adds a new option named `dest` to the parser. The destination | |
301 | is not inferred (unlike with optparse) and needs to be explicitly | |
302 | provided. Action can be any of ``store``, ``store_const``, | |
303 | ``append``, ``append_const`` or ``count``. | |
304 | ||
305 | The `obj` can be used to identify the option in the order list | |
306 | that is returned from the parser. | |
307 | """ | |
308 | opts = [normalize_opt(opt, self.ctx) for opt in opts] | |
309 | option = Option(obj, opts, dest, action=action, nargs=nargs, const=const) | |
310 | self._opt_prefixes.update(option.prefixes) | |
311 | for opt in option._short_opts: | |
312 | self._short_opt[opt] = option | |
313 | for opt in option._long_opts: | |
314 | self._long_opt[opt] = option | |
315 | ||
316 | def add_argument( | |
317 | self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1 | |
318 | ) -> None: | |
319 | """Adds a positional argument named `dest` to the parser. | |
320 | ||
321 | The `obj` can be used to identify the option in the order list | |
322 | that is returned from the parser. | |
323 | """ | |
324 | self._args.append(Argument(obj, dest=dest, nargs=nargs)) | |
325 | ||
326 | def parse_args( | |
327 | self, args: t.List[str] | |
328 | ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]: | |
329 | """Parses positional arguments and returns ``(values, args, order)`` | |
330 | for the parsed options and arguments as well as the leftover | |
331 | arguments if there are any. The order is a list of objects as they | |
332 | appear on the command line. If arguments appear multiple times they | |
333 | will be memorized multiple times as well. | |
334 | """ | |
335 | state = ParsingState(args) | |
336 | try: | |
337 | self._process_args_for_options(state) | |
338 | self._process_args_for_args(state) | |
339 | except UsageError: | |
340 | if self.ctx is None or not self.ctx.resilient_parsing: | |
341 | raise | |
342 | return state.opts, state.largs, state.order | |
343 | ||
344 | def _process_args_for_args(self, state: ParsingState) -> None: | |
345 | pargs, args = _unpack_args( | |
346 | state.largs + state.rargs, [x.nargs for x in self._args] | |
347 | ) | |
348 | ||
349 | for idx, arg in enumerate(self._args): | |
350 | arg.process(pargs[idx], state) | |
351 | ||
352 | state.largs = args | |
353 | state.rargs = [] | |
354 | ||
355 | def _process_args_for_options(self, state: ParsingState) -> None: | |
356 | while state.rargs: | |
357 | arg = state.rargs.pop(0) | |
358 | arglen = len(arg) | |
359 | # Double dashes always handled explicitly regardless of what | |
360 | # prefixes are valid. | |
361 | if arg == "--": | |
362 | return | |
363 | elif arg[:1] in self._opt_prefixes and arglen > 1: | |
364 | self._process_opts(arg, state) | |
365 | elif self.allow_interspersed_args: | |
366 | state.largs.append(arg) | |
367 | else: | |
368 | state.rargs.insert(0, arg) | |
369 | return | |
370 | ||
371 | # Say this is the original argument list: | |
372 | # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] | |
373 | # ^ | |
374 | # (we are about to process arg(i)). | |
375 | # | |
376 | # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of | |
377 | # [arg0, ..., arg(i-1)] (any options and their arguments will have | |
378 | # been removed from largs). | |
379 | # | |
380 | # The while loop will usually consume 1 or more arguments per pass. | |
381 | # If it consumes 1 (eg. arg is an option that takes no arguments), | |
382 | # then after _process_arg() is done the situation is: | |
383 | # | |
384 | # largs = subset of [arg0, ..., arg(i)] | |
385 | # rargs = [arg(i+1), ..., arg(N-1)] | |
386 | # | |
387 | # If allow_interspersed_args is false, largs will always be | |
388 | # *empty* -- still a subset of [arg0, ..., arg(i-1)], but | |
389 | # not a very interesting subset! | |
390 | ||
391 | def _match_long_opt( | |
392 | self, opt: str, explicit_value: t.Optional[str], state: ParsingState | |
393 | ) -> None: | |
394 | if opt not in self._long_opt: | |
395 | from difflib import get_close_matches | |
396 | ||
397 | possibilities = get_close_matches(opt, self._long_opt) | |
398 | raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) | |
399 | ||
400 | option = self._long_opt[opt] | |
401 | if option.takes_value: | |
402 | # At this point it's safe to modify rargs by injecting the | |
403 | # explicit value, because no exception is raised in this | |
404 | # branch. This means that the inserted value will be fully | |
405 | # consumed. | |
406 | if explicit_value is not None: | |
407 | state.rargs.insert(0, explicit_value) | |
408 | ||
409 | value = self._get_value_from_state(opt, option, state) | |
410 | ||
411 | elif explicit_value is not None: | |
412 | raise BadOptionUsage( | |
413 | opt, _("Option {name!r} does not take a value.").format(name=opt) | |
414 | ) | |
415 | ||
416 | else: | |
417 | value = None | |
418 | ||
419 | option.process(value, state) | |
420 | ||
421 | def _match_short_opt(self, arg: str, state: ParsingState) -> None: | |
422 | stop = False | |
423 | i = 1 | |
424 | prefix = arg[0] | |
425 | unknown_options = [] | |
426 | ||
427 | for ch in arg[1:]: | |
428 | opt = normalize_opt(f"{prefix}{ch}", self.ctx) | |
429 | option = self._short_opt.get(opt) | |
430 | i += 1 | |
431 | ||
432 | if not option: | |
433 | if self.ignore_unknown_options: | |
434 | unknown_options.append(ch) | |
435 | continue | |
436 | raise NoSuchOption(opt, ctx=self.ctx) | |
437 | if option.takes_value: | |
438 | # Any characters left in arg? Pretend they're the | |
439 | # next arg, and stop consuming characters of arg. | |
440 | if i < len(arg): | |
441 | state.rargs.insert(0, arg[i:]) | |
442 | stop = True | |
443 | ||
444 | value = self._get_value_from_state(opt, option, state) | |
445 | ||
446 | else: | |
447 | value = None | |
448 | ||
449 | option.process(value, state) | |
450 | ||
451 | if stop: | |
452 | break | |
453 | ||
454 | # If we got any unknown options we recombine the string of the | |
455 | # remaining options and re-attach the prefix, then report that | |
456 | # to the state as new larg. This way there is basic combinatorics | |
457 | # that can be achieved while still ignoring unknown arguments. | |
458 | if self.ignore_unknown_options and unknown_options: | |
459 | state.largs.append(f"{prefix}{''.join(unknown_options)}") | |
460 | ||
461 | def _get_value_from_state( | |
462 | self, option_name: str, option: Option, state: ParsingState | |
463 | ) -> t.Any: | |
464 | nargs = option.nargs | |
465 | ||
466 | if len(state.rargs) < nargs: | |
467 | if option.obj._flag_needs_value: | |
468 | # Option allows omitting the value. | |
469 | value = _flag_needs_value | |
470 | else: | |
471 | raise BadOptionUsage( | |
472 | option_name, | |
473 | ngettext( | |
474 | "Option {name!r} requires an argument.", | |
475 | "Option {name!r} requires {nargs} arguments.", | |
476 | nargs, | |
477 | ).format(name=option_name, nargs=nargs), | |
478 | ) | |
479 | elif nargs == 1: | |
480 | next_rarg = state.rargs[0] | |
481 | ||
482 | if ( | |
483 | option.obj._flag_needs_value | |
484 | and isinstance(next_rarg, str) | |
485 | and next_rarg[:1] in self._opt_prefixes | |
486 | and len(next_rarg) > 1 | |
487 | ): | |
488 | # The next arg looks like the start of an option, don't | |
489 | # use it as the value if omitting the value is allowed. | |
490 | value = _flag_needs_value | |
491 | else: | |
492 | value = state.rargs.pop(0) | |
493 | else: | |
494 | value = tuple(state.rargs[:nargs]) | |
495 | del state.rargs[:nargs] | |
496 | ||
497 | return value | |
498 | ||
499 | def _process_opts(self, arg: str, state: ParsingState) -> None: | |
500 | explicit_value = None | |
501 | # Long option handling happens in two parts. The first part is | |
502 | # supporting explicitly attached values. In any case, we will try | |
503 | # to long match the option first. | |
504 | if "=" in arg: | |
505 | long_opt, explicit_value = arg.split("=", 1) | |
506 | else: | |
507 | long_opt = arg | |
508 | norm_long_opt = normalize_opt(long_opt, self.ctx) | |
509 | ||
510 | # At this point we will match the (assumed) long option through | |
511 | # the long option matching code. Note that this allows options | |
512 | # like "-foo" to be matched as long options. | |
513 | try: | |
514 | self._match_long_opt(norm_long_opt, explicit_value, state) | |
515 | except NoSuchOption: | |
516 | # At this point the long option matching failed, and we need | |
517 | # to try with short options. However there is a special rule | |
518 | # which says, that if we have a two character options prefix | |
519 | # (applies to "--foo" for instance), we do not dispatch to the | |
520 | # short option code and will instead raise the no option | |
521 | # error. | |
522 | if arg[:2] not in self._opt_prefixes: | |
523 | self._match_short_opt(arg, state) | |
524 | return | |
525 | ||
526 | if not self.ignore_unknown_options: | |
527 | raise | |
528 | ||
529 | state.largs.append(arg) |