Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/click/parser.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
comparison
equal
deleted
inserted
replaced
4:79f47841a781 | 5:9b1c78e6ba9c |
---|---|
1 # -*- coding: utf-8 -*- | |
2 """ | |
3 This module started out as largely a copy paste from the stdlib's | |
4 optparse module with the features removed that we do not need from | |
5 optparse because we implement them in Click on a higher level (for | |
6 instance type handling, help formatting and a lot more). | |
7 | |
8 The plan is to remove more and more from here over time. | |
9 | |
10 The reason this is a different module and not optparse from the stdlib | |
11 is that there are differences in 2.x and 3.x about the error messages | |
12 generated and optparse in the stdlib uses gettext for no good reason | |
13 and might cause us issues. | |
14 | |
15 Click uses parts of optparse written by Gregory P. Ward and maintained | |
16 by the Python Software Foundation. This is limited to code in parser.py. | |
17 | |
18 Copyright 2001-2006 Gregory P. Ward. All rights reserved. | |
19 Copyright 2002-2006 Python Software Foundation. All rights reserved. | |
20 """ | |
21 import re | |
22 from collections import deque | |
23 | |
24 from .exceptions import BadArgumentUsage | |
25 from .exceptions import BadOptionUsage | |
26 from .exceptions import NoSuchOption | |
27 from .exceptions import UsageError | |
28 | |
29 | |
30 def _unpack_args(args, nargs_spec): | |
31 """Given an iterable of arguments and an iterable of nargs specifications, | |
32 it returns a tuple with all the unpacked arguments at the first index | |
33 and all remaining arguments as the second. | |
34 | |
35 The nargs specification is the number of arguments that should be consumed | |
36 or `-1` to indicate that this position should eat up all the remainders. | |
37 | |
38 Missing items are filled with `None`. | |
39 """ | |
40 args = deque(args) | |
41 nargs_spec = deque(nargs_spec) | |
42 rv = [] | |
43 spos = None | |
44 | |
45 def _fetch(c): | |
46 try: | |
47 if spos is None: | |
48 return c.popleft() | |
49 else: | |
50 return c.pop() | |
51 except IndexError: | |
52 return None | |
53 | |
54 while nargs_spec: | |
55 nargs = _fetch(nargs_spec) | |
56 if nargs == 1: | |
57 rv.append(_fetch(args)) | |
58 elif nargs > 1: | |
59 x = [_fetch(args) for _ in range(nargs)] | |
60 # If we're reversed, we're pulling in the arguments in reverse, | |
61 # so we need to turn them around. | |
62 if spos is not None: | |
63 x.reverse() | |
64 rv.append(tuple(x)) | |
65 elif nargs < 0: | |
66 if spos is not None: | |
67 raise TypeError("Cannot have two nargs < 0") | |
68 spos = len(rv) | |
69 rv.append(None) | |
70 | |
71 # spos is the position of the wildcard (star). If it's not `None`, | |
72 # we fill it with the remainder. | |
73 if spos is not None: | |
74 rv[spos] = tuple(args) | |
75 args = [] | |
76 rv[spos + 1 :] = reversed(rv[spos + 1 :]) | |
77 | |
78 return tuple(rv), list(args) | |
79 | |
80 | |
81 def _error_opt_args(nargs, opt): | |
82 if nargs == 1: | |
83 raise BadOptionUsage(opt, "{} option requires an argument".format(opt)) | |
84 raise BadOptionUsage(opt, "{} option requires {} arguments".format(opt, nargs)) | |
85 | |
86 | |
87 def split_opt(opt): | |
88 first = opt[:1] | |
89 if first.isalnum(): | |
90 return "", opt | |
91 if opt[1:2] == first: | |
92 return opt[:2], opt[2:] | |
93 return first, opt[1:] | |
94 | |
95 | |
96 def normalize_opt(opt, ctx): | |
97 if ctx is None or ctx.token_normalize_func is None: | |
98 return opt | |
99 prefix, opt = split_opt(opt) | |
100 return prefix + ctx.token_normalize_func(opt) | |
101 | |
102 | |
103 def split_arg_string(string): | |
104 """Given an argument string this attempts to split it into small parts.""" | |
105 rv = [] | |
106 for match in re.finditer( | |
107 r"('([^'\\]*(?:\\.[^'\\]*)*)'|\"([^\"\\]*(?:\\.[^\"\\]*)*)\"|\S+)\s*", | |
108 string, | |
109 re.S, | |
110 ): | |
111 arg = match.group().strip() | |
112 if arg[:1] == arg[-1:] and arg[:1] in "\"'": | |
113 arg = arg[1:-1].encode("ascii", "backslashreplace").decode("unicode-escape") | |
114 try: | |
115 arg = type(string)(arg) | |
116 except UnicodeError: | |
117 pass | |
118 rv.append(arg) | |
119 return rv | |
120 | |
121 | |
122 class Option(object): | |
123 def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None): | |
124 self._short_opts = [] | |
125 self._long_opts = [] | |
126 self.prefixes = set() | |
127 | |
128 for opt in opts: | |
129 prefix, value = split_opt(opt) | |
130 if not prefix: | |
131 raise ValueError("Invalid start character for option ({})".format(opt)) | |
132 self.prefixes.add(prefix[0]) | |
133 if len(prefix) == 1 and len(value) == 1: | |
134 self._short_opts.append(opt) | |
135 else: | |
136 self._long_opts.append(opt) | |
137 self.prefixes.add(prefix) | |
138 | |
139 if action is None: | |
140 action = "store" | |
141 | |
142 self.dest = dest | |
143 self.action = action | |
144 self.nargs = nargs | |
145 self.const = const | |
146 self.obj = obj | |
147 | |
148 @property | |
149 def takes_value(self): | |
150 return self.action in ("store", "append") | |
151 | |
152 def process(self, value, state): | |
153 if self.action == "store": | |
154 state.opts[self.dest] = value | |
155 elif self.action == "store_const": | |
156 state.opts[self.dest] = self.const | |
157 elif self.action == "append": | |
158 state.opts.setdefault(self.dest, []).append(value) | |
159 elif self.action == "append_const": | |
160 state.opts.setdefault(self.dest, []).append(self.const) | |
161 elif self.action == "count": | |
162 state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 | |
163 else: | |
164 raise ValueError("unknown action '{}'".format(self.action)) | |
165 state.order.append(self.obj) | |
166 | |
167 | |
168 class Argument(object): | |
169 def __init__(self, dest, nargs=1, obj=None): | |
170 self.dest = dest | |
171 self.nargs = nargs | |
172 self.obj = obj | |
173 | |
174 def process(self, value, state): | |
175 if self.nargs > 1: | |
176 holes = sum(1 for x in value if x is None) | |
177 if holes == len(value): | |
178 value = None | |
179 elif holes != 0: | |
180 raise BadArgumentUsage( | |
181 "argument {} takes {} values".format(self.dest, self.nargs) | |
182 ) | |
183 state.opts[self.dest] = value | |
184 state.order.append(self.obj) | |
185 | |
186 | |
187 class ParsingState(object): | |
188 def __init__(self, rargs): | |
189 self.opts = {} | |
190 self.largs = [] | |
191 self.rargs = rargs | |
192 self.order = [] | |
193 | |
194 | |
195 class OptionParser(object): | |
196 """The option parser is an internal class that is ultimately used to | |
197 parse options and arguments. It's modelled after optparse and brings | |
198 a similar but vastly simplified API. It should generally not be used | |
199 directly as the high level Click classes wrap it for you. | |
200 | |
201 It's not nearly as extensible as optparse or argparse as it does not | |
202 implement features that are implemented on a higher level (such as | |
203 types or defaults). | |
204 | |
205 :param ctx: optionally the :class:`~click.Context` where this parser | |
206 should go with. | |
207 """ | |
208 | |
209 def __init__(self, ctx=None): | |
210 #: The :class:`~click.Context` for this parser. This might be | |
211 #: `None` for some advanced use cases. | |
212 self.ctx = ctx | |
213 #: This controls how the parser deals with interspersed arguments. | |
214 #: If this is set to `False`, the parser will stop on the first | |
215 #: non-option. Click uses this to implement nested subcommands | |
216 #: safely. | |
217 self.allow_interspersed_args = True | |
218 #: This tells the parser how to deal with unknown options. By | |
219 #: default it will error out (which is sensible), but there is a | |
220 #: second mode where it will ignore it and continue processing | |
221 #: after shifting all the unknown options into the resulting args. | |
222 self.ignore_unknown_options = False | |
223 if ctx is not None: | |
224 self.allow_interspersed_args = ctx.allow_interspersed_args | |
225 self.ignore_unknown_options = ctx.ignore_unknown_options | |
226 self._short_opt = {} | |
227 self._long_opt = {} | |
228 self._opt_prefixes = {"-", "--"} | |
229 self._args = [] | |
230 | |
231 def add_option(self, opts, dest, action=None, nargs=1, const=None, obj=None): | |
232 """Adds a new option named `dest` to the parser. The destination | |
233 is not inferred (unlike with optparse) and needs to be explicitly | |
234 provided. Action can be any of ``store``, ``store_const``, | |
235 ``append``, ``appnd_const`` or ``count``. | |
236 | |
237 The `obj` can be used to identify the option in the order list | |
238 that is returned from the parser. | |
239 """ | |
240 if obj is None: | |
241 obj = dest | |
242 opts = [normalize_opt(opt, self.ctx) for opt in opts] | |
243 option = Option(opts, dest, action=action, nargs=nargs, const=const, obj=obj) | |
244 self._opt_prefixes.update(option.prefixes) | |
245 for opt in option._short_opts: | |
246 self._short_opt[opt] = option | |
247 for opt in option._long_opts: | |
248 self._long_opt[opt] = option | |
249 | |
250 def add_argument(self, dest, nargs=1, obj=None): | |
251 """Adds a positional argument named `dest` to the parser. | |
252 | |
253 The `obj` can be used to identify the option in the order list | |
254 that is returned from the parser. | |
255 """ | |
256 if obj is None: | |
257 obj = dest | |
258 self._args.append(Argument(dest=dest, nargs=nargs, obj=obj)) | |
259 | |
260 def parse_args(self, args): | |
261 """Parses positional arguments and returns ``(values, args, order)`` | |
262 for the parsed options and arguments as well as the leftover | |
263 arguments if there are any. The order is a list of objects as they | |
264 appear on the command line. If arguments appear multiple times they | |
265 will be memorized multiple times as well. | |
266 """ | |
267 state = ParsingState(args) | |
268 try: | |
269 self._process_args_for_options(state) | |
270 self._process_args_for_args(state) | |
271 except UsageError: | |
272 if self.ctx is None or not self.ctx.resilient_parsing: | |
273 raise | |
274 return state.opts, state.largs, state.order | |
275 | |
276 def _process_args_for_args(self, state): | |
277 pargs, args = _unpack_args( | |
278 state.largs + state.rargs, [x.nargs for x in self._args] | |
279 ) | |
280 | |
281 for idx, arg in enumerate(self._args): | |
282 arg.process(pargs[idx], state) | |
283 | |
284 state.largs = args | |
285 state.rargs = [] | |
286 | |
287 def _process_args_for_options(self, state): | |
288 while state.rargs: | |
289 arg = state.rargs.pop(0) | |
290 arglen = len(arg) | |
291 # Double dashes always handled explicitly regardless of what | |
292 # prefixes are valid. | |
293 if arg == "--": | |
294 return | |
295 elif arg[:1] in self._opt_prefixes and arglen > 1: | |
296 self._process_opts(arg, state) | |
297 elif self.allow_interspersed_args: | |
298 state.largs.append(arg) | |
299 else: | |
300 state.rargs.insert(0, arg) | |
301 return | |
302 | |
303 # Say this is the original argument list: | |
304 # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] | |
305 # ^ | |
306 # (we are about to process arg(i)). | |
307 # | |
308 # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of | |
309 # [arg0, ..., arg(i-1)] (any options and their arguments will have | |
310 # been removed from largs). | |
311 # | |
312 # The while loop will usually consume 1 or more arguments per pass. | |
313 # If it consumes 1 (eg. arg is an option that takes no arguments), | |
314 # then after _process_arg() is done the situation is: | |
315 # | |
316 # largs = subset of [arg0, ..., arg(i)] | |
317 # rargs = [arg(i+1), ..., arg(N-1)] | |
318 # | |
319 # If allow_interspersed_args is false, largs will always be | |
320 # *empty* -- still a subset of [arg0, ..., arg(i-1)], but | |
321 # not a very interesting subset! | |
322 | |
323 def _match_long_opt(self, opt, explicit_value, state): | |
324 if opt not in self._long_opt: | |
325 possibilities = [word for word in self._long_opt if word.startswith(opt)] | |
326 raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) | |
327 | |
328 option = self._long_opt[opt] | |
329 if option.takes_value: | |
330 # At this point it's safe to modify rargs by injecting the | |
331 # explicit value, because no exception is raised in this | |
332 # branch. This means that the inserted value will be fully | |
333 # consumed. | |
334 if explicit_value is not None: | |
335 state.rargs.insert(0, explicit_value) | |
336 | |
337 nargs = option.nargs | |
338 if len(state.rargs) < nargs: | |
339 _error_opt_args(nargs, opt) | |
340 elif nargs == 1: | |
341 value = state.rargs.pop(0) | |
342 else: | |
343 value = tuple(state.rargs[:nargs]) | |
344 del state.rargs[:nargs] | |
345 | |
346 elif explicit_value is not None: | |
347 raise BadOptionUsage(opt, "{} option does not take a value".format(opt)) | |
348 | |
349 else: | |
350 value = None | |
351 | |
352 option.process(value, state) | |
353 | |
354 def _match_short_opt(self, arg, state): | |
355 stop = False | |
356 i = 1 | |
357 prefix = arg[0] | |
358 unknown_options = [] | |
359 | |
360 for ch in arg[1:]: | |
361 opt = normalize_opt(prefix + ch, self.ctx) | |
362 option = self._short_opt.get(opt) | |
363 i += 1 | |
364 | |
365 if not option: | |
366 if self.ignore_unknown_options: | |
367 unknown_options.append(ch) | |
368 continue | |
369 raise NoSuchOption(opt, ctx=self.ctx) | |
370 if option.takes_value: | |
371 # Any characters left in arg? Pretend they're the | |
372 # next arg, and stop consuming characters of arg. | |
373 if i < len(arg): | |
374 state.rargs.insert(0, arg[i:]) | |
375 stop = True | |
376 | |
377 nargs = option.nargs | |
378 if len(state.rargs) < nargs: | |
379 _error_opt_args(nargs, opt) | |
380 elif nargs == 1: | |
381 value = state.rargs.pop(0) | |
382 else: | |
383 value = tuple(state.rargs[:nargs]) | |
384 del state.rargs[:nargs] | |
385 | |
386 else: | |
387 value = None | |
388 | |
389 option.process(value, state) | |
390 | |
391 if stop: | |
392 break | |
393 | |
394 # If we got any unknown options we re-combinate the string of the | |
395 # remaining options and re-attach the prefix, then report that | |
396 # to the state as new larg. This way there is basic combinatorics | |
397 # that can be achieved while still ignoring unknown arguments. | |
398 if self.ignore_unknown_options and unknown_options: | |
399 state.largs.append("{}{}".format(prefix, "".join(unknown_options))) | |
400 | |
401 def _process_opts(self, arg, state): | |
402 explicit_value = None | |
403 # Long option handling happens in two parts. The first part is | |
404 # supporting explicitly attached values. In any case, we will try | |
405 # to long match the option first. | |
406 if "=" in arg: | |
407 long_opt, explicit_value = arg.split("=", 1) | |
408 else: | |
409 long_opt = arg | |
410 norm_long_opt = normalize_opt(long_opt, self.ctx) | |
411 | |
412 # At this point we will match the (assumed) long option through | |
413 # the long option matching code. Note that this allows options | |
414 # like "-foo" to be matched as long options. | |
415 try: | |
416 self._match_long_opt(norm_long_opt, explicit_value, state) | |
417 except NoSuchOption: | |
418 # At this point the long option matching failed, and we need | |
419 # to try with short options. However there is a special rule | |
420 # which says, that if we have a two character options prefix | |
421 # (applies to "--foo" for instance), we do not dispatch to the | |
422 # short option code and will instead raise the no option | |
423 # error. | |
424 if arg[:2] not in self._opt_prefixes: | |
425 return self._match_short_opt(arg, state) | |
426 if not self.ignore_unknown_options: | |
427 raise | |
428 state.largs.append(arg) |