codekingpro/portable-devtools
114k
1# Author: Steven J. Bethard <steven.bethard@gmail.com>.2# New maintainer as of 29 August 2019: Raymond Hettinger <raymond.hettinger@gmail.com>3 4"""Command-line parsing library5 6This module is an optparse-inspired command-line parsing library that:7 8 - handles both optional and positional arguments9 - produces highly informative usage messages10 - supports parsers that dispatch to sub-parsers11 12The following is a simple usage example that sums integers from the13command-line and writes the result to a file::14 15 parser = argparse.ArgumentParser(16 description='sum the integers at the command line')17 parser.add_argument(18 'integers', metavar='int', nargs='+', type=int,19 help='an integer to be summed')20 parser.add_argument(21 '--log',22 help='the file where the sum should be written')23 args = parser.parse_args()24 with (open(args.log, 'w') if args.log is not None25 else contextlib.nullcontext(sys.stdout)) as log:26 log.write('%s' % sum(args.integers))27 28The module contains the following public classes:29 30 - ArgumentParser -- The main entry point for command-line parsing. As the31 example above shows, the add_argument() method is used to populate32 the parser with actions for optional and positional arguments. Then33 the parse_args() method is invoked to convert the args at the34 command-line into an object with attributes.35 36 - ArgumentError -- The exception raised by ArgumentParser objects when37 there are errors with the parser's actions. Errors raised while38 parsing the command-line are caught by ArgumentParser and emitted39 as command-line messages.40 41 - FileType -- A factory for defining types of files to be created. As the42 example above shows, instances of FileType are typically passed as43 the type= argument of add_argument() calls. Deprecated since44 Python 3.14.45 46 - Action -- The base class for parser actions. Typically actions are47 selected by passing strings like 'store_true' or 'append_const' to48 the action= argument of add_argument(). However, for greater49 customization of ArgumentParser actions, subclasses of Action may50 be defined and passed as the action= argument.51 52 - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,53 ArgumentDefaultsHelpFormatter -- Formatter classes which54 may be passed as the formatter_class= argument to the55 ArgumentParser constructor. HelpFormatter is the default,56 RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser57 not to change the formatting for help text, and58 ArgumentDefaultsHelpFormatter adds information about argument defaults59 to the help.60 61All other classes in this module are considered implementation details.62(Also note that HelpFormatter and RawDescriptionHelpFormatter are only63considered public as object names -- the API of the formatter objects is64still considered an implementation detail.)65"""66 67__version__ = '1.1'68__all__ = [69 'ArgumentParser',70 'ArgumentError',71 'ArgumentTypeError',72 'BooleanOptionalAction',73 'FileType',74 'HelpFormatter',75 'ArgumentDefaultsHelpFormatter',76 'RawDescriptionHelpFormatter',77 'RawTextHelpFormatter',78 'MetavarTypeHelpFormatter',79 'Namespace',80 'Action',81 'ONE_OR_MORE',82 'OPTIONAL',83 'PARSER',84 'REMAINDER',85 'SUPPRESS',86 'ZERO_OR_MORE',87]88 89 90import os as _os91import re as _re92import sys as _sys93 94from gettext import gettext as _, ngettext95 96SUPPRESS = '==SUPPRESS=='97 98OPTIONAL = '?'99ZERO_OR_MORE = '*'100ONE_OR_MORE = '+'101PARSER = 'A...'102REMAINDER = '...'103_UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'104 105# =============================106# Utility functions and classes107# =============================108 109class _AttributeHolder(object):110 """Abstract base class that provides __repr__.111 112 The __repr__ method returns a string in the format::113 ClassName(attr=name, attr=name, ...)114 The attributes are determined either by a class-level attribute,115 '_kwarg_names', or by inspecting the instance __dict__.116 """117 118 def __repr__(self):119 type_name = type(self).__name__120 arg_strings = []121 star_args = {}122 for arg in self._get_args():123 arg_strings.append(repr(arg))124 for name, value in self._get_kwargs():125 if name.isidentifier():126 arg_strings.append('%s=%r' % (name, value))127 else:128 star_args[name] = value129 if star_args:130 arg_strings.append('**%s' % repr(star_args))131 return '%s(%s)' % (type_name, ', '.join(arg_strings))132 133 def _get_kwargs(self):134 return list(self.__dict__.items())135 136 def _get_args(self):137 return []138 139 140def _copy_items(items):141 if items is None:142 return []143 # The copy module is used only in the 'append' and 'append_const'144 # actions, and it is needed only when the default value isn't a list.145 # Delay its import for speeding up the common case.146 if type(items) is list:147 return items[:]148 import copy149 return copy.copy(items)150 151 152def _identity(value):153 return value154 155 156# ===============157# Formatting Help158# ===============159 160 161class HelpFormatter(object):162 """Formatter for generating usage messages and argument help strings.163 164 Only the name of this class is considered a public API. All the methods165 provided by the class are considered an implementation detail.166 """167 168 def __init__(169 self,170 prog,171 indent_increment=2,172 max_help_position=24,173 width=None,174 color=True,175 ):176 # default setting for width177 if width is None:178 import shutil179 width = shutil.get_terminal_size().columns180 width -= 2181 182 self._set_color(color)183 self._prog = prog184 self._indent_increment = indent_increment185 self._max_help_position = min(max_help_position,186 max(width - 20, indent_increment * 2))187 self._width = width188 189 self._current_indent = 0190 self._level = 0191 self._action_max_length = 0192 193 self._root_section = self._Section(self, None)194 self._current_section = self._root_section195 196 self._whitespace_matcher = _re.compile(r'\s+', _re.ASCII)197 self._long_break_matcher = _re.compile(r'\n\n\n+')198 199 def _set_color(self, color):200 from _colorize import can_colorize, decolor, get_theme201 202 if color and can_colorize():203 self._theme = get_theme(force_color=True).argparse204 self._decolor = decolor205 else:206 self._theme = get_theme(force_no_color=True).argparse207 self._decolor = _identity208 209 # ===============================210 # Section and indentation methods211 # ===============================212 213 def _indent(self):214 self._current_indent += self._indent_increment215 self._level += 1216 217 def _dedent(self):218 self._current_indent -= self._indent_increment219 assert self._current_indent >= 0, 'Indent decreased below 0.'220 self._level -= 1221 222 class _Section(object):223 224 def __init__(self, formatter, parent, heading=None):225 self.formatter = formatter226 self.parent = parent227 self.heading = heading228 self.items = []229 230 def format_help(self):231 # format the indented section232 if self.parent is not None:233 self.formatter._indent()234 join = self.formatter._join_parts235 item_help = join([func(*args) for func, args in self.items])236 if self.parent is not None:237 self.formatter._dedent()238 239 # return nothing if the section was empty240 if not item_help:241 return ''242 243 # add the heading if the section was non-empty244 if self.heading is not SUPPRESS and self.heading is not None:245 current_indent = self.formatter._current_indent246 heading_text = _('%(heading)s:') % dict(heading=self.heading)247 t = self.formatter._theme248 heading = (249 f'{" " * current_indent}'250 f'{t.heading}{heading_text}{t.reset}\n'251 )252 else:253 heading = ''254 255 # join the section-initial newline, the heading and the help256 return join(['\n', heading, item_help, '\n'])257 258 def _add_item(self, func, args):259 self._current_section.items.append((func, args))260 261 # ========================262 # Message building methods263 # ========================264 265 def start_section(self, heading):266 self._indent()267 section = self._Section(self, self._current_section, heading)268 self._add_item(section.format_help, [])269 self._current_section = section270 271 def end_section(self):272 self._current_section = self._current_section.parent273 self._dedent()274 275 def add_text(self, text):276 if text is not SUPPRESS and text is not None:277 self._add_item(self._format_text, [text])278 279 def add_usage(self, usage, actions, groups, prefix=None):280 if usage is not SUPPRESS:281 args = usage, actions, groups, prefix282 self._add_item(self._format_usage, args)283 284 def add_argument(self, action):285 if action.help is not SUPPRESS:286 287 # find all invocations288 get_invocation = lambda x: self._decolor(self._format_action_invocation(x))289 invocation_lengths = [len(get_invocation(action)) + self._current_indent]290 for subaction in self._iter_indented_subactions(action):291 invocation_lengths.append(len(get_invocation(subaction)) + self._current_indent)292 293 # update the maximum item length294 action_length = max(invocation_lengths)295 self._action_max_length = max(self._action_max_length,296 action_length)297 298 # add the item to the list299 self._add_item(self._format_action, [action])300 301 def add_arguments(self, actions):302 for action in actions:303 self.add_argument(action)304 305 # =======================306 # Help-formatting methods307 # =======================308 309 def format_help(self):310 help = self._root_section.format_help()311 if help:312 help = self._long_break_matcher.sub('\n\n', help)313 help = help.strip('\n') + '\n'314 return help315 316 def _join_parts(self, part_strings):317 return ''.join([part318 for part in part_strings319 if part and part is not SUPPRESS])320 321 def _format_usage(self, usage, actions, groups, prefix):322 t = self._theme323 324 if prefix is None:325 prefix = _('usage: ')326 327 # if usage is specified, use that328 if usage is not None:329 usage = (330 t.prog_extra331 + usage332 % {"prog": f"{t.prog}{self._prog}{t.reset}{t.prog_extra}"}333 + t.reset334 )335 336 # if no optionals or positionals are available, usage is just prog337 elif usage is None and not actions:338 usage = f"{t.prog}{self._prog}{t.reset}"339 340 # if optionals and positionals are available, calculate usage341 elif usage is None:342 prog = '%(prog)s' % dict(prog=self._prog)343 344 parts, pos_start = self._get_actions_usage_parts(actions, groups)345 # build full usage string346 usage = ' '.join(filter(None, [prog, *parts]))347 348 # wrap the usage parts if it's too long349 text_width = self._width - self._current_indent350 if len(prefix) + len(self._decolor(usage)) > text_width:351 352 # break usage into wrappable parts353 opt_parts = parts[:pos_start]354 pos_parts = parts[pos_start:]355 356 # helper for wrapping lines357 def get_lines(parts, indent, prefix=None):358 lines = []359 line = []360 indent_length = len(indent)361 if prefix is not None:362 line_len = len(prefix) - 1363 else:364 line_len = indent_length - 1365 for part in parts:366 part_len = len(self._decolor(part))367 if line_len + 1 + part_len > text_width and line:368 lines.append(indent + ' '.join(line))369 line = []370 line_len = indent_length - 1371 line.append(part)372 line_len += part_len + 1373 if line:374 lines.append(indent + ' '.join(line))375 if prefix is not None:376 lines[0] = lines[0][indent_length:]377 return lines378 379 # if prog is short, follow it with optionals or positionals380 prog_len = len(self._decolor(prog))381 if len(prefix) + prog_len <= 0.75 * text_width:382 indent = ' ' * (len(prefix) + prog_len + 1)383 if opt_parts:384 lines = get_lines([prog] + opt_parts, indent, prefix)385 lines.extend(get_lines(pos_parts, indent))386 elif pos_parts:387 lines = get_lines([prog] + pos_parts, indent, prefix)388 else:389 lines = [prog]390 391 # if prog is long, put it on its own line392 else:393 indent = ' ' * len(prefix)394 parts = opt_parts + pos_parts395 lines = get_lines(parts, indent)396 if len(lines) > 1:397 lines = []398 lines.extend(get_lines(opt_parts, indent))399 lines.extend(get_lines(pos_parts, indent))400 lines = [prog] + lines401 402 # join lines into usage403 usage = '\n'.join(lines)404 405 usage = usage.removeprefix(prog)406 usage = f"{t.prog}{prog}{t.reset}{usage}"407 408 # prefix with 'usage:'409 return f'{t.usage}{prefix}{t.reset}{usage}\n\n'410 411 def _is_long_option(self, string):412 return len(string) > 2413 414 def _get_actions_usage_parts(self, actions, groups):415 """Get usage parts with split index for optionals/positionals.416 417 Returns (parts, pos_start) where pos_start is the index in parts418 where positionals begin.419 This preserves mutually exclusive group formatting across the420 optionals/positionals boundary (gh-75949).421 """422 actions = [action for action in actions if action.help is not SUPPRESS]423 # group actions by mutually exclusive groups424 action_groups = dict.fromkeys(actions)425 for group in groups:426 for action in group._group_actions:427 if action in action_groups:428 action_groups[action] = group429 # positional arguments keep their position430 positionals = []431 for action in actions:432 if not action.option_strings:433 group = action_groups.pop(action)434 if group:435 group_actions = [436 action2 for action2 in group._group_actions437 if action2.option_strings and438 action_groups.pop(action2, None)439 ] + [action]440 positionals.append((group.required, group_actions))441 else:442 positionals.append((None, [action]))443 # the remaining optional arguments are sorted by the position of444 # the first option in the group445 optionals = []446 for action in actions:447 if action.option_strings and action in action_groups:448 group = action_groups.pop(action)449 if group:450 group_actions = [action] + [451 action2 for action2 in group._group_actions452 if action2.option_strings and453 action_groups.pop(action2, None)454 ]455 optionals.append((group.required, group_actions))456 else:457 optionals.append((None, [action]))458 459 # collect all actions format strings460 parts = []461 t = self._theme462 pos_start = None463 for i, (required, group) in enumerate(optionals + positionals):464 start = len(parts)465 if i == len(optionals):466 pos_start = start467 in_group = len(group) > 1468 for action in group:469 # produce all arg strings470 if not action.option_strings:471 default = self._get_default_metavar_for_positional(action)472 part = self._format_args(action, default)473 # if it's in a group, strip the outer []474 if in_group:475 if part[0] == '[' and part[-1] == ']':476 part = part[1:-1]477 part = t.summary_action + part + t.reset478 479 # produce the first way to invoke the option in brackets480 else:481 option_string = action.option_strings[0]482 if self._is_long_option(option_string):483 option_color = t.summary_long_option484 else:485 option_color = t.summary_short_option486 487 # if the Optional doesn't take a value, format is:488 # -s or --long489 if action.nargs == 0:490 part = action.format_usage()491 part = f"{option_color}{part}{t.reset}"492 493 # if the Optional takes a value, format is:494 # -s ARGS or --long ARGS495 else:496 default = self._get_default_metavar_for_optional(action)497 args_string = self._format_args(action, default)498 part = (499 f"{option_color}{option_string} "500 f"{t.summary_label}{args_string}{t.reset}"501 )502 503 # make it look optional if it's not required or in a group504 if not (action.required or required or in_group):505 part = '[%s]' % part506 507 # add the action string to the list508 parts.append(part)509 510 if in_group:511 parts[start] = ('(' if required else '[') + parts[start]512 for i in range(start, len(parts) - 1):513 parts[i] += ' |'514 parts[-1] += ')' if required else ']'515 516 if pos_start is None:517 pos_start = len(parts)518 return parts, pos_start519 520 def _format_text(self, text):521 if '%(prog)' in text:522 text = text % dict(prog=self._prog)523 text_width = max(self._width - self._current_indent, 11)524 indent = ' ' * self._current_indent525 return self._fill_text(text, text_width, indent) + '\n\n'526 527 def _format_action(self, action):528 # determine the required width and the entry label529 help_position = min(self._action_max_length + 2,530 self._max_help_position)531 help_width = max(self._width - help_position, 11)532 action_width = help_position - self._current_indent - 2533 action_header = self._format_action_invocation(action)534 action_header_no_color = self._decolor(action_header)535 536 # no help; start on same line and add a final newline537 if not action.help:538 tup = self._current_indent, '', action_header539 action_header = '%*s%s\n' % tup540 541 # short action name; start on the same line and pad two spaces542 elif len(action_header_no_color) <= action_width:543 # calculate widths without color codes544 action_header_color = action_header545 tup = self._current_indent, '', action_width, action_header_no_color546 action_header = '%*s%-*s ' % tup547 # swap in the colored header548 action_header = action_header.replace(549 action_header_no_color, action_header_color550 )551 indent_first = 0552 553 # long action name; start on the next line554 else:555 tup = self._current_indent, '', action_header556 action_header = '%*s%s\n' % tup557 indent_first = help_position558 559 # collect the pieces of the action help560 parts = [action_header]561 562 # if there was help for the action, add lines of help text563 if action.help and action.help.strip():564 help_text = self._expand_help(action)565 if help_text:566 help_lines = self._split_lines(help_text, help_width)567 parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))568 for line in help_lines[1:]:569 parts.append('%*s%s\n' % (help_position, '', line))570 571 # or add a newline if the description doesn't end with one572 elif not action_header.endswith('\n'):573 parts.append('\n')574 575 # if there are any sub-actions, add their help as well576 for subaction in self._iter_indented_subactions(action):577 parts.append(self._format_action(subaction))578 579 # return a single string580 return self._join_parts(parts)581 582 def _format_action_invocation(self, action):583 t = self._theme584 585 if not action.option_strings:586 default = self._get_default_metavar_for_positional(action)587 return (588 t.action589 + ' '.join(self._metavar_formatter(action, default)(1))590 + t.reset591 )592 593 else:594 595 def color_option_strings(strings):596 parts = []597 for s in strings:598 if self._is_long_option(s):599 parts.append(f"{t.long_option}{s}{t.reset}")600 else:601 parts.append(f"{t.short_option}{s}{t.reset}")602 return parts603 604 # if the Optional doesn't take a value, format is:605 # -s, --long606 if action.nargs == 0:607 option_strings = color_option_strings(action.option_strings)608 return ', '.join(option_strings)609 610 # if the Optional takes a value, format is:611 # -s, --long ARGS612 else:613 default = self._get_default_metavar_for_optional(action)614 option_strings = color_option_strings(action.option_strings)615 args_string = (616 f"{t.label}{self._format_args(action, default)}{t.reset}"617 )618 return ', '.join(option_strings) + ' ' + args_string619 620 def _metavar_formatter(self, action, default_metavar):621 if action.metavar is not None:622 result = action.metavar623 elif action.choices is not None:624 result = '{%s}' % ','.join(map(str, action.choices))625 else:626 result = default_metavar627 628 def format(tuple_size):629 if isinstance(result, tuple):630 return result631 else:632 return (result, ) * tuple_size633 return format634 635 def _format_args(self, action, default_metavar):636 get_metavar = self._metavar_formatter(action, default_metavar)637 if action.nargs is None:638 result = '%s' % get_metavar(1)639 elif action.nargs == OPTIONAL:640 result = '[%s]' % get_metavar(1)641 elif action.nargs == ZERO_OR_MORE:642 metavar = get_metavar(1)643 if len(metavar) == 2:644 result = '[%s [%s ...]]' % metavar645 else:646 result = '[%s ...]' % metavar647 elif action.nargs == ONE_OR_MORE:648 result = '%s [%s ...]' % get_metavar(2)649 elif action.nargs == REMAINDER:650 result = '...'651 elif action.nargs == PARSER:652 result = '%s ...' % get_metavar(1)653 elif action.nargs == SUPPRESS:654 result = ''655 else:656 try:657 formats = ['%s' for _ in range(action.nargs)]658 except TypeError:659 raise ValueError("invalid nargs value") from None660 result = ' '.join(formats) % get_metavar(action.nargs)661 return result662 663 def _expand_help(self, action):664 help_string = self._get_help_string(action)665 if '%' not in help_string:666 return help_string667 params = dict(vars(action), prog=self._prog)668 for name in list(params):669 value = params[name]670 if value is SUPPRESS:671 del params[name]672 elif hasattr(value, '__name__'):673 params[name] = value.__name__674 if params.get('choices') is not None:675 params['choices'] = ', '.join(map(str, params['choices']))676 return help_string % params677 678 def _iter_indented_subactions(self, action):679 try:680 get_subactions = action._get_subactions681 except AttributeError:682 pass683 else:684 self._indent()685 yield from get_subactions()686 self._dedent()687 688 def _split_lines(self, text, width):689 text = self._whitespace_matcher.sub(' ', text).strip()690 # The textwrap module is used only for formatting help.691 # Delay its import for speeding up the common usage of argparse.692 import textwrap693 return textwrap.wrap(text, width)694 695 def _fill_text(self, text, width, indent):696 text = self._whitespace_matcher.sub(' ', text).strip()697 import textwrap698 return textwrap.fill(text, width,699 initial_indent=indent,700 subsequent_indent=indent)701 702 def _get_help_string(self, action):703 return action.help704 705 def _get_default_metavar_for_optional(self, action):706 return action.dest.upper()707 708 def _get_default_metavar_for_positional(self, action):709 return action.dest710 711 712class RawDescriptionHelpFormatter(HelpFormatter):713 """Help message formatter which retains any formatting in descriptions.714 715 Only the name of this class is considered a public API. All the methods716 provided by the class are considered an implementation detail.717 """718 719 def _fill_text(self, text, width, indent):720 return ''.join(indent + line for line in text.splitlines(keepends=True))721 722 723class RawTextHelpFormatter(RawDescriptionHelpFormatter):724 """Help message formatter which retains formatting of all help text.725 726 Only the name of this class is considered a public API. All the methods727 provided by the class are considered an implementation detail.728 """729 730 def _split_lines(self, text, width):731 return text.splitlines()732 733 734class ArgumentDefaultsHelpFormatter(HelpFormatter):735 """Help message formatter which adds default values to argument help.736 737 Only the name of this class is considered a public API. All the methods738 provided by the class are considered an implementation detail.739 """740 741 def _get_help_string(self, action):742 help = action.help743 if help is None:744 help = ''745 746 if (747 '%(default)' not in help748 and action.default is not SUPPRESS749 and not action.required750 ):751 defaulting_nargs = (OPTIONAL, ZERO_OR_MORE)752 if action.option_strings or action.nargs in defaulting_nargs:753 help += _(' (default: %(default)s)')754 return help755 756 757 758class MetavarTypeHelpFormatter(HelpFormatter):759 """Help message formatter which uses the argument 'type' as the default760 metavar value (instead of the argument 'dest')761 762 Only the name of this class is considered a public API. All the methods763 provided by the class are considered an implementation detail.764 """765 766 def _get_default_metavar_for_optional(self, action):767 return action.type.__name__768 769 def _get_default_metavar_for_positional(self, action):770 return action.type.__name__771 772 773# =====================774# Options and Arguments775# =====================776 777def _get_action_name(argument):778 if argument is None:779 return None780 elif argument.option_strings:781 return '/'.join(argument.option_strings)782 elif argument.metavar not in (None, SUPPRESS):783 metavar = argument.metavar784 if not isinstance(metavar, tuple):785 return metavar786 if argument.nargs == ZERO_OR_MORE and len(metavar) == 2:787 return '%s[, %s]' % metavar788 elif argument.nargs == ONE_OR_MORE:789 return '%s[, %s]' % metavar790 else:791 return ', '.join(metavar)792 elif argument.dest not in (None, SUPPRESS):793 return argument.dest794 elif argument.choices:795 return '{%s}' % ','.join(map(str, argument.choices))796 else:797 return None798 799 800class ArgumentError(Exception):801 """An error from creating or using an argument (optional or positional).802 803 The string value of this exception is the message, augmented with804 information about the argument that caused it.805 """806 807 def __init__(self, argument, message):808 self.argument_name = _get_action_name(argument)809 self.message = message810 811 def __str__(self):812 if self.argument_name is None:813 format = '%(message)s'814 else:815 format = _('argument %(argument_name)s: %(message)s')816 return format % dict(message=self.message,817 argument_name=self.argument_name)818 819 820class ArgumentTypeError(Exception):821 """An error from trying to convert a command line string to a type."""822 pass823 824 825# ==============826# Action classes827# ==============828 829class Action(_AttributeHolder):830 """Information about how to convert command line strings to Python objects.831 832 Action objects are used by an ArgumentParser to represent the information833 needed to parse a single argument from one or more strings from the834 command line. The keyword arguments to the Action constructor are also835 all attributes of Action instances.836 837 Keyword Arguments:838 839 - option_strings -- A list of command-line option strings which840 should be associated with this action.841 842 - dest -- The name of the attribute to hold the created object(s)843 844 - nargs -- The number of command-line arguments that should be845 consumed. By default, one argument will be consumed and a single846 value will be produced. Other values include:847 - N (an integer) consumes N arguments (and produces a list)848 - '?' consumes zero or one arguments849 - '*' consumes zero or more arguments (and produces a list)850 - '+' consumes one or more arguments (and produces a list)851 Note that the difference between the default and nargs=1 is that852 with the default, a single value will be produced, while with853 nargs=1, a list containing a single value will be produced.854 855 - const -- The value to be produced if the option is specified and the856 option uses an action that takes no values.857 858 - default -- The value to be produced if the option is not specified.859 860 - type -- A callable that accepts a single string argument, and861 returns the converted value. The standard Python types str, int,862 float, and complex are useful examples of such callables. If None,863 str is used.864 865 - choices -- A container of values that should be allowed. If not None,866 after a command-line argument has been converted to the appropriate867 type, an exception will be raised if it is not a member of this868 collection.869 870 - required -- True if the action must always be specified at the871 command line. This is only meaningful for optional command-line872 arguments.873 874 - help -- The help string describing the argument.875 876 - metavar -- The name to be used for the option's argument with the877 help string. If None, the 'dest' value will be used as the name.878 """879 880 def __init__(self,881 option_strings,882 dest,883 nargs=None,884 const=None,885 default=None,886 type=None,887 choices=None,888 required=False,889 help=None,890 metavar=None,891 deprecated=False):892 self.option_strings = option_strings893 self.dest = dest894 self.nargs = nargs895 self.const = const896 self.default = default897 self.type = type898 self.choices = choices899 self.required = required900 self.help = help901 self.metavar = metavar902 self.deprecated = deprecated903 904 def _get_kwargs(self):905 names = [906 'option_strings',907 'dest',908 'nargs',909 'const',910 'default',911 'type',912 'choices',913 'required',914 'help',915 'metavar',916 'deprecated',917 ]918 return [(name, getattr(self, name)) for name in names]919 920 def format_usage(self):921 return self.option_strings[0]922 923 def __call__(self, parser, namespace, values, option_string=None):924 raise NotImplementedError('.__call__() not defined')925 926 927class BooleanOptionalAction(Action):928 def __init__(self,929 option_strings,930 dest,931 default=None,932 required=False,933 help=None,934 deprecated=False):935 936 _option_strings = []937 for option_string in option_strings:938 _option_strings.append(option_string)939 940 if option_string.startswith('--'):941 if option_string.startswith('--no-'):942 raise ValueError(f'invalid option name {option_string!r} '943 f'for BooleanOptionalAction')944 option_string = '--no-' + option_string[2:]945 _option_strings.append(option_string)946 947 super().__init__(948 option_strings=_option_strings,949 dest=dest,950 nargs=0,951 default=default,952 required=required,953 help=help,954 deprecated=deprecated)955 956 957 def __call__(self, parser, namespace, values, option_string=None):958 if option_string in self.option_strings:959 setattr(namespace, self.dest, not option_string.startswith('--no-'))960 961 def format_usage(self):962 return ' | '.join(self.option_strings)963 964 965class _StoreAction(Action):966 967 def __init__(self,968 option_strings,969 dest,970 nargs=None,971 const=None,972 default=None,973 type=None,974 choices=None,975 required=False,976 help=None,977 metavar=None,978 deprecated=False):979 if nargs == 0:980 raise ValueError('nargs for store actions must be != 0; if you '981 'have nothing to store, actions such as store '982 'true or store const may be more appropriate')983 if const is not None and nargs != OPTIONAL:984 raise ValueError('nargs must be %r to supply const' % OPTIONAL)985 super(_StoreAction, self).__init__(986 option_strings=option_strings,987 dest=dest,988 nargs=nargs,989 const=const,990 default=default,991 type=type,992 choices=choices,993 required=required,994 help=help,995 metavar=metavar,996 deprecated=deprecated)997 998 def __call__(self, parser, namespace, values, option_string=None):999 setattr(namespace, self.dest, values)1000 1001 1002class _StoreConstAction(Action):1003 1004 def __init__(self,1005 option_strings,1006 dest,1007 const=None,1008 default=None,1009 required=False,1010 help=None,1011 metavar=None,1012 deprecated=False):1013 super(_StoreConstAction, self).__init__(1014 option_strings=option_strings,1015 dest=dest,1016 nargs=0,1017 const=const,1018 default=default,1019 required=required,1020 help=help,1021 deprecated=deprecated)1022 1023 def __call__(self, parser, namespace, values, option_string=None):1024 setattr(namespace, self.dest, self.const)1025 1026 1027class _StoreTrueAction(_StoreConstAction):1028 1029 def __init__(self,1030 option_strings,1031 dest,1032 default=False,1033 required=False,1034 help=None,1035 deprecated=False):1036 super(_StoreTrueAction, self).__init__(1037 option_strings=option_strings,1038 dest=dest,1039 const=True,1040 deprecated=deprecated,1041 required=required,1042 help=help,1043 default=default)1044 1045 1046class _StoreFalseAction(_StoreConstAction):1047 1048 def __init__(self,1049 option_strings,1050 dest,1051 default=True,1052 required=False,1053 help=None,1054 deprecated=False):1055 super(_StoreFalseAction, self).__init__(1056 option_strings=option_strings,1057 dest=dest,1058 const=False,1059 default=default,1060 required=required,1061 help=help,1062 deprecated=deprecated)1063 1064 1065class _AppendAction(Action):1066 1067 def __init__(self,1068 option_strings,1069 dest,1070 nargs=None,1071 const=None,1072 default=None,1073 type=None,1074 choices=None,1075 required=False,1076 help=None,1077 metavar=None,1078 deprecated=False):1079 if nargs == 0:1080 raise ValueError('nargs for append actions must be != 0; if arg '1081 'strings are not supplying the value to append, '1082 'the append const action may be more appropriate')1083 if const is not None and nargs != OPTIONAL:1084 raise ValueError('nargs must be %r to supply const' % OPTIONAL)1085 super(_AppendAction, self).__init__(1086 option_strings=option_strings,1087 dest=dest,1088 nargs=nargs,1089 const=const,1090 default=default,1091 type=type,1092 choices=choices,1093 required=required,1094 help=help,1095 metavar=metavar,1096 deprecated=deprecated)1097 1098 def __call__(self, parser, namespace, values, option_string=None):1099 items = getattr(namespace, self.dest, None)1100 items = _copy_items(items)1101 items.append(values)1102 setattr(namespace, self.dest, items)1103 1104 1105class _AppendConstAction(Action):1106 1107 def __init__(self,1108 option_strings,1109 dest,1110 const=None,1111 default=None,1112 required=False,1113 help=None,1114 metavar=None,1115 deprecated=False):1116 super(_AppendConstAction, self).__init__(1117 option_strings=option_strings,1118 dest=dest,1119 nargs=0,1120 const=const,1121 default=default,1122 required=required,1123 help=help,1124 metavar=metavar,1125 deprecated=deprecated)1126 1127 def __call__(self, parser, namespace, values, option_string=None):1128 items = getattr(namespace, self.dest, None)1129 items = _copy_items(items)1130 items.append(self.const)1131 setattr(namespace, self.dest, items)1132 1133 1134class _CountAction(Action):1135 1136 def __init__(self,1137 option_strings,1138 dest,1139 default=None,1140 required=False,1141 help=None,1142 deprecated=False):1143 super(_CountAction, self).__init__(1144 option_strings=option_strings,1145 dest=dest,1146 nargs=0,1147 default=default,1148 required=required,1149 help=help,1150 deprecated=deprecated)1151 1152 def __call__(self, parser, namespace, values, option_string=None):1153 count = getattr(namespace, self.dest, None)1154 if count is None:1155 count = 01156 setattr(namespace, self.dest, count + 1)1157 1158 1159class _HelpAction(Action):1160 1161 def __init__(self,1162 option_strings,1163 dest=SUPPRESS,1164 default=SUPPRESS,1165 help=None,1166 deprecated=False):1167 super(_HelpAction, self).__init__(1168 option_strings=option_strings,1169 dest=dest,1170 default=default,1171 nargs=0,1172 help=help,1173 deprecated=deprecated)1174 1175 def __call__(self, parser, namespace, values, option_string=None):1176 parser.print_help()1177 parser.exit()1178 1179 1180class _VersionAction(Action):1181 1182 def __init__(self,1183 option_strings,1184 version=None,1185 dest=SUPPRESS,1186 default=SUPPRESS,1187 help=None,1188 deprecated=False):1189 if help is None:1190 help = _("show program's version number and exit")1191 super(_VersionAction, self).__init__(1192 option_strings=option_strings,1193 dest=dest,1194 default=default,1195 nargs=0,1196 help=help)1197 self.version = version1198 1199 def __call__(self, parser, namespace, values, option_string=None):1200 version = self.version