Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(13)

Delta Between Two Patch Sets: Lib/argparse.py

Issue 14191: argparse: nargs='*' doesn't get out-of-order positional parameters
Left Patch Set: Created 6 years, 11 months ago
Right Patch Set: Created 6 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Doc/library/argparse.rst ('k') | Lib/test/test_argparse.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # Author: Steven J. Bethard <steven.bethard@gmail.com>. 1 # Author: Steven J. Bethard <steven.bethard@gmail.com>.
2 2
3 """Command-line parsing library 3 """Command-line parsing library
4 4
5 This module is an optparse-inspired command-line parsing library that: 5 This module is an optparse-inspired command-line parsing library that:
6 6
7 - handles both optional and positional arguments 7 - handles both optional and positional arguments
8 - produces highly informative usage messages 8 - produces highly informative usage messages
9 - supports parsers that dispatch to sub-parsers 9 - supports parsers that dispatch to sub-parsers
10 10
(...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 elif action.nargs == OPTIONAL: 574 elif action.nargs == OPTIONAL:
575 result = '[%s]' % get_metavar(1) 575 result = '[%s]' % get_metavar(1)
576 elif action.nargs == ZERO_OR_MORE: 576 elif action.nargs == ZERO_OR_MORE:
577 result = '[%s [%s ...]]' % get_metavar(2) 577 result = '[%s [%s ...]]' % get_metavar(2)
578 elif action.nargs == ONE_OR_MORE: 578 elif action.nargs == ONE_OR_MORE:
579 result = '%s [%s ...]' % get_metavar(2) 579 result = '%s [%s ...]' % get_metavar(2)
580 elif action.nargs == REMAINDER: 580 elif action.nargs == REMAINDER:
581 result = '...' 581 result = '...'
582 elif action.nargs == PARSER: 582 elif action.nargs == PARSER:
583 result = '%s ...' % get_metavar(1) 583 result = '%s ...' % get_metavar(1)
584 elif action.nargs == SUPPRESS:
585 result = ''
584 else: 586 else:
585 formats = ['%s' for _ in range(action.nargs)] 587 formats = ['%s' for _ in range(action.nargs)]
586 result = ' '.join(formats) % get_metavar(action.nargs) 588 result = ' '.join(formats) % get_metavar(action.nargs)
587 return result 589 return result
588 590
589 def _expand_help(self, action): 591 def _expand_help(self, action):
590 params = dict(vars(action), prog=self._prog) 592 params = dict(vars(action), prog=self._prog)
591 for name in list(params): 593 for name in list(params):
592 if params[name] is SUPPRESS: 594 if params[name] is SUPPRESS:
593 del params[name] 595 del params[name]
(...skipping 1302 matching lines...) Expand 10 before | Expand all | Expand 10 after
1896 # by consume_positionals() 1898 # by consume_positionals()
1897 positionals = self._get_positional_actions() 1899 positionals = self._get_positional_actions()
1898 1900
1899 # function to convert arg_strings into positional actions 1901 # function to convert arg_strings into positional actions
1900 def consume_positionals(start_index): 1902 def consume_positionals(start_index):
1901 # match as many Positionals as possible 1903 # match as many Positionals as possible
1902 match_partial = self._match_arguments_partial 1904 match_partial = self._match_arguments_partial
1903 selected_pattern = arg_strings_pattern[start_index:] 1905 selected_pattern = arg_strings_pattern[start_index:]
1904 arg_counts = match_partial(positionals, selected_pattern) 1906 arg_counts = match_partial(positionals, selected_pattern)
1905 1907
1906 #print([[x[0].dest,x[1]] for x in zip(positionals, arg_counts)])
1907 # if arg_count==0 and nargs '*' ('?'as well) make it tentative?
1908 # or lop off the last match if count is 0 and there's an 'O' in
1909 # remaining pattern
1910 # e.g. 'AOAA',[1,0],[null,'*']
1911 if 'O' in arg_strings_pattern[start_index:]:
1912 # if there is an optional after this, remove
1913 # 'empty' positionals from the current match
1914 while len(arg_counts)>1 and arg_counts[-1]==0:
1915 print(arg_counts, arg_strings_pattern)
1916 arg_counts = arg_counts[:-1]
1917 print([[x[0].dest,x[1]] for x in zip(positionals, arg_counts )])
1918
1919 # slice off the appropriate arg strings for each Positional 1908 # slice off the appropriate arg strings for each Positional
1920 # and add the Positional and its args to the list 1909 # and add the Positional and its args to the list
1921 for action, arg_count in zip(positionals, arg_counts): 1910 for action, arg_count in zip(positionals, arg_counts):
1922 args = arg_strings[start_index: start_index + arg_count] 1911 args = arg_strings[start_index: start_index + arg_count]
1923 start_index += arg_count 1912 start_index += arg_count
1924 take_action(action, args) 1913 take_action(action, args)
1925 1914
1926 # slice off the Positionals that we just parsed and return the 1915 # slice off the Positionals that we just parsed and return the
1927 # index at which the Positionals' string args stopped 1916 # index at which the Positionals' string args stopped
1928 positionals[:] = positionals[len(arg_counts):] 1917 positionals[:] = positionals[len(arg_counts):]
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
2201 nargs_pattern = '(-*A[A-]*)' 2190 nargs_pattern = '(-*A[A-]*)'
2202 2191
2203 # allow any number of options or arguments 2192 # allow any number of options or arguments
2204 elif nargs == REMAINDER: 2193 elif nargs == REMAINDER:
2205 nargs_pattern = '([-AO]*)' 2194 nargs_pattern = '([-AO]*)'
2206 2195
2207 # allow one argument followed by any number of options or arguments 2196 # allow one argument followed by any number of options or arguments
2208 elif nargs == PARSER: 2197 elif nargs == PARSER:
2209 nargs_pattern = '(-*A[-AO]*)' 2198 nargs_pattern = '(-*A[-AO]*)'
2210 2199
2200 # suppress action, like nargs=0
2201 elif nargs == SUPPRESS:
2202 nargs_pattern = '(-*-*)'
2203
2211 # all others should be integers 2204 # all others should be integers
2212 else: 2205 else:
2213 nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs) 2206 nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
2214 2207
2215 # if this is an optional action, -- is not allowed 2208 # if this is an optional action, -- is not allowed
2216 if action.option_strings: 2209 if action.option_strings:
2217 nargs_pattern = nargs_pattern.replace('-*', '') 2210 nargs_pattern = nargs_pattern.replace('-*', '')
2218 nargs_pattern = nargs_pattern.replace('-', '') 2211 nargs_pattern = nargs_pattern.replace('-', '')
2219 2212
2220 # return the pattern 2213 # return the pattern
2221 return nargs_pattern 2214 return nargs_pattern
2215
2216 # ========================
2217 # Alt command line argument parsing, allowing free intermix
2218 # ========================
2219
2220 def parse_intermixed_args(self, args=None, namespace=None):
2221 args, argv = self.parse_known_intermixed_args(args, namespace)
2222 if argv:
2223 msg = _('unrecognized arguments: %s')
2224 self.error(msg % ' '.join(argv))
2225 return args
2226
2227 def parse_known_intermixed_args(self, args=None, namespace=None):
2228 # self - argparse parser
2229 # args, namespace - as used by parse_known_args
2230 # returns a namespace and list of extras
2231
2232 # positional can be freely intermixed with optionals
2233 # optionals are first parsed with all positional arguments deactivated
2234 # the 'extras' are then parsed
2235 # if parser definition is incompatible with the intermixed assumptions
2236 # returns a TypeError (e.g. use of REMAINDER, subparsers)
2237
2238 # positionals are 'deactivated' by setting nargs and default to SUPPRESS .
2239 # This blocks the addition of that positional to the namespace
2240
2241 positionals = self._get_positional_actions()
2242 a = [action for action in positionals if action.nargs in [PARSER, REMAIN DER]]
2243 if a:
2244 raise TypeError('parse_intermixed_args: positional arg with nargs=%s '%a[0].nargs)
2245
2246 if [action.dest for group in self._mutually_exclusive_groups
2247 for action in group._group_actions if action in positionals]:
2248 raise TypeError('parse_intermixed_args: positional in mutuallyExclus iveGroup')
2249
2250 save_usage = self.usage
2251 try:
2252 if self.usage is None:
2253 # capture the full usage for use in error messages
2254 self.usage = self.format_usage()[7:]
2255 for action in positionals:
2256 # deactivate positionals
2257 action.save_nargs = action.nargs
2258 # action.nargs = 0
2259 action.nargs = SUPPRESS
2260 action.save_default = action.default
2261 action.default = SUPPRESS
2262 try:
2263 namespace, remaining_args = self.parse_known_args(args, namespac e)
2264 for action in positionals:
2265 # remove the empty positional values from namespace
2266 if hasattr(namespace, action.dest) and getattr(namespace, ac tion.dest)==[]:
2267 from warnings import warn
2268 warn('Do not expect %s in %s'%(action.dest,namespace))
2269 delattr(namespace, action.dest)
2270 finally:
2271 # restore nargs and usage before exiting
2272 for action in positionals:
2273 action.nargs = action.save_nargs
2274 action.default = action.save_default
2275 # parse positionals
2276 # optionals aren't normally required, but just in case, turn that of f
2277 optionals = self._get_optional_actions()
2278 for action in optionals:
2279 action.save_required = action.required
2280 action.required = False
2281 for group in self._mutually_exclusive_groups:
2282 group.save_required = group.required
2283 group.required = False
2284 try:
2285 namespace, extras = self.parse_known_args(remaining_args, namesp ace)
2286 finally:
2287 # restore parser values before exiting
2288 for action in optionals:
2289 action.required = action.save_required
2290 for group in self._mutually_exclusive_groups:
2291 group.required = group.save_required
2292 finally:
2293 self.usage = save_usage
2294 return namespace, extras
2222 2295
2223 # ======================== 2296 # ========================
2224 # Value conversion methods 2297 # Value conversion methods
2225 # ======================== 2298 # ========================
2226 def _get_values(self, action, arg_strings): 2299 def _get_values(self, action, arg_strings):
2227 # for everything but PARSER, REMAINDER args, strip out first '--' 2300 # for everything but PARSER, REMAINDER args, strip out first '--'
2228 if action.nargs not in [PARSER, REMAINDER]: 2301 if action.nargs not in [PARSER, REMAINDER]:
2229 try: 2302 try:
2230 arg_strings.remove('--') 2303 arg_strings.remove('--')
2231 except ValueError: 2304 except ValueError:
(...skipping 27 matching lines...) Expand all
2259 2332
2260 # REMAINDER arguments convert all values, checking none 2333 # REMAINDER arguments convert all values, checking none
2261 elif action.nargs == REMAINDER: 2334 elif action.nargs == REMAINDER:
2262 value = [self._get_value(action, v) for v in arg_strings] 2335 value = [self._get_value(action, v) for v in arg_strings]
2263 2336
2264 # PARSER arguments convert all values, but check only the first 2337 # PARSER arguments convert all values, but check only the first
2265 elif action.nargs == PARSER: 2338 elif action.nargs == PARSER:
2266 value = [self._get_value(action, v) for v in arg_strings] 2339 value = [self._get_value(action, v) for v in arg_strings]
2267 self._check_value(action, value[0]) 2340 self._check_value(action, value[0])
2268 2341
2342 # SUPPRESS argument does not put anything in the namespace
2343 elif action.nargs == SUPPRESS:
2344 value = SUPPRESS
2345
2269 # all other types of nargs produce a list 2346 # all other types of nargs produce a list
2270 else: 2347 else:
2271 value = [self._get_value(action, v) for v in arg_strings] 2348 value = [self._get_value(action, v) for v in arg_strings]
2272 for v in value: 2349 for v in value:
2273 self._check_value(action, v) 2350 self._check_value(action, v)
2274 2351
2275 # return the converted value 2352 # return the converted value
2276 return value 2353 return value
2277 2354
2278 def _get_value(self, action, arg_string): 2355 def _get_value(self, action, arg_string):
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
2376 2453
2377 Prints a usage message incorporating the message to stderr and 2454 Prints a usage message incorporating the message to stderr and
2378 exits. 2455 exits.
2379 2456
2380 If you override this in a subclass, it should not return -- it 2457 If you override this in a subclass, it should not return -- it
2381 should either exit or raise an exception. 2458 should either exit or raise an exception.
2382 """ 2459 """
2383 self.print_usage(_sys.stderr) 2460 self.print_usage(_sys.stderr)
2384 args = {'prog': self.prog, 'message': message} 2461 args = {'prog': self.prog, 'message': message}
2385 self.exit(2, _('%(prog)s: error: %(message)s\n') % args) 2462 self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+