gh-58032: Deprecate the argparse.FileType type converter (GH-124664)

This commit is contained in:
Serhiy Storchaka 2024-10-23 10:50:29 +03:00 committed by GitHub
parent c75ff2ef8e
commit 834ba5aaf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 83 additions and 45 deletions

View File

@ -4,16 +4,6 @@ Pending removal in future versions
The following APIs will be removed in the future,
although there is currently no date scheduled for their removal.
* :mod:`argparse`:
* Nesting argument groups and nesting mutually exclusive
groups are deprecated.
* Passing the undocumented keyword argument *prefix_chars* to
:meth:`~argparse.ArgumentParser.add_argument_group` is now
deprecated.
* :mod:`array`'s ``'u'`` format code (:gh:`57281`)
* :mod:`builtins`:
* ``bool(NotImplemented)``.
@ -43,6 +33,17 @@ although there is currently no date scheduled for their removal.
as a single positional argument.
(Contributed by Serhiy Storchaka in :gh:`109218`.)
* :mod:`argparse`:
* Nesting argument groups and nesting mutually exclusive
groups are deprecated.
* Passing the undocumented keyword argument *prefix_chars* to
:meth:`~argparse.ArgumentParser.add_argument_group` is now
deprecated.
* The :class:`argparse.FileType` type converter is deprecated.
* :mod:`array`'s ``'u'`` format code (:gh:`57281`)
* :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are
deprecated and replaced by :data:`calendar.JANUARY` and
:data:`calendar.FEBRUARY`.

View File

@ -865,16 +865,14 @@ See also :ref:`specifying-ambiguous-arguments`. The supported values are:
output files::
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
... default=sys.stdin)
>>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
... default=sys.stdout)
>>> parser.add_argument('infile', nargs='?')
>>> parser.add_argument('outfile', nargs='?')
>>> parser.parse_args(['input.txt', 'output.txt'])
Namespace(infile=<_io.TextIOWrapper name='input.txt' encoding='UTF-8'>,
outfile=<_io.TextIOWrapper name='output.txt' encoding='UTF-8'>)
Namespace(infile='input.txt', outfile='output.txt')
>>> parser.parse_args(['input.txt'])
Namespace(infile='input.txt', outfile=None)
>>> parser.parse_args([])
Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>,
outfile=<_io.TextIOWrapper name='<stdout>' encoding='UTF-8'>)
Namespace(infile=None, outfile=None)
.. index:: single: * (asterisk); in argparse module
@ -1033,7 +1031,6 @@ Common built-in types and functions can be used as type converters:
parser.add_argument('distance', type=float)
parser.add_argument('street', type=ascii)
parser.add_argument('code_point', type=ord)
parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1'))
parser.add_argument('datapath', type=pathlib.Path)
User defined functions can be used as well:
@ -1827,9 +1824,19 @@ FileType objects
>>> parser.parse_args(['-'])
Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>)
.. note::
If one argument uses *FileType* and then a subsequent argument fails,
an error is reported but the file is not automatically closed.
This can also clobber the output files.
In this case, it would be better to wait until after the parser has
run and then use the :keyword:`with`-statement to manage the files.
.. versionchanged:: 3.4
Added the *encodings* and *errors* parameters.
.. deprecated:: 3.14
Argument groups
^^^^^^^^^^^^^^^

View File

@ -464,6 +464,12 @@ Deprecated
as a single positional argument.
(Contributed by Serhiy Storchaka in :gh:`109218`.)
* :mod:`argparse`:
Deprecated the :class:`argparse.FileType` type converter.
Anything with resource management should be done downstream after the
arguments are parsed.
(Contributed by Serhiy Storchaka in :gh:`58032`.)
* :mod:`multiprocessing` and :mod:`concurrent.futures`:
The default start method (see :ref:`multiprocessing-start-methods`) changed
away from *fork* to *forkserver* on platforms where it was not already

View File

