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) |