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