@ -18,11 +18,12 @@ command-line and writes the result to a file::
'integers', metavar='int', nargs='+', type=int,
help='an integer to be summed')
parser.add_argument(
'--log', default=sys.stdout, type=argparse.FileType('w'),
'--log',
help='the file where the sum should be written')
args = parser.parse_args()
args.log.write('%s' % sum(args.integers))
args.log.close()
with (open(args.log, 'w') if args.log is not None
else contextlib.nullcontext(sys.stdout)) as log:
log.write('%s' % sum(args.integers))
The module contains the following public classes:
@ -39,7 +40,8 @@ The module contains the following public classes:
- FileType -- A factory for defining types of files to be created. As the
example above shows, instances of FileType are typically passed as
the type= argument of add_argument() calls.
the type= argument of add_argument() calls. Deprecated since
Python 3.14.
- Action -- The base class for parser actions. Typically actions are
selected by passing strings like 'store_true' or 'append_const' to
@ -1252,7 +1254,7 @@ class _ExtendAction(_AppendAction):
# ==============
class FileType(object):
"""Factory for creating file object types
"""Deprecated factory for creating file object types
Instances of FileType are typically passed as type= arguments to the
ArgumentParser add_argument() method.
@ -1269,6 +1271,12 @@ class FileType(object):
"""
def __init__(self, mode='r', bufsize=-1, encoding=None, errors=None):
import warnings
warnings.warn(
"FileType is deprecated. Simply open files after parsing arguments.",
category=PendingDeprecationWarning,
stacklevel=2
)
self._mode = mode
self._bufsize = bufsize
self._encoding = encoding

View File

@ -1773,27 +1773,43 @@ class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
# Type conversion tests
# =====================
def FileType(*args, **kwargs):
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'FileType is deprecated',
PendingDeprecationWarning, __name__)
return argparse.FileType(*args, **kwargs)
class TestFileTypeDeprecation(TestCase):
def test(self):
with self.assertWarns(PendingDeprecationWarning) as cm:
argparse.FileType()
self.assertIn('FileType is deprecated', str(cm.warning))
self.assertEqual(cm.filename, __file__)
class TestFileTypeRepr(TestCase):
def test_r(self):
type = argparse.FileType('r')
type = FileType('r')
self.assertEqual("FileType('r')", repr(type))
def test_wb_1(self):
type = argparse.FileType('wb', 1)
type = FileType('wb', 1)
self.assertEqual("FileType('wb', 1)", repr(type))
def test_r_latin(self):
type = argparse.FileType('r', encoding='latin_1')
type = FileType('r', encoding='latin_1')
self.assertEqual("FileType('r', encoding='latin_1')", repr(type))
def test_w_big5_ignore(self):
type = argparse.FileType('w', encoding='big5', errors='ignore')
type = FileType('w', encoding='big5', errors='ignore')
self.assertEqual("FileType('w', encoding='big5', errors='ignore')",
repr(type))
def test_r_1_replace(self):
type = argparse.FileType('r', 1, errors='replace')
type = FileType('r', 1, errors='replace')
self.assertEqual("FileType('r', 1, errors='replace')", repr(type))
@ -1847,7 +1863,6 @@ class RFile(object):
text = text.decode('ascii')
return self.name == other.name == text
class TestFileTypeR(TempDirMixin, ParserTestCase):
"""Test the FileType option/argument type for reading files"""
@ -1860,8 +1875,8 @@ class TestFileTypeR(TempDirMixin, ParserTestCase):
self.create_readonly_file('readonly')
argument_signatures = [
Sig('-x', type=argparse.FileType()),
Sig('spam', type=argparse.FileType('r')),
Sig('-x', type=FileType()),
Sig('spam', type=FileType('r')),
]
failures = ['-x', '', 'non-existent-file.txt']
successes = [
@ -1881,7 +1896,7 @@ class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
file.close()
argument_signatures = [
Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
Sig('-c', type=FileType('r'), default='no-file.txt'),
]
# should provoke no such file error
failures = ['']
@ -1900,8 +1915,8 @@ class TestFileTypeRB(TempDirMixin, ParserTestCase):
file.write(file_name)
argument_signatures = [
Sig('-x', type=argparse.FileType('rb')),
Sig('spam', type=argparse.FileType('rb')),
Sig('-x', type=FileType('rb')),
Sig('spam', type=FileType('rb')),
]
failures = ['-x', '']
successes = [
@ -1939,8 +1954,8 @@ class TestFileTypeW(TempDirMixin, ParserTestCase):
self.create_writable_file('writable')
argument_signatures = [
Sig('-x', type=argparse.FileType('w')),
Sig('spam', type=argparse.FileType('w')),
Sig('-x', type=FileType('w')),
Sig('spam', type=FileType('w')),
]
failures = ['-x', '', 'readonly']
successes = [
@ -1962,8 +1977,8 @@ class TestFileTypeX(TempDirMixin, ParserTestCase):
self.create_writable_file('writable')
argument_signatures = [
Sig('-x', type=argparse.FileType('x')),
Sig('spam', type=argparse.FileType('x')),
Sig('-x', type=FileType('x')),
Sig('spam', type=FileType('x')),
]
failures = ['-x', '', 'readonly', 'writable']
successes = [
@ -1977,8 +1992,8 @@ class TestFileTypeWB(TempDirMixin, ParserTestCase):
"""Test the FileType option/argument type for writing binary files"""
argument_signatures = [
Sig('-x', type=argparse.FileType('wb')),
Sig('spam', type=argparse.FileType('wb')),
Sig('-x', type=FileType('wb')),
Sig('spam', type=FileType('wb')),
]
failures = ['-x', '']
successes = [
@ -1994,8 +2009,8 @@ class TestFileTypeXB(TestFileTypeX):
"Test the FileType option/argument type for writing new binary files only"
argument_signatures = [
Sig('-x', type=argparse.FileType('xb')),
Sig('spam', type=argparse.FileType('xb')),
Sig('-x', type=FileType('xb')),
Sig('spam', type=FileType('xb')),
]
successes = [
('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
@ -2007,7 +2022,7 @@ class TestFileTypeOpenArgs(TestCase):
"""Test that open (the builtin) is correctly called"""
def test_open_args(self):
FT = argparse.FileType
FT = FileType
cases = [
(FT('rb'), ('rb', -1, None, None)),
(FT('w', 1), ('w', 1, None, None)),
@ -2022,7 +2037,7 @@ class TestFileTypeOpenArgs(TestCase):
def test_invalid_file_type(self):
with self.assertRaises(ValueError):
argparse.FileType('b')('-test')
FileType('b')('-test')
class TestFileTypeMissingInitialization(TestCase):

View File

@ -0,0 +1 @@
Deprecate the :class:`argparse.FileType` type converter.