1 def _parse_known_args(self, arg_strings, namespace):
2 # replace arg strings that are file references
3 if self.fromfile_prefix_chars is not None:
4 arg_strings = self._read_args_from_files(arg_strings)
5
6 # map all mutually exclusive arguments to the other arguments
7 # they can't occur with
8 action_conflicts = {}
9 for mutex_group in self._mutually_exclusive_groups:
10 group_actions = mutex_group._group_actions
11 for i, mutex_action in enumerate(mutex_group._group_actions):
12 conflicts = action_conflicts.setdefault(mutex_action, [])
13 conflicts.extend(group_actions[:i])
14 conflicts.extend(group_actions[i + 1:])
15
16 # find all option indices, and determine the arg_string_pattern
17 # which has an 'O' if there is an option at an index,
18 # an 'A' if there is an argument, or a '-' if there is a '--'
19 option_string_indices = {}
20 arg_string_pattern_parts = []
21 arg_strings_iter = iter(arg_strings)
22 for i, arg_string in enumerate(arg_strings_iter):
23
24 # all args after -- are non-options
25 if arg_string == '--':
26 arg_string_pattern_parts.append('-')
27 for arg_string in arg_strings_iter:
28 arg_string_pattern_parts.append('A')
29
30 # otherwise, add the arg to the arg strings
31 # and note the index if it was an option
32 else:
33 option_tuple = self._parse_optional(arg_string)
34 if option_tuple is None:
35 pattern = 'A'
36 else:
37 option_string_indices[i] = option_tuple
38 pattern = 'O'
39 arg_string_pattern_parts.append(pattern)
40
41 # join the pieces together to form the pattern
42 arg_strings_pattern = ''.join(arg_string_pattern_parts)
43
44 # converts arg strings to the appropriate and then takes the action
45 seen_actions = set()
46 seen_non_default_actions = set()
47
48 def take_action(action, argument_strings, option_string=None):
49 seen_actions.add(action)
50 argument_values = self._get_values(action, argument_strings)
51
52 # error if this argument is not allowed with other previously
53 # seen arguments, assuming that actions that use the default
54 # value don't really count as "present"
55 if argument_values is not action.default:
56 seen_non_default_actions.add(action)
57 for conflict_action in action_conflicts.get(action, []):
58 if conflict_action in seen_non_default_actions:
59 msg = _('not allowed with argument %s')
60 action_name = _get_action_name(conflict_action)
61 raise ArgumentError(action, msg % action_name)
62
63 # take the action if we didn't receive a SUPPRESS value
64 # (e.g. from a default)
65 if argument_values is not SUPPRESS:
66 action(self, namespace, argument_values, option_string)
67
68 # function to convert arg_strings into an optional action
69 def consume_optional(start_index):
70
71 # get the optional identified at this index
72 option_tuple = option_string_indices[start_index]
73 action, option_string, explicit_arg = option_tuple
74
75 # identify additional optionals in the same arg string
76 # (e.g. -xyz is the same as -x -y -z if no args are required)
77 match_argument = self._match_argument
78 action_tuples = []
79 while True:
80
81 # if we found no optional action, skip it
82 if action is None:
83 extras.append(arg_strings[start_index])
84 return start_index + 1
85
86 # if there is an explicit argument, try to match the
87 # optional's string arguments to only this
88 if explicit_arg is not None:
89 arg_count = match_argument(action, 'A')
90
91 # if the action is a single-dash option and takes no
92 # arguments, try to parse more single-dash options out
93 # of the tail of the option string
94 chars = self.prefix_chars
95 if arg_count == 0 and option_string[1] not in chars:
96 action_tuples.append((action, [], option_string))
97 char = option_string[0]
98 option_string = char + explicit_arg[0]
99 new_explicit_arg = explicit_arg[1:] or None
100 optionals_map = self._option_string_actions
101 if option_string in optionals_map:
102 action = optionals_map[option_string]
103 explicit_arg = new_explicit_arg
104 else:
105 msg = _('ignored explicit argument %r')
106 raise ArgumentError(action, msg % explicit_arg)
107
108 # if the action expect exactly one argument, we've
109 # successfully matched the option; exit the loop
110 elif arg_count == 1:
111 stop = start_index + 1
112 args = [explicit_arg]
113 action_tuples.append((action, args, option_string))
114 break
115
116 # error if a double-dash option did not use the
117 # explicit argument
118 else:
119 msg = _('ignored explicit argument %r')
120 raise ArgumentError(action, msg % explicit_arg)
121
122 # if there is no explicit argument, try to match the
123 # optional's string arguments with the following strings
124 # if successful, exit the loop
125 else:
126 start = start_index + 1
127 selected_patterns = arg_strings_pattern[start:]
128 arg_count = match_argument(action, selected_patterns)
129 stop = start + arg_count
130 args = arg_strings[start:stop]
131 action_tuples.append((action, args, option_string))
132 break
133
134 # add the Optional to the list and return the index at which
135 # the Optional's string args stopped
136 assert action_tuples
137 for action, args, option_string in action_tuples:
138 take_action(action, args, option_string)
139 return stop
140
141 # the list of Positionals left to be parsed; this is modified
142 # by consume_positionals()
143 positionals = self._get_positional_actions()
144
145 # function to convert arg_strings into positional actions
146 def consume_positionals(start_index):
147 # match as many Positionals as possible
148 match_partial = self._match_arguments_partial
149 selected_pattern = arg_strings_pattern[start_index:]
150 arg_counts = match_partial(positionals, selected_pattern)
151
152 # slice off the appropriate arg strings for each Positional
153 # and add the Positional and its args to the list
154 for action, arg_count in zip(positionals, arg_counts):
155 args = arg_strings[start_index: start_index + arg_count]
156 start_index += arg_count
157 take_action(action, args)
158
159 # slice off the Positionals that we just parsed and return the
160 # index at which the Positionals' string args stopped
161 positionals[:] = positionals[len(arg_counts):]
162 return start_index
163
164 # consume Positionals and Optionals alternately, until we have
165 # passed the last option string
166 extras = []
167 start_index = 0
168 if option_string_indices:
169 max_option_string_index = max(option_string_indices)
170 else:
171 max_option_string_index = -1
172 while start_index <= max_option_string_index:
173
174 # consume any Positionals preceding the next option
175 next_option_string_index = min([
176 index
177 for index in option_string_indices
178 if index >= start_index])
179 if start_index != next_option_string_index:
180 positionals_end_index = consume_positionals(start_index)
181
182 # only try to parse the next optional if we didn't consume
183 # the option string during the positionals parsing
184 if positionals_end_index > start_index:
185 start_index = positionals_end_index
186 continue
187 else:
188 start_index = positionals_end_index
189
190 # if we consumed all the positionals we could and we're not
191 # at the index of an option string, there were extra arguments
192 if start_index not in option_string_indices:
193 strings = arg_strings[start_index:next_option_string_index]
194 extras.extend(strings)
195 start_index = next_option_string_index
196
197 # consume the next optional and any arguments for it
198 start_index = consume_optional(start_index)
199
200 # consume any positionals following the last Optional
201 stop_index = consume_positionals(start_index)
202
203 # if we didn't consume all the argument strings, there were extras
204 extras.extend(arg_strings[stop_index:])
205
206 # make sure all required actions were present and also convert
207 # action defaults which were not given as arguments
208 required_actions = []
209 for action in self._actions:
210 if action not in seen_actions:
211 if action.required:
212 required_actions.append(_get_action_name(action))
213 else:
214 # Convert action default now instead of doing it before
215 # parsing arguments to avoid calling convert functions
216 # twice (which may fail) if the argument was given, but
217 # only if it was defined already in the namespace
218 if (action.default is not None and
219 isinstance(action.default, str) and
220 hasattr(namespace, action.dest) and
221 action.default is getattr(namespace, action.dest)):
222 setattr(namespace, action.dest,
223 self._get_value(action, action.default))
224
225 if required_actions:
226 self.error(_('the following arguments are required: %s') %
227 ', '.join(required_actions))
228
229 # make sure all required groups had one option present
230 for group in self._mutually_exclusive_groups:
231 if group.required:
232 for action in group._group_actions:
233 if action in seen_non_default_actions:
234 break
235
236 # if no actions were used, report the error
237 else:
238 names = [_get_action_name(action)
239 for action in group._group_actions
240 if action.help is not SUPPRESS]
241 msg = _('one of the arguments %s is required')
242 self.error(msg % ' '.join(names))
243
244 # return the updated namespace and the extra arguments
245 return namespace, extras