Parse args for a subcommand but do not consume the arg table. This is similar to the ArgTableArgParser, except it doesn't consume any args from the provided arg table, though it will respect the arg table when looking for a subcommand.
| 214 | |
| 215 | |
| 216 | class SubCommandArgParser(ArgTableArgParser): |
| 217 | """Parse args for a subcommand but do not consume the arg table. |
| 218 | |
| 219 | This is similar to the ArgTableArgParser, except it doesn't consume |
| 220 | any args from the provided arg table, though it will respect the |
| 221 | arg table when looking for a subcommand. |
| 222 | |
| 223 | """ |
| 224 | |
| 225 | def parse_known_args(self, args, namespace=None): |
| 226 | parsed_args, remaining = super().parse_known_args(args, namespace) |
| 227 | if getattr(parsed_args, 'subcommand', None) is not None: |
| 228 | new_args = self._remove_subcommand(args, parsed_args) |
| 229 | return new_args, parsed_args.subcommand |
| 230 | return None |
| 231 | |
| 232 | def _remove_subcommand(self, args, parsed_args): |
| 233 | # We want to remove only the subcommand from the args list |
| 234 | # and keep everything else. We should be safe to remove |
| 235 | # the first argument that matches the subcommand name. |
| 236 | # |
| 237 | # .parse_known_args() assumes that any args that it doesn't |
| 238 | # understand do not consume any values. For example: |
| 239 | # |
| 240 | # aws ecs --cluster mycluster describe-tasks --tasks foo |
| 241 | # |
| 242 | # is not a valid command, because we ignore `--cluster` |
| 243 | # and assume that `mycluster` is a subcommand. |
| 244 | # |
| 245 | # However, this command works: |
| 246 | # |
| 247 | # aws ecs --cluster=mycluster desribe-tasks --tasks foo |
| 248 | # |
| 249 | # Therefore we don't have to worry about the case where |
| 250 | # a param *value* shadows the parsed subcommand because |
| 251 | # the existing parser would have already errored out. |
| 252 | new_args = args[:] |
| 253 | new_args.remove(parsed_args.subcommand) |
| 254 | return new_args |
| 255 | |
| 256 | def _build(self, argument_table, command_table): |
| 257 | # In order to check for a subcommand while still respecting |
| 258 | # the arg table, we do need to consider the arg table, but not |
| 259 | # fail if any of the required args aren't provided. We don't |
| 260 | # want to mutate the arg table that's provided to us, so we |
| 261 | # make a copy of it and then set all the required to not required. |
| 262 | non_required_arg_table = self._non_required_arg_table(argument_table) |
| 263 | for arg_name in non_required_arg_table: |
| 264 | argument = non_required_arg_table[arg_name] |
| 265 | argument.add_to_parser(self) |
| 266 | if command_table: |
| 267 | self.add_argument( |
| 268 | 'subcommand', |
| 269 | action=CommandAction, |
| 270 | command_table=command_table, |
| 271 | nargs='?', |
| 272 | ) |
| 273 |
no outgoing calls
no test coverage detected