comparison env/lib/python3.9/site-packages/argcomplete/my_argparse.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # Copyright 2012-2019, Andrey Kislyuk and argcomplete contributors.
2 # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info.
3
4 from argparse import ArgumentParser, ArgumentError, SUPPRESS, _SubParsersAction
5 from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER
6 from argparse import _get_action_name, _
7
8 _num_consumed_args = {}
9
10
11 def action_is_satisfied(action):
12 ''' Returns False if the parse would raise an error if no more arguments are given to this action, True otherwise.
13 '''
14 num_consumed_args = _num_consumed_args.get(action, 0)
15
16 if action.nargs in [OPTIONAL, ZERO_OR_MORE, REMAINDER]:
17 return True
18 if action.nargs == ONE_OR_MORE:
19 return num_consumed_args >= 1
20 if action.nargs == PARSER:
21 # Not sure what this should be, but this previously always returned False
22 # so at least this won't break anything that wasn't already broken.
23 return False
24 if action.nargs is None:
25 return num_consumed_args == 1
26
27 assert isinstance(action.nargs, int), 'failed to handle a possible nargs value: %r' % action.nargs
28 return num_consumed_args == action.nargs
29
30
31 def action_is_open(action):
32 ''' Returns True if action could consume more arguments (i.e., its pattern is open).
33 '''
34 num_consumed_args = _num_consumed_args.get(action, 0)
35
36 if action.nargs in [ZERO_OR_MORE, ONE_OR_MORE, PARSER, REMAINDER]:
37 return True
38 if action.nargs == OPTIONAL or action.nargs is None:
39 return num_consumed_args == 0
40
41 assert isinstance(action.nargs, int), 'failed to handle a possible nargs value: %r' % action.nargs
42 return num_consumed_args < action.nargs
43
44
45 def action_is_greedy(action, isoptional=False):
46 ''' Returns True if action will necessarily consume the next argument.
47 isoptional indicates whether the argument is an optional (starts with -).
48 '''
49 num_consumed_args = _num_consumed_args.get(action, 0)
50
51 if action.option_strings:
52 if not isoptional and not action_is_satisfied(action):
53 return True
54 return action.nargs == REMAINDER
55 else:
56 return action.nargs == REMAINDER and num_consumed_args >= 1
57
58
59 class IntrospectiveArgumentParser(ArgumentParser):
60 ''' The following is a verbatim copy of ArgumentParser._parse_known_args (Python 2.7.3),
61 except for the lines that contain the string "Added by argcomplete".
62 '''
63
64 def _parse_known_args(self, arg_strings, namespace):
65 _num_consumed_args.clear() # Added by argcomplete
66 self._argcomplete_namespace = namespace
67 self.active_actions = [] # Added by argcomplete
68 # replace arg strings that are file references
69 if self.fromfile_prefix_chars is not None:
70 arg_strings = self._read_args_from_files(arg_strings)
71
72 # map all mutually exclusive arguments to the other arguments
73 # they can't occur with
74 action_conflicts = {}
75 self._action_conflicts = action_conflicts # Added by argcomplete
76 for mutex_group in self._mutually_exclusive_groups:
77 group_actions = mutex_group._group_actions
78 for i, mutex_action in enumerate(mutex_group._group_actions):
79 conflicts = action_conflicts.setdefault(mutex_action, [])
80 conflicts.extend(group_actions[:i])
81 conflicts.extend(group_actions[i + 1:])
82
83 # find all option indices, and determine the arg_string_pattern
84 # which has an 'O' if there is an option at an index,
85 # an 'A' if there is an argument, or a '-' if there is a '--'
86 option_string_indices = {}
87 arg_string_pattern_parts = []
88 arg_strings_iter = iter(arg_strings)
89 for i, arg_string in enumerate(arg_strings_iter):
90
91 # all args after -- are non-options
92 if arg_string == '--':
93 arg_string_pattern_parts.append('-')
94 for arg_string in arg_strings_iter:
95 arg_string_pattern_parts.append('A')
96
97 # otherwise, add the arg to the arg strings
98 # and note the index if it was an option
99 else:
100 option_tuple = self._parse_optional(arg_string)
101 if option_tuple is None:
102 pattern = 'A'
103 else:
104 option_string_indices[i] = option_tuple
105 pattern = 'O'
106 arg_string_pattern_parts.append(pattern)
107
108 # join the pieces together to form the pattern
109 arg_strings_pattern = ''.join(arg_string_pattern_parts)
110
111 # converts arg strings to the appropriate and then takes the action
112 seen_actions = set()
113 seen_non_default_actions = set()
114 self._seen_non_default_actions = seen_non_default_actions # Added by argcomplete
115
116 def take_action(action, argument_strings, option_string=None):
117 seen_actions.add(action)
118 argument_values = self._get_values(action, argument_strings)
119
120 # error if this argument is not allowed with other previously
121 # seen arguments, assuming that actions that use the default
122 # value don't really count as "present"
123 if argument_values is not action.default:
124 seen_non_default_actions.add(action)
125 for conflict_action in action_conflicts.get(action, []):
126 if conflict_action in seen_non_default_actions:
127 msg = _('not allowed with argument %s')
128 action_name = _get_action_name(conflict_action)
129 raise ArgumentError(action, msg % action_name)
130
131 # take the action if we didn't receive a SUPPRESS value
132 # (e.g. from a default)
133 if argument_values is not SUPPRESS \
134 or isinstance(action, _SubParsersAction):
135 try:
136 action(self, namespace, argument_values, option_string)
137 except:
138 # Begin added by argcomplete
139 # When a subparser action is taken and fails due to incomplete arguments, it does not merge the
140 # contents of its parsed namespace into the parent namespace. Do that here to allow completers to
141 # access the partially parsed arguments for the subparser.
142 if isinstance(action, _SubParsersAction):
143 subnamespace = action._name_parser_map[argument_values[0]]._argcomplete_namespace
144 for key, value in vars(subnamespace).items():
145 setattr(namespace, key, value)
146 # End added by argcomplete
147 raise
148
149 # function to convert arg_strings into an optional action
150 def consume_optional(start_index):
151
152 # get the optional identified at this index
153 option_tuple = option_string_indices[start_index]
154 action, option_string, explicit_arg = option_tuple
155
156 # identify additional optionals in the same arg string
157 # (e.g. -xyz is the same as -x -y -z if no args are required)
158 match_argument = self._match_argument
159 action_tuples = []
160 while True:
161
162 # if we found no optional action, skip it
163 if action is None:
164 extras.append(arg_strings[start_index])
165 return start_index + 1
166
167 # if there is an explicit argument, try to match the
168 # optional's string arguments to only this
169 if explicit_arg is not None:
170 arg_count = match_argument(action, 'A')
171
172 # if the action is a single-dash option and takes no
173 # arguments, try to parse more single-dash options out
174 # of the tail of the option string
175 chars = self.prefix_chars
176 if arg_count == 0 and option_string[1] not in chars:
177 action_tuples.append((action, [], option_string))
178 char = option_string[0]
179 option_string = char + explicit_arg[0]
180 new_explicit_arg = explicit_arg[1:] or None
181 optionals_map = self._option_string_actions
182 if option_string in optionals_map:
183 action = optionals_map[option_string]
184 explicit_arg = new_explicit_arg
185 else:
186 msg = _('ignored explicit argument %r')
187 raise ArgumentError(action, msg % explicit_arg)
188
189 # if the action expect exactly one argument, we've
190 # successfully matched the option; exit the loop
191 elif arg_count == 1:
192 stop = start_index + 1
193 args = [explicit_arg]
194 action_tuples.append((action, args, option_string))
195 break
196
197 # error if a double-dash option did not use the
198 # explicit argument
199 else:
200 msg = _('ignored explicit argument %r')
201 raise ArgumentError(action, msg % explicit_arg)
202
203 # if there is no explicit argument, try to match the
204 # optional's string arguments with the following strings
205 # if successful, exit the loop
206 else:
207 start = start_index + 1
208 selected_patterns = arg_strings_pattern[start:]
209 self.active_actions = [action] # Added by argcomplete
210 _num_consumed_args[action] = 0 # Added by argcomplete
211 arg_count = match_argument(action, selected_patterns)
212 stop = start + arg_count
213 args = arg_strings[start:stop]
214
215 # Begin added by argcomplete
216 # If the pattern is not open (e.g. no + at the end), remove the action from active actions (since
217 # it wouldn't be able to consume any more args)
218 _num_consumed_args[action] = len(args)
219 if not action_is_open(action):
220 self.active_actions.remove(action)
221 # End added by argcomplete
222
223 action_tuples.append((action, args, option_string))
224 break
225
226 # add the Optional to the list and return the index at which
227 # the Optional's string args stopped
228 assert action_tuples
229 for action, args, option_string in action_tuples:
230 take_action(action, args, option_string)
231 return stop
232
233 # the list of Positionals left to be parsed; this is modified
234 # by consume_positionals()
235 positionals = self._get_positional_actions()
236
237 # function to convert arg_strings into positional actions
238 def consume_positionals(start_index):
239 # match as many Positionals as possible
240 match_partial = self._match_arguments_partial
241 selected_pattern = arg_strings_pattern[start_index:]
242 arg_counts = match_partial(positionals, selected_pattern)
243
244 # slice off the appropriate arg strings for each Positional
245 # and add the Positional and its args to the list
246 for action, arg_count in zip(positionals, arg_counts): # Added by argcomplete
247 self.active_actions.append(action) # Added by argcomplete
248 for action, arg_count in zip(positionals, arg_counts):
249 args = arg_strings[start_index: start_index + arg_count]
250 start_index += arg_count
251 _num_consumed_args[action] = len(args) # Added by argcomplete
252 take_action(action, args)
253
254 # slice off the Positionals that we just parsed and return the
255 # index at which the Positionals' string args stopped
256 positionals[:] = positionals[len(arg_counts):]
257 return start_index
258
259 # consume Positionals and Optionals alternately, until we have
260 # passed the last option string
261 extras = []
262 start_index = 0
263 if option_string_indices:
264 max_option_string_index = max(option_string_indices)
265 else:
266 max_option_string_index = -1
267 while start_index <= max_option_string_index:
268
269 # consume any Positionals preceding the next option
270 next_option_string_index = min([
271 index
272 for index in option_string_indices
273 if index >= start_index])
274 if start_index != next_option_string_index:
275 positionals_end_index = consume_positionals(start_index)
276
277 # only try to parse the next optional if we didn't consume
278 # the option string during the positionals parsing
279 if positionals_end_index > start_index:
280 start_index = positionals_end_index
281 continue
282 else:
283 start_index = positionals_end_index
284
285 # if we consumed all the positionals we could and we're not
286 # at the index of an option string, there were extra arguments
287 if start_index not in option_string_indices:
288 strings = arg_strings[start_index:next_option_string_index]
289 extras.extend(strings)
290 start_index = next_option_string_index
291
292 # consume the next optional and any arguments for it
293 start_index = consume_optional(start_index)
294
295 # consume any positionals following the last Optional
296 stop_index = consume_positionals(start_index)
297
298 # if we didn't consume all the argument strings, there were extras
299 extras.extend(arg_strings[stop_index:])
300
301 # if we didn't use all the Positional objects, there were too few
302 # arg strings supplied.
303
304 if positionals:
305 self.active_actions.append(positionals[0]) # Added by argcomplete
306 self.error(_('too few arguments'))
307
308 # make sure all required actions were present
309 for action in self._actions:
310 if action.required:
311 if action not in seen_actions:
312 name = _get_action_name(action)
313 self.error(_('argument %s is required') % name)
314
315 # make sure all required groups had one option present
316 for group in self._mutually_exclusive_groups:
317 if group.required:
318 for action in group._group_actions:
319 if action in seen_non_default_actions:
320 break
321
322 # if no actions were used, report the error
323 else:
324 names = [_get_action_name(action)
325 for action in group._group_actions
326 if action.help is not SUPPRESS]
327 msg = _('one of the arguments %s is required')
328 self.error(msg % ' '.join(names))
329
330 # return the updated namespace and the extra arguments
331 return namespace, extras