bpo-39467: allow user to deprecate CLI arguments
This commit is contained in:
parent
b9783d2e03
commit
7c1d2bedda
|
@ -698,6 +698,15 @@ The add_argument() method
|
||||||
* default_ - The value produced if the argument is absent from the
|
* default_ - The value produced if the argument is absent from the
|
||||||
command line.
|
command line.
|
||||||
|
|
||||||
|
* deprecated_ - Define if the argument is deprecated.
|
||||||
|
|
||||||
|
* deprecated_reason_ - Custome deprecation warning message to display if
|
||||||
|
the argument is deprecated.
|
||||||
|
|
||||||
|
* deprecated_pending_ - Define if the deprecation is pending. The argument
|
||||||
|
is obsolete and expected to be deprecated in the future, but is not
|
||||||
|
deprecated at the moment.
|
||||||
|
|
||||||
* type_ - The type to which the command-line argument should be converted.
|
* type_ - The type to which the command-line argument should be converted.
|
||||||
|
|
||||||
* choices_ - A container of the allowable values for the argument.
|
* choices_ - A container of the allowable values for the argument.
|
||||||
|
@ -1052,6 +1061,72 @@ command-line argument was not present::
|
||||||
Namespace(foo='1')
|
Namespace(foo='1')
|
||||||
|
|
||||||
|
|
||||||
|
deprecated
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
During projects lifecycle some arguments could be removed from the
|
||||||
|
command line, before removing these arguments definitively you would inform
|
||||||
|
your user that arguments are deprecated and will be removed.
|
||||||
|
The ``deprecated`` keyword argument of
|
||||||
|
:meth:`~ArgumentParser.add_argument`, whose value default to ``False``,
|
||||||
|
specifies if the argument is deprecated and will be removed
|
||||||
|
from the command-line available arguments in the future.
|
||||||
|
For arguments, if ``deprecated`` is ``True`` then a warning (``DeprecationWarning``) will be
|
||||||
|
emitted if the argument is given by user in the command line parameters::
|
||||||
|
|
||||||
|
>>> import argparse
|
||||||
|
>>> parser = argparse.ArgumentParser()
|
||||||
|
>>> parser.add_argument('bar', default=1)
|
||||||
|
>>> parser.add_argument('--foo', default=2, deprecated=True)
|
||||||
|
>>> parser.parse_args(['test'])
|
||||||
|
Namespace(bar='test', foo='2')
|
||||||
|
>>> parser.parse_args(['test', '--foo', '4'])
|
||||||
|
/home/cpython/Lib/argparse.py:1979: DeprecationWarning: Usage of parameter foo are deprecated
|
||||||
|
Namespace(bar='test', foo='4')
|
||||||
|
|
||||||
|
|
||||||
|
deprecated_reason
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Custome deprecation warning message to display if the argument is deprecated.
|
||||||
|
If not given then a standard message will be displayed.
|
||||||
|
The ``deprecated_reason`` keyword argument of
|
||||||
|
:meth:`~ArgumentParser.add_argument`, allow to define a custome message to
|
||||||
|
display if the argument is deprecated and given by user in the command line parameters::
|
||||||
|
|
||||||
|
>>> import argparse
|
||||||
|
>>> parser = argparse.ArgumentParser()
|
||||||
|
>>> parser.add_argument('bar', default=1)
|
||||||
|
>>> parser.add_argument('--foo', default=2, deprecated=True, deprecated_reason='my custom message')
|
||||||
|
>>> parser.parse_args(['test'])
|
||||||
|
Namespace(bar='test', foo='2')
|
||||||
|
>>> parser.parse_args(['test', '--foo', '4'])
|
||||||
|
/home/cpython/Lib/argparse.py:1979: DeprecationWarning: my custome message
|
||||||
|
Namespace(bar='test', foo='4')
|
||||||
|
|
||||||
|
deprecated_pending
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Define if the deprecation is pending. Could be used to define that an argument
|
||||||
|
is obsolete and expected to be deprecated in the future, but is not
|
||||||
|
deprecated at the moment.
|
||||||
|
The ``deprecated_pending`` keyword argument of
|
||||||
|
:meth:`~ArgumentParser.add_argument`, whose value default to ``False``,
|
||||||
|
specifies if the argument is obsolete and expected to be deprecated in the future.
|
||||||
|
For arguments, if ``deprecated_pending`` is ``True`` then a warning
|
||||||
|
(``PendingDeprecationWarning``) will be emitted if the argument is given by
|
||||||
|
user in the command line parameters::
|
||||||
|
|
||||||
|
>>> import argparse
|
||||||
|
>>> parser = argparse.ArgumentParser()
|
||||||
|
>>> parser.add_argument('bar', default=1)
|
||||||
|
>>> parser.add_argument('--foo', default=2, deprecated=True, deprecated_pending=True)
|
||||||
|
>>> parser.parse_args(['test'])
|
||||||
|
Namespace(bar='test', foo='2')
|
||||||
|
>>> parser.parse_args(['test', '--foo', '4'])
|
||||||
|
/home/cpython/Lib/argparse.py:1979: PendingDeprecationWarning: The argument foo is obsolete and expected to be deprecated in the future
|
||||||
|
Namespace(bar='test', foo='4')
|
||||||
|
|
||||||
type
|
type
|
||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ __all__ = [
|
||||||
import os as _os
|
import os as _os
|
||||||
import re as _re
|
import re as _re
|
||||||
import sys as _sys
|
import sys as _sys
|
||||||
|
import warnings
|
||||||
|
|
||||||
from gettext import gettext as _, ngettext
|
from gettext import gettext as _, ngettext
|
||||||
|
|
||||||
|
@ -817,6 +818,9 @@ class Action(_AttributeHolder):
|
||||||
nargs=None,
|
nargs=None,
|
||||||
const=None,
|
const=None,
|
||||||
default=None,
|
default=None,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
type=None,
|
type=None,
|
||||||
choices=None,
|
choices=None,
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -827,6 +831,14 @@ class Action(_AttributeHolder):
|
||||||
self.nargs = nargs
|
self.nargs = nargs
|
||||||
self.const = const
|
self.const = const
|
||||||
self.default = default
|
self.default = default
|
||||||
|
self.deprecated = deprecated
|
||||||
|
if not deprecated_reason:
|
||||||
|
deprecated_reason = f"Usage of parameter {dest} are deprecated"
|
||||||
|
if deprecated_pending:
|
||||||
|
deprecated_reason = f"The argument {dest} is obsolete and " \
|
||||||
|
"expected to be deprecated in the future"
|
||||||
|
self.deprecated_reason = deprecated_reason
|
||||||
|
self.deprecated_pending=deprecated_pending
|
||||||
self.type = type
|
self.type = type
|
||||||
self.choices = choices
|
self.choices = choices
|
||||||
self.required = required
|
self.required = required
|
||||||
|
@ -840,6 +852,9 @@ class Action(_AttributeHolder):
|
||||||
'nargs',
|
'nargs',
|
||||||
'const',
|
'const',
|
||||||
'default',
|
'default',
|
||||||
|
'deprecated',
|
||||||
|
'deprecated_reason',
|
||||||
|
'deprecated_pending',
|
||||||
'type',
|
'type',
|
||||||
'choices',
|
'choices',
|
||||||
'help',
|
'help',
|
||||||
|
@ -859,6 +874,9 @@ class BooleanOptionalAction(Action):
|
||||||
dest,
|
dest,
|
||||||
const=None,
|
const=None,
|
||||||
default=None,
|
default=None,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
type=None,
|
type=None,
|
||||||
choices=None,
|
choices=None,
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -881,6 +899,9 @@ class BooleanOptionalAction(Action):
|
||||||
dest=dest,
|
dest=dest,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
type=type,
|
type=type,
|
||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
|
@ -903,6 +924,9 @@ class _StoreAction(Action):
|
||||||
nargs=None,
|
nargs=None,
|
||||||
const=None,
|
const=None,
|
||||||
default=None,
|
default=None,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
type=None,
|
type=None,
|
||||||
choices=None,
|
choices=None,
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -920,6 +944,9 @@ class _StoreAction(Action):
|
||||||
nargs=nargs,
|
nargs=nargs,
|
||||||
const=const,
|
const=const,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
type=type,
|
type=type,
|
||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
|
@ -937,6 +964,9 @@ class _StoreConstAction(Action):
|
||||||
dest,
|
dest,
|
||||||
const,
|
const,
|
||||||
default=None,
|
default=None,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None):
|
||||||
|
@ -946,6 +976,9 @@ class _StoreConstAction(Action):
|
||||||
nargs=0,
|
nargs=0,
|
||||||
const=const,
|
const=const,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help)
|
||||||
|
|
||||||
|
@ -959,6 +992,9 @@ class _StoreTrueAction(_StoreConstAction):
|
||||||
option_strings,
|
option_strings,
|
||||||
dest,
|
dest,
|
||||||
default=False,
|
default=False,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
required=False,
|
required=False,
|
||||||
help=None):
|
help=None):
|
||||||
super(_StoreTrueAction, self).__init__(
|
super(_StoreTrueAction, self).__init__(
|
||||||
|
@ -966,6 +1002,9 @@ class _StoreTrueAction(_StoreConstAction):
|
||||||
dest=dest,
|
dest=dest,
|
||||||
const=True,
|
const=True,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help)
|
||||||
|
|
||||||
|
@ -976,6 +1015,9 @@ class _StoreFalseAction(_StoreConstAction):
|
||||||
option_strings,
|
option_strings,
|
||||||
dest,
|
dest,
|
||||||
default=True,
|
default=True,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
required=False,
|
required=False,
|
||||||
help=None):
|
help=None):
|
||||||
super(_StoreFalseAction, self).__init__(
|
super(_StoreFalseAction, self).__init__(
|
||||||
|
@ -983,6 +1025,9 @@ class _StoreFalseAction(_StoreConstAction):
|
||||||
dest=dest,
|
dest=dest,
|
||||||
const=False,
|
const=False,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help)
|
||||||
|
|
||||||
|
@ -995,6 +1040,9 @@ class _AppendAction(Action):
|
||||||
nargs=None,
|
nargs=None,
|
||||||
const=None,
|
const=None,
|
||||||
default=None,
|
default=None,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
type=None,
|
type=None,
|
||||||
choices=None,
|
choices=None,
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -1012,6 +1060,9 @@ class _AppendAction(Action):
|
||||||
nargs=nargs,
|
nargs=nargs,
|
||||||
const=const,
|
const=const,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
type=type,
|
type=type,
|
||||||
choices=choices,
|
choices=choices,
|
||||||
required=required,
|
required=required,
|
||||||
|
@ -1032,6 +1083,9 @@ class _AppendConstAction(Action):
|
||||||
dest,
|
dest,
|
||||||
const,
|
const,
|
||||||
default=None,
|
default=None,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
required=False,
|
required=False,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None):
|
||||||
|
@ -1041,6 +1095,9 @@ class _AppendConstAction(Action):
|
||||||
nargs=0,
|
nargs=0,
|
||||||
const=const,
|
const=const,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
required=required,
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar)
|
||||||
|
@ -1058,6 +1115,9 @@ class _CountAction(Action):
|
||||||
option_strings,
|
option_strings,
|
||||||
dest,
|
dest,
|
||||||
default=None,
|
default=None,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason=None,
|
||||||
|
deprecated_pending=False,
|
||||||
required=False,
|
required=False,
|
||||||
help=None):
|
help=None):
|
||||||
super(_CountAction, self).__init__(
|
super(_CountAction, self).__init__(
|
||||||
|
@ -1065,6 +1125,9 @@ class _CountAction(Action):
|
||||||
dest=dest,
|
dest=dest,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
default=default,
|
default=default,
|
||||||
|
deprecated=deprecated,
|
||||||
|
deprecated_reason=deprecated_reason,
|
||||||
|
deprecated_pending=deprecated_pending,
|
||||||
required=required,
|
required=required,
|
||||||
help=help)
|
help=help)
|
||||||
|
|
||||||
|
@ -1901,6 +1964,18 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
pattern = 'O'
|
pattern = 'O'
|
||||||
arg_string_pattern_parts.append(pattern)
|
arg_string_pattern_parts.append(pattern)
|
||||||
|
|
||||||
|
# check if the arg is deprecated
|
||||||
|
# and warn only if it's given in the CLI paramters
|
||||||
|
for action in self._actions:
|
||||||
|
if arg_string.replace("-", "") == action.dest:
|
||||||
|
if not action.deprecated:
|
||||||
|
continue
|
||||||
|
warnings.warn(
|
||||||
|
action.deprecated_reason,
|
||||||
|
PendingDeprecationWarning \
|
||||||
|
if action.deprecated_pending \
|
||||||
|
else DeprecationWarning)
|
||||||
|
|
||||||
# join the pieces together to form the pattern
|
# join the pieces together to form the pattern
|
||||||
arg_strings_pattern = ''.join(arg_string_pattern_parts)
|
arg_strings_pattern = ''.join(arg_string_pattern_parts)
|
||||||
|
|
||||||
|
|
|
@ -4660,12 +4660,17 @@ class TestStrings(TestCase):
|
||||||
type='int',
|
type='int',
|
||||||
nargs='+',
|
nargs='+',
|
||||||
default=42,
|
default=42,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason='foo bar',
|
||||||
|
deprecated_pending=False,
|
||||||
choices=[1, 2, 3],
|
choices=[1, 2, 3],
|
||||||
help='HELP',
|
help='HELP',
|
||||||
metavar='METAVAR')
|
metavar='METAVAR')
|
||||||
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, deprecated=False, "
|
||||||
|
"deprecated_reason='foo bar', "
|
||||||
|
"deprecated_pending=False, type='int', "
|
||||||
"choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
|
"choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
|
||||||
self.assertStringEqual(option, string)
|
self.assertStringEqual(option, string)
|
||||||
|
|
||||||
|
@ -4676,12 +4681,18 @@ class TestStrings(TestCase):
|
||||||
type=float,
|
type=float,
|
||||||
nargs='?',
|
nargs='?',
|
||||||
default=2.5,
|
default=2.5,
|
||||||
|
deprecated=False,
|
||||||
|
deprecated_reason='foo bar',
|
||||||
|
deprecated_pending=False,
|
||||||
choices=[0.5, 1.5, 2.5],
|
choices=[0.5, 1.5, 2.5],
|
||||||
help='H HH H',
|
help='H HH H',
|
||||||
metavar='MV MV MV')
|
metavar='MV MV MV')
|
||||||
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, deprecated=False, "
|
||||||
|
"deprecated_reason='foo bar', "
|
||||||
|
"deprecated_pending=False, "
|
||||||
|
"type=%r, choices=[0.5, 1.5, 2.5], "
|
||||||
"help='H HH H', metavar='MV MV MV')" % float)
|
"help='H HH H', metavar='MV MV MV')" % float)
|
||||||
self.assertStringEqual(argument, string)
|
self.assertStringEqual(argument, string)
|
||||||
|
|
||||||
|
@ -4874,6 +4885,39 @@ 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 raise warning
|
||||||
|
# =============================================
|
||||||
|
|
||||||
|
class TestTypeFunctionCallWithDeprecated(TestCase):
|
||||||
|
|
||||||
|
def test_type_function_call_with_deprecated(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--foo', deprecated=True, default='bar')
|
||||||
|
with support.captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo', 'spam'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertIn("DeprecationWarning", stderr)
|
||||||
|
|
||||||
|
def test_type_function_call_with_pending_deprecated(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--foo', deprecated=True,
|
||||||
|
deprecated_pending=True, default='bar')
|
||||||
|
with support.captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo', 'spam'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertIn("PendingDeprecationWarning", stderr)
|
||||||
|
|
||||||
|
def test_type_function_call_with_deprecated_custome_msg(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--foo', deprecated=True,
|
||||||
|
deprecated_reason="foo bar", default='bar')
|
||||||
|
with support.captured_stderr() as stderr:
|
||||||
|
parser.parse_args(['--foo', 'spam'])
|
||||||
|
stderr = stderr.getvalue()
|
||||||
|
self.assertIn("DeprecationWarning: foo bar", stderr)
|
||||||
|
|
||||||
# ==================================================================
|
# ==================================================================
|
||||||
# Check semantics regarding the default argument and type conversion
|
# Check semantics regarding the default argument and type conversion
|
||||||
# ==================================================================
|
# ==================================================================
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Allow to deprecate CLI arguments with argparse
|
Loading…
Reference in New Issue