Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/click/parser.py @ 0:d30785e31577 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:18:57 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:d30785e31577 |
|---|---|
| 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) |
