mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +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
|
@ -777,6 +777,8 @@ The add_argument() method
|
||||||
* dest_ - The name of the attribute to be added to the object returned by
|
* dest_ - The name of the attribute to be added to the object returned by
|
||||||
:meth:`parse_args`.
|
:meth:`parse_args`.
|
||||||
|
|
||||||
|
* deprecated_ - Whether or not use of the argument is deprecated.
|
||||||
|
|
||||||
The following sections describe how each of these are used.
|
The following sections describe how each of these are used.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1439,6 +1441,34 @@ behavior::
|
||||||
>>> parser.parse_args('--foo XXX'.split())
|
>>> parser.parse_args('--foo XXX'.split())
|
||||||
Namespace(bar='XXX')
|
Namespace(bar='XXX')
|
||||||
|
|
||||||
|
|
||||||
|
.. _deprecated:
|
||||||
|
|
||||||
|
deprecated
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
During a project's lifetime, some arguments may need to be removed from the
|
||||||
|
command line. Before removing them, you should inform
|
||||||
|
your users that the arguments are deprecated and will be removed.
|
||||||
|
The ``deprecated`` keyword argument of
|
||||||
|
:meth:`~ArgumentParser.add_argument`, which defaults to ``False``,
|
||||||
|
specifies if the argument is deprecated and will be removed
|
||||||
|
in the future.
|
||||||
|
For arguments, if ``deprecated`` is ``True``, then a warning will be
|
||||||
|
printed to standard error when the argument is used::
|
||||||
|
|
||||||
|
>>> import argparse
|
||||||
|
>>> parser = argparse.ArgumentParser(prog='snake.py')
|
||||||
|
>>> parser.add_argument('--legs', default=0, type=int, deprecated=True)
|
||||||
|
>>> parser.parse_args([])
|
||||||
|
Namespace(legs=0)
|
||||||
|
>>> parser.parse_args(['--legs', '4']) # doctest: +SKIP
|
||||||
|
snake.py: warning: option '--legs' is deprecated
|
||||||
|
Namespace(legs=4)
|
||||||
|
|
||||||
|
.. versionchanged:: 3.13
|
||||||
|
|
||||||
|
|
||||||
Action classes
|
Action classes
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -1842,7 +1872,8 @@ Sub-commands
|
||||||
|
|
||||||
{foo,bar} additional help
|
{foo,bar} additional help
|
||||||
|
|
||||||
Furthermore, ``add_parser`` supports an additional ``aliases`` argument,
|
Furthermore, :meth:`~_SubParsersAction.add_parser` supports an additional
|
||||||
|
*aliases* argument,
|
||||||
which allows multiple strings to refer to the same subparser. This example,
|
which allows multiple strings to refer to the same subparser. This example,
|
||||||
like ``svn``, aliases ``co`` as a shorthand for ``checkout``::
|
like ``svn``, aliases ``co`` as a shorthand for ``checkout``::
|
||||||
|
|
||||||
|
@ -1853,6 +1884,20 @@ Sub-commands
|
||||||
>>> parser.parse_args(['co', 'bar'])
|
>>> parser.parse_args(['co', 'bar'])
|
||||||
Namespace(foo='bar')
|
Namespace(foo='bar')
|
||||||
|
|
||||||
|
:meth:`~_SubParsersAction.add_parser` supports also an additional
|
||||||
|
*deprecated* argument, which allows to deprecate the subparser.
|
||||||
|
|
||||||
|
>>> import argparse
|
||||||
|
>>> parser = argparse.ArgumentParser(prog='chicken.py')
|
||||||
|
>>> subparsers = parser.add_subparsers()
|
||||||
|
>>> run = subparsers.add_parser('run')
|
||||||
|
>>> fly = subparsers.add_parser('fly', deprecated=True)
|
||||||
|
>>> parser.parse_args(['fly']) # doctest: +SKIP
|
||||||
|
chicken.py: warning: command 'fly' is deprecated
|
||||||
|
Namespace()
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
One particularly effective way of handling sub-commands is to combine the use
|
One particularly effective way of handling sub-commands is to combine the use
|
||||||
of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so
|
of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so
|
||||||
that each subparser knows which Python function it should execute. For
|
that each subparser knows which Python function it should execute. For
|
||||||
|
|
|
@ -169,6 +169,15 @@ New Modules
|
||||||
Improved Modules
|
Improved Modules
|
||||||
================
|
================
|
||||||
|
|
||||||
|
argparse
|
||||||
|
--------
|
||||||
|
|
||||||
|
* Add parameter *deprecated* in methods
|
||||||
|
:meth:`~argparse.ArgumentParser.add_argument` and :meth:`!add_parser`
|
||||||
|
which allows to deprecate command-line options, positional arguments and
|
||||||
|
subcommands.
|
||||||
|
(Contributed by Serhiy Storchaka in :gh:`83648`).
|
||||||
|
|
||||||
array
|
array
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
@ -843,7 +843,8 @@ class Action(_AttributeHolder):
|
||||||
choices=None,
|
choices=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None,
|
||||||
|
deprecated=False):
|
||||||
self.option_strings = option_strings
|
self.option_strings = option_strings
|
||||||
self.dest = dest
|
self.dest = dest
|
||||||
self.nargs = nargs
|
self.nargs = nargs
|
||||||
|
@ -854,6 +855,7 @@ class Action(_AttributeHolder):
|
||||||
self.required = required
|
self.required = required
|
||||||
self.help = help
|
self.help = help
|
||||||
self.metavar = metavar
|
self.metavar = metavar
|
||||||
|
self.deprecated = deprecated
|
||||||
|
|
||||||
def _get_kwargs(self):
|
def _get_kwargs(self):
|
||||||
names = [
|
names = [
|
||||||
|
@ -867,6 +869,7 @@ class Action(_AttributeHolder):
|
||||||
'required',
|
'required',
|
||||||
'help',
|
'help',
|
||||||
'metavar',
|
'metavar',
|
||||||
|
'deprecated',
|
||||||
]
|
]
|
||||||
return [(name, getattr(self, name)) for name in names]
|
return [(name, getattr(self, name)) for name in names]
|
||||||
|
|
||||||
|
@ -889,7 +892,8 @@ class BooleanOptionalAction(Action):
|
||||||
choices=_deprecated_default,
|
choices=_deprecated_default,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=_deprecated_default):
|
metavar=_deprecated_default,
|
||||||
|
deprecated=False):
|
||||||
|
|
||||||
_option_strings = []
|
_option_strings = []
|
||||||
for option_string in option_strings:
|
for option_string in option_strings:
|
||||||
|
@ -927,7 +931,8 @@ class BooleanOptionalAction(Action):
|
||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
@ -950,7 +955,8 @@ class _StoreAction(Action):
|
||||||
choices=None,
|
choices=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None,
|
||||||
|
deprecated=False):
|
||||||
if nargs == 0:
|
if nargs == 0:
|
||||||
raise ValueError('nargs for store actions must be != 0; if you '
|
raise ValueError('nargs for store actions must be != 0; if you '
|
||||||
'have nothing to store, actions such as store '
|
'have nothing to store, actions such as store '
|
||||||
|
@ -967,7 +973,8 @@ class _StoreAction(Action):
|
||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
setattr(namespace, self.dest, values)
|
setattr(namespace, self.dest, values)
|
||||||
|
@ -982,7 +989,8 @@ class _StoreConstAction(Action):
|
||||||
default=None,
|
default=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None,
|
||||||
|
deprecated=False):
|
||||||
super(_StoreConstAction, self).__init__(
|
super(_StoreConstAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
|
@ -990,7 +998,8 @@ class _StoreConstAction(Action):
|
||||||
const=const,
|
const=const,
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
setattr(namespace, self.dest, self.const)
|
setattr(namespace, self.dest, self.const)
|
||||||
|
@ -1003,14 +1012,16 @@ class _StoreTrueAction(_StoreConstAction):
|
||||||
dest,
|
dest,
|
||||||
default=False,
|
default=False,
|
||||||
required=False,
|
required=False,
|
||||||
help=None):
|
help=None,
|
||||||
|
deprecated=False):
|
||||||
super(_StoreTrueAction, self).__init__(
|
super(_StoreTrueAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
const=True,
|
const=True,
|
||||||
default=default,
|
deprecated=deprecated,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help,
|
||||||
|
default=default)
|
||||||
|
|
||||||
|
|
||||||
class _StoreFalseAction(_StoreConstAction):
|
class _StoreFalseAction(_StoreConstAction):
|
||||||
|
@ -1020,14 +1031,16 @@ class _StoreFalseAction(_StoreConstAction):
|
||||||
dest,
|
dest,
|
||||||
default=True,
|
default=True,
|
||||||
required=False,
|
required=False,
|
||||||
help=None):
|
help=None,
|
||||||
|
deprecated=False):
|
||||||
super(_StoreFalseAction, self).__init__(
|
super(_StoreFalseAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
const=False,
|
const=False,
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
|
|
||||||
class _AppendAction(Action):
|
class _AppendAction(Action):
|
||||||
|
@ -1042,7 +1055,8 @@ class _AppendAction(Action):
|
||||||
choices=None,
|
choices=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None,
|
||||||
|
deprecated=False):
|
||||||
if nargs == 0:
|
if nargs == 0:
|
||||||
raise ValueError('nargs for append actions must be != 0; if arg '
|
raise ValueError('nargs for append actions must be != 0; if arg '
|
||||||
'strings are not supplying the value to append, '
|
'strings are not supplying the value to append, '
|
||||||
|
@ -1059,7 +1073,8 @@ class _AppendAction(Action):
|
||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
items = getattr(namespace, self.dest, None)
|
items = getattr(namespace, self.dest, None)
|
||||||
|
@ -1077,7 +1092,8 @@ class _AppendConstAction(Action):
|
||||||
default=None,
|
default=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None,
|
||||||
|
deprecated=False):
|
||||||
super(_AppendConstAction, self).__init__(
|
super(_AppendConstAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
|
@ -1086,7 +1102,8 @@ class _AppendConstAction(Action):
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
items = getattr(namespace, self.dest, None)
|
items = getattr(namespace, self.dest, None)
|
||||||
|
@ -1102,14 +1119,16 @@ class _CountAction(Action):
|
||||||
dest,
|
dest,
|
||||||
default=None,
|
default=None,
|
||||||
required=False,
|
required=False,
|
||||||
help=None):
|
help=None,
|
||||||
|
deprecated=False):
|
||||||
super(_CountAction, self).__init__(
|
super(_CountAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
default=default,
|
default=default,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
count = getattr(namespace, self.dest, None)
|
count = getattr(namespace, self.dest, None)
|
||||||
|
@ -1124,13 +1143,15 @@ class _HelpAction(Action):
|
||||||
option_strings,
|
option_strings,
|
||||||
dest=SUPPRESS,
|
dest=SUPPRESS,
|
||||||
default=SUPPRESS,
|
default=SUPPRESS,
|
||||||
help=None):
|
help=None,
|
||||||
|
deprecated=False):
|
||||||
super(_HelpAction, self).__init__(
|
super(_HelpAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
default=default,
|
default=default,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
help=help)
|
help=help,
|
||||||
|
deprecated=deprecated)
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
|
@ -1144,7 +1165,8 @@ class _VersionAction(Action):
|
||||||
version=None,
|
version=None,
|
||||||
dest=SUPPRESS,
|
dest=SUPPRESS,
|
||||||
default=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__(
|
super(_VersionAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
dest=dest,
|
dest=dest,
|
||||||
|
@ -1188,6 +1210,7 @@ class _SubParsersAction(Action):
|
||||||
self._parser_class = parser_class
|
self._parser_class = parser_class
|
||||||
self._name_parser_map = {}
|
self._name_parser_map = {}
|
||||||
self._choices_actions = []
|
self._choices_actions = []
|
||||||
|
self._deprecated = set()
|
||||||
|
|
||||||
super(_SubParsersAction, self).__init__(
|
super(_SubParsersAction, self).__init__(
|
||||||
option_strings=option_strings,
|
option_strings=option_strings,
|
||||||
|
@ -1198,7 +1221,7 @@ class _SubParsersAction(Action):
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar)
|
||||||
|
|
||||||
def add_parser(self, name, **kwargs):
|
def add_parser(self, name, *, deprecated=False, **kwargs):
|
||||||
# set prog from the existing prefix
|
# set prog from the existing prefix
|
||||||
if kwargs.get('prog') is None:
|
if kwargs.get('prog') is None:
|
||||||
kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
|
kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
|
||||||
|
@ -1226,6 +1249,10 @@ class _SubParsersAction(Action):
|
||||||
for alias in aliases:
|
for alias in aliases:
|
||||||
self._name_parser_map[alias] = parser
|
self._name_parser_map[alias] = parser
|
||||||
|
|
||||||
|
if deprecated:
|
||||||
|
self._deprecated.add(name)
|
||||||
|
self._deprecated.update(aliases)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def _get_subactions(self):
|
def _get_subactions(self):
|
||||||
|
@ -1241,13 +1268,17 @@ class _SubParsersAction(Action):
|
||||||
|
|
||||||
# select the parser
|
# select the parser
|
||||||
try:
|
try:
|
||||||
parser = self._name_parser_map[parser_name]
|
subparser = self._name_parser_map[parser_name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
args = {'parser_name': parser_name,
|
args = {'parser_name': parser_name,
|
||||||
'choices': ', '.join(self._name_parser_map)}
|
'choices': ', '.join(self._name_parser_map)}
|
||||||
msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args
|
msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args
|
||||||
raise ArgumentError(self, msg)
|
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
|
# parse all the remaining options into the namespace
|
||||||
# store any unrecognized options on the object, so that the top
|
# store any unrecognized options on the object, so that the top
|
||||||
# level parser can decide what to do with them
|
# 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 case this subparser defines new defaults, we parse them
|
||||||
# in a new namespace object and then update the original
|
# in a new namespace object and then update the original
|
||||||
# namespace for the relevant parts.
|
# 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():
|
for key, value in vars(subnamespace).items():
|
||||||
setattr(namespace, key, value)
|
setattr(namespace, key, value)
|
||||||
|
|
||||||
|
@ -1975,6 +2006,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
# converts arg strings to the appropriate and then takes the action
|
# converts arg strings to the appropriate and then takes the action
|
||||||
seen_actions = set()
|
seen_actions = set()
|
||||||
seen_non_default_actions = set()
|
seen_non_default_actions = set()
|
||||||
|
warned = set()
|
||||||
|
|
||||||
def take_action(action, argument_strings, option_string=None):
|
def take_action(action, argument_strings, option_string=None):
|
||||||
seen_actions.add(action)
|
seen_actions.add(action)
|
||||||
|
@ -2070,6 +2102,10 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
# the Optional's string args stopped
|
# the Optional's string args stopped
|
||||||
assert action_tuples
|
assert action_tuples
|
||||||
for action, args, option_string in 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)
|
take_action(action, args, option_string)
|
||||||
return stop
|
return stop
|
||||||
|
|
||||||
|
@ -2089,6 +2125,10 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
for action, arg_count in zip(positionals, arg_counts):
|
for action, arg_count in zip(positionals, arg_counts):
|
||||||
args = arg_strings[start_index: start_index + arg_count]
|
args = arg_strings[start_index: start_index + arg_count]
|
||||||
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)
|
take_action(action, args)
|
||||||
|
|
||||||
# slice off the Positionals that we just parsed and return the
|
# slice off the Positionals that we just parsed and return the
|
||||||
|
@ -2650,3 +2690,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
self.print_usage(_sys.stderr)
|
self.print_usage(_sys.stderr)
|
||||||
args = {'prog': self.prog, 'message': message}
|
args = {'prog': self.prog, 'message': message}
|
||||||
self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
|
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)
|
||||||
|
|
|
@ -5099,7 +5099,8 @@ class TestStrings(TestCase):
|
||||||
string = (
|
string = (
|
||||||
"Action(option_strings=['--foo', '-a', '-b'], dest='b', "
|
"Action(option_strings=['--foo', '-a', '-b'], dest='b', "
|
||||||
"nargs='+', const=None, default=42, type='int', "
|
"nargs='+', const=None, default=42, type='int', "
|
||||||
"choices=[1, 2, 3], required=False, help='HELP', metavar='METAVAR')")
|
"choices=[1, 2, 3], required=False, help='HELP', "
|
||||||
|
"metavar='METAVAR', deprecated=False)")
|
||||||
self.assertStringEqual(option, string)
|
self.assertStringEqual(option, string)
|
||||||
|
|
||||||
def test_argument(self):
|
def test_argument(self):
|
||||||
|
@ -5116,7 +5117,8 @@ class TestStrings(TestCase):
|
||||||
string = (
|
string = (
|
||||||
"Action(option_strings=[], dest='x', nargs='?', "
|
"Action(option_strings=[], dest='x', nargs='?', "
|
||||||
"const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
|
"const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
|
||||||
"required=True, help='H HH H', metavar='MV MV MV')" % float)
|
"required=True, help='H HH H', metavar='MV MV MV', "
|
||||||
|
"deprecated=False)" % float)
|
||||||
self.assertStringEqual(argument, string)
|
self.assertStringEqual(argument, string)
|
||||||
|
|
||||||
def test_namespace(self):
|
def test_namespace(self):
|
||||||
|
@ -5308,6 +5310,139 @@ class TestTypeFunctionCallOnlyOnce(TestCase):
|
||||||
args = parser.parse_args('--foo spam!'.split())
|
args = parser.parse_args('--foo spam!'.split())
|
||||||
self.assertEqual(NS(foo='foo_converted'), args)
|
self.assertEqual(NS(foo='foo_converted'), args)
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================
|
||||||
|
# Check that deprecated arguments output warning
|
||||||
|
# ==============================================
|
||||||
|
|
||||||
|
class TestDeprecatedArguments(TestCase):
|
||||||
|
|
||||||
|
def test_deprecated_option(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-f', '--foo', deprecated=True)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo', 'spam'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '--foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['-f', 'spam'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '-f' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo', 'spam', '-f', 'ham'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '--foo' is deprecated")
|
||||||
|
self.assertRegex(stderr, "warning: option '-f' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 2)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo', 'spam', '--foo', 'ham'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '--foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
def test_deprecated_boolean_option(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-f', '--foo', action=argparse.BooleanOptionalAction, deprecated=True)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '--foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['-f'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '-f' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--no-foo'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '--no-foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo', '--no-foo'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: option '--foo' is deprecated")
|
||||||
|
self.assertRegex(stderr, "warning: option '--no-foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 2)
|
||||||
|
|
||||||
|
def test_deprecated_arguments(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('foo', nargs='?', deprecated=True)
|
||||||
|
parser.add_argument('bar', nargs='?', deprecated=True)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args([])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 0)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['spam'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: argument 'foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['spam', 'ham'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: argument 'foo' is deprecated")
|
||||||
|
self.assertRegex(stderr, "warning: argument 'bar' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 2)
|
||||||
|
|
||||||
|
def test_deprecated_varargument(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('foo', nargs='*', deprecated=True)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args([])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 0)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['spam'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: argument 'foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['spam', 'ham'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: argument 'foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
def test_deprecated_subparser(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
subparsers = parser.add_subparsers()
|
||||||
|
subparsers.add_parser('foo', aliases=['baz'], deprecated=True)
|
||||||
|
subparsers.add_parser('bar')
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['bar'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 0)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['foo'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: command 'foo' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
with captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['baz'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertRegex(stderr, "warning: command 'baz' is deprecated")
|
||||||
|
self.assertEqual(stderr.count('is deprecated'), 1)
|
||||||
|
|
||||||
|
|
||||||
# ==================================================================
|
# ==================================================================
|
||||||
# Check semantics regarding the default argument and type conversion
|
# Check semantics regarding the default argument and type conversion
|
||||||
# ==================================================================
|
# ==================================================================
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Support deprecation of options, positional arguments and subcommands in
|
||||||
|
:mod:`argparse`.
|
Loading…
Add table
Add a link
Reference in a new issue