mirror of
https://github.com/python/cpython.git
synced 2025-09-18 06:30:38 +00:00
gh-83648: Support deprecation of options, arguments and subcommands in argparse (GH-114086)
This commit is contained in:
parent
c32bae5290
commit
bb57ffdb38
5 changed files with 262 additions and 27 deletions
|
@ -843,7 +843,8 @@ class Action(_AttributeHolder):
|
|||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
metavar=None,
|
||||
deprecated=False):
|
||||
self.option_strings = option_strings
|
||||
self.dest = dest
|
||||
self.nargs = nargs
|
||||
|
@ -854,6 +855,7 @@ class Action(_AttributeHolder):
|
|||
self.required = required
|
||||
self.help = help
|
||||
self.metavar = metavar
|
||||
self.deprecated = deprecated
|
||||
|
||||
def _get_kwargs(self):
|
||||
names = [
|
||||
|
@ -867,6 +869,7 @@ class Action(_AttributeHolder):
|
|||
'required',
|
||||
'help',
|
||||
'metavar',
|
||||
'deprecated',
|
||||
]
|
||||
return [(name, getattr(self, name)) for name in names]
|
||||
|
||||
|
@ -889,7 +892,8 @@ class BooleanOptionalAction(Action):
|
|||
choices=_deprecated_default,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=_deprecated_default):
|
||||
metavar=_deprecated_default,
|
||||
deprecated=False):
|
||||
|
||||
_option_strings = []
|
||||
for option_string in option_strings:
|
||||
|
@ -927,7 +931,8 @@ class BooleanOptionalAction(Action):
|
|||
choices=choices,
|
||||
required=required,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
deprecated=deprecated)
|
||||
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
|
@ -950,7 +955,8 @@ class _StoreAction(Action):
|
|||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
metavar=None,
|
||||
deprecated=False):
|
||||
if nargs == 0:
|
||||
raise ValueError('nargs for store actions must be != 0; if you '
|
||||
'have nothing to store, actions such as store '
|
||||
|
@ -967,7 +973,8 @@ class _StoreAction(Action):
|
|||
choices=choices,
|
||||
required=required,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
deprecated=deprecated)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
setattr(namespace, self.dest, values)
|
||||
|
@ -982,7 +989,8 @@ class _StoreConstAction(Action):
|
|||
default=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
metavar=None,
|
||||
deprecated=False):
|
||||
super(_StoreConstAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
|
@ -990,7 +998,8 @@ class _StoreConstAction(Action):
|
|||
const=const,
|
||||
default=default,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
deprecated=deprecated)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
setattr(namespace, self.dest, self.const)
|
||||
|
@ -1003,14 +1012,16 @@ class _StoreTrueAction(_StoreConstAction):
|
|||
dest,
|
||||
default=False,
|
||||
required=False,
|
||||
help=None):
|
||||
help=None,
|
||||
deprecated=False):
|
||||
super(_StoreTrueAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
const=True,
|
||||
default=default,
|
||||
deprecated=deprecated,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
default=default)
|
||||
|
||||
|
||||
class _StoreFalseAction(_StoreConstAction):
|
||||
|
@ -1020,14 +1031,16 @@ class _StoreFalseAction(_StoreConstAction):
|
|||
dest,
|
||||
default=True,
|
||||
required=False,
|
||||
help=None):
|
||||
help=None,
|
||||
deprecated=False):
|
||||
super(_StoreFalseAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
const=False,
|
||||
default=default,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
deprecated=deprecated)
|
||||
|
||||
|
||||
class _AppendAction(Action):
|
||||
|
@ -1042,7 +1055,8 @@ class _AppendAction(Action):
|
|||
choices=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
metavar=None,
|
||||
deprecated=False):
|
||||
if nargs == 0:
|
||||
raise ValueError('nargs for append actions must be != 0; if arg '
|
||||
'strings are not supplying the value to append, '
|
||||
|
@ -1059,7 +1073,8 @@ class _AppendAction(Action):
|
|||
choices=choices,
|
||||
required=required,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
deprecated=deprecated)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
items = getattr(namespace, self.dest, None)
|
||||
|
@ -1077,7 +1092,8 @@ class _AppendConstAction(Action):
|
|||
default=None,
|
||||
required=False,
|
||||
help=None,
|
||||
metavar=None):
|
||||
metavar=None,
|
||||
deprecated=False):
|
||||
super(_AppendConstAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
|
@ -1086,7 +1102,8 @@ class _AppendConstAction(Action):
|
|||
default=default,
|
||||
required=required,
|
||||
help=help,
|
||||
metavar=metavar)
|
||||
metavar=metavar,
|
||||
deprecated=deprecated)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
items = getattr(namespace, self.dest, None)
|
||||
|
@ -1102,14 +1119,16 @@ class _CountAction(Action):
|
|||
dest,
|
||||
default=None,
|
||||
required=False,
|
||||
help=None):
|
||||
help=None,
|
||||
deprecated=False):
|
||||
super(_CountAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
nargs=0,
|
||||
default=default,
|
||||
required=required,
|
||||
help=help)
|
||||
help=help,
|
||||
deprecated=deprecated)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
count = getattr(namespace, self.dest, None)
|
||||
|
@ -1124,13 +1143,15 @@ class _HelpAction(Action):
|
|||
option_strings,
|
||||
dest=SUPPRESS,
|
||||
default=SUPPRESS,
|
||||
help=None):
|
||||
help=None,
|
||||
deprecated=False):
|
||||
super(_HelpAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
default=default,
|
||||
nargs=0,
|
||||
help=help)
|
||||
help=help,
|
||||
deprecated=deprecated)
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
parser.print_help()
|
||||
|
@ -1144,7 +1165,8 @@ class _VersionAction(Action):
|
|||
version=None,
|
||||
dest=SUPPRESS,
|
||||
default=SUPPRESS,
|
||||
help="show program's version number and exit"):
|
||||
help="show program's version number and exit",
|
||||
deprecated=False):
|
||||
super(_VersionAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
dest=dest,
|
||||
|
@ -1188,6 +1210,7 @@ class _SubParsersAction(Action):
|
|||
self._parser_class = parser_class
|
||||
self._name_parser_map = {}
|
||||
self._choices_actions = []
|
||||
self._deprecated = set()
|
||||
|
||||
super(_SubParsersAction, self).__init__(
|
||||
option_strings=option_strings,
|
||||
|
@ -1198,7 +1221,7 @@ class _SubParsersAction(Action):
|
|||
help=help,
|
||||
metavar=metavar)
|
||||
|
||||
def add_parser(self, name, **kwargs):
|
||||
def add_parser(self, name, *, deprecated=False, **kwargs):
|
||||
# set prog from the existing prefix
|
||||
if kwargs.get('prog') is None:
|
||||
kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
|
||||
|
@ -1226,6 +1249,10 @@ class _SubParsersAction(Action):
|
|||
for alias in aliases:
|
||||
self._name_parser_map[alias] = parser
|
||||
|
||||
if deprecated:
|
||||
self._deprecated.add(name)
|
||||
self._deprecated.update(aliases)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_subactions(self):
|
||||
|
@ -1241,13 +1268,17 @@ class _SubParsersAction(Action):
|
|||
|
||||
# select the parser
|
||||
try:
|
||||
parser = self._name_parser_map[parser_name]
|
||||
subparser = self._name_parser_map[parser_name]
|
||||
except KeyError:
|
||||
args = {'parser_name': parser_name,
|
||||
'choices': ', '.join(self._name_parser_map)}
|
||||
msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args
|
||||
raise ArgumentError(self, msg)
|
||||
|
||||
if parser_name in self._deprecated:
|
||||
parser._warning(_("command '%(parser_name)s' is deprecated") %
|
||||
{'parser_name': parser_name})
|
||||
|
||||
# parse all the remaining options into the namespace
|
||||
# store any unrecognized options on the object, so that the top
|
||||
# level parser can decide what to do with them
|
||||
|
@ -1255,7 +1286,7 @@ class _SubParsersAction(Action):
|
|||
# In case this subparser defines new defaults, we parse them
|
||||
# in a new namespace object and then update the original
|
||||
# namespace for the relevant parts.
|
||||
subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
|
||||
subnamespace, arg_strings = subparser.parse_known_args(arg_strings, None)
|
||||
for key, value in vars(subnamespace).items():
|
||||
setattr(namespace, key, value)
|
||||
|
||||
|
@ -1975,6 +2006,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
# converts arg strings to the appropriate and then takes the action
|
||||
seen_actions = set()
|
||||
seen_non_default_actions = set()
|
||||
warned = set()
|
||||
|
||||
def take_action(action, argument_strings, option_string=None):
|
||||
seen_actions.add(action)
|
||||
|
@ -2070,6 +2102,10 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
# the Optional's string args stopped
|
||||
assert action_tuples
|
||||
for action, args, option_string in action_tuples:
|
||||
if action.deprecated and option_string not in warned:
|
||||
self._warning(_("option '%(option)s' is deprecated") %
|
||||
{'option': option_string})
|
||||
warned.add(option_string)
|
||||
take_action(action, args, option_string)
|
||||
return stop
|
||||
|
||||
|
@ -2089,6 +2125,10 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
for action, arg_count in zip(positionals, arg_counts):
|
||||
args = arg_strings[start_index: start_index + arg_count]
|
||||
start_index += arg_count
|
||||
if args and action.deprecated and action.dest not in warned:
|
||||
self._warning(_("argument '%(argument_name)s' is deprecated") %
|
||||
{'argument_name': action.dest})
|
||||
warned.add(action.dest)
|
||||
take_action(action, args)
|
||||
|
||||
# slice off the Positionals that we just parsed and return the
|
||||
|
@ -2650,3 +2690,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
|||
self.print_usage(_sys.stderr)
|
||||
args = {'prog': self.prog, 'message': message}
|
||||
self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
|
||||
|
||||
def _warning(self, message):
|
||||
args = {'prog': self.prog, 'message': message}
|
||||
self._print_message(_('%(prog)s: warning: %(message)s\n') % args, _sys.stderr)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue