mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
#11175: argparse.FileType now accepts encoding and errors arguments.
Patch by Lucas Maystre.
This commit is contained in:
parent
09bb89b8cf
commit
74d6c250e1
5 changed files with 60 additions and 12 deletions
|
@ -976,9 +976,9 @@ See the section on the default_ keyword argument for information on when the
|
||||||
``type`` argument is applied to default arguments.
|
``type`` argument is applied to default arguments.
|
||||||
|
|
||||||
To ease the use of various types of files, the argparse module provides the
|
To ease the use of various types of files, the argparse module provides the
|
||||||
factory FileType which takes the ``mode=`` and ``bufsize=`` arguments of the
|
factory FileType which takes the ``mode=``, ``bufsize=``, ``encoding=`` and
|
||||||
:func:`open` function. For example, ``FileType('w')`` can be used to create a
|
``errors=`` arguments of the :func:`open` function. For example,
|
||||||
writable file::
|
``FileType('w')`` can be used to create a writable file::
|
||||||
|
|
||||||
>>> parser = argparse.ArgumentParser()
|
>>> parser = argparse.ArgumentParser()
|
||||||
>>> parser.add_argument('bar', type=argparse.FileType('w'))
|
>>> parser.add_argument('bar', type=argparse.FileType('w'))
|
||||||
|
@ -1617,17 +1617,19 @@ Sub-commands
|
||||||
FileType objects
|
FileType objects
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. class:: FileType(mode='r', bufsize=None)
|
.. class:: FileType(mode='r', bufsize=-1, encoding=None, errors=None)
|
||||||
|
|
||||||
The :class:`FileType` factory creates objects that can be passed to the type
|
The :class:`FileType` factory creates objects that can be passed to the type
|
||||||
argument of :meth:`ArgumentParser.add_argument`. Arguments that have
|
argument of :meth:`ArgumentParser.add_argument`. Arguments that have
|
||||||
:class:`FileType` objects as their type will open command-line arguments as files
|
:class:`FileType` objects as their type will open command-line arguments as
|
||||||
with the requested modes and buffer sizes::
|
files with the requested modes, buffer sizes, encodings and error handling
|
||||||
|
(see the :func:`open` function for more details)::
|
||||||
|
|
||||||
>>> parser = argparse.ArgumentParser()
|
>>> parser = argparse.ArgumentParser()
|
||||||
>>> parser.add_argument('--output', type=argparse.FileType('wb', 0))
|
>>> parser.add_argument('--raw', type=argparse.FileType('wb', 0))
|
||||||
>>> parser.parse_args(['--output', 'out'])
|
>>> parser.add_argument('out', type=argparse.FileType('w', encoding='UTF-8'))
|
||||||
Namespace(output=<_io.BufferedWriter name='out'>)
|
>>> parser.parse_args(['--raw', 'raw.dat', 'file.txt'])
|
||||||
|
Namespace(out=<_io.TextIOWrapper name='file.txt' mode='w' encoding='UTF-8'>, raw=<_io.FileIO name='raw.dat' mode='wb'>)
|
||||||
|
|
||||||
FileType objects understand the pseudo-argument ``'-'`` and automatically
|
FileType objects understand the pseudo-argument ``'-'`` and automatically
|
||||||
convert this into ``sys.stdin`` for readable :class:`FileType` objects and
|
convert this into ``sys.stdin`` for readable :class:`FileType` objects and
|
||||||
|
|
|
@ -1140,11 +1140,17 @@ class FileType(object):
|
||||||
same values as the builtin open() function.
|
same values as the builtin open() function.
|
||||||
- bufsize -- The file's desired buffer size. Accepts the same values as
|
- bufsize -- The file's desired buffer size. Accepts the same values as
|
||||||
the builtin open() function.
|
the builtin open() function.
|
||||||
|
- encoding -- The file's encoding. Accepts the same values as the
|
||||||
|
the builtin open() function.
|
||||||
|
- errors -- A string indicating how encoding and decoding errors are to
|
||||||
|
be handled. Accepts the same value as the builtin open() function.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, mode='r', bufsize=-1):
|
def __init__(self, mode='r', bufsize=-1, encoding=None, errors=None):
|
||||||
self._mode = mode
|
self._mode = mode
|
||||||
self._bufsize = bufsize
|
self._bufsize = bufsize
|
||||||
|
self._encoding = encoding
|
||||||
|
self._errors = errors
|
||||||
|
|
||||||
def __call__(self, string):
|
def __call__(self, string):
|
||||||
# the special argument "-" means sys.std{in,out}
|
# the special argument "-" means sys.std{in,out}
|
||||||
|
@ -1159,14 +1165,18 @@ class FileType(object):
|
||||||
|
|
||||||
# all other arguments are used as file names
|
# all other arguments are used as file names
|
||||||
try:
|
try:
|
||||||
return open(string, self._mode, self._bufsize)
|
return open(string, self._mode, self._bufsize, self._encoding,
|
||||||
|
self._errors)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
message = _("can't open '%s': %s")
|
message = _("can't open '%s': %s")
|
||||||
raise ArgumentTypeError(message % (string, e))
|
raise ArgumentTypeError(message % (string, e))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
args = self._mode, self._bufsize
|
args = self._mode, self._bufsize
|
||||||
args_str = ', '.join(repr(arg) for arg in args if arg != -1)
|
kwargs = [('encoding', self._encoding), ('errors', self._errors)]
|
||||||
|
args_str = ', '.join([repr(arg) for arg in args if arg != -1] +
|
||||||
|
['%s=%r' % (kw, arg) for kw, arg in kwargs
|
||||||
|
if arg is not None])
|
||||||
return '%s(%s)' % (type(self).__name__, args_str)
|
return '%s(%s)' % (type(self).__name__, args_str)
|
||||||
|
|
||||||
# ===========================
|
# ===========================
|
||||||
|
|
|
@ -14,6 +14,7 @@ import argparse
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
|
from unittest import mock
|
||||||
class StdIOBuffer(StringIO):
|
class StdIOBuffer(StringIO):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1421,6 +1422,19 @@ class TestFileTypeRepr(TestCase):
|
||||||
type = argparse.FileType('wb', 1)
|
type = argparse.FileType('wb', 1)
|
||||||
self.assertEqual("FileType('wb', 1)", repr(type))
|
self.assertEqual("FileType('wb', 1)", repr(type))
|
||||||
|
|
||||||
|
def test_r_latin(self):
|
||||||
|
type = argparse.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')
|
||||||
|
self.assertEqual("FileType('w', encoding='big5', errors='ignore')",
|
||||||
|
repr(type))
|
||||||
|
|
||||||
|
def test_r_1_replace(self):
|
||||||
|
type = argparse.FileType('r', 1, errors='replace')
|
||||||
|
self.assertEqual("FileType('r', 1, errors='replace')", repr(type))
|
||||||
|
|
||||||
|
|
||||||
class RFile(object):
|
class RFile(object):
|
||||||
seen = {}
|
seen = {}
|
||||||
|
@ -1557,6 +1571,24 @@ class TestFileTypeWB(TempDirMixin, ParserTestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileTypeOpenArgs(TestCase):
|
||||||
|
"""Test that open (the builtin) is correctly called"""
|
||||||
|
|
||||||
|
def test_open_args(self):
|
||||||
|
FT = argparse.FileType
|
||||||
|
cases = [
|
||||||
|
(FT('rb'), ('rb', -1, None, None)),
|
||||||
|
(FT('w', 1), ('w', 1, None, None)),
|
||||||
|
(FT('w', errors='replace'), ('w', -1, None, 'replace')),
|
||||||
|
(FT('wb', encoding='big5'), ('wb', -1, 'big5', None)),
|
||||||
|
(FT('w', 0, 'l1', 'strict'), ('w', 0, 'l1', 'strict')),
|
||||||
|
]
|
||||||
|
with mock.patch('builtins.open') as m:
|
||||||
|
for type, args in cases:
|
||||||
|
type('foo')
|
||||||
|
m.assert_called_with('foo', *args)
|
||||||
|
|
||||||
|
|
||||||
class TestTypeCallable(ParserTestCase):
|
class TestTypeCallable(ParserTestCase):
|
||||||
"""Test some callables as option/argument types"""
|
"""Test some callables as option/argument types"""
|
||||||
|
|
||||||
|
|
|
@ -768,6 +768,7 @@ Laura Matson
|
||||||
Graham Matthews
|
Graham Matthews
|
||||||
Dieter Maurer
|
Dieter Maurer
|
||||||
Daniel May
|
Daniel May
|
||||||
|
Lucas Maystre
|
||||||
Arnaud Mazin
|
Arnaud Mazin
|
||||||
Rebecca McCreary
|
Rebecca McCreary
|
||||||
Kirk McDonald
|
Kirk McDonald
|
||||||
|
|
|
@ -167,6 +167,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #11175: argparse.FileType now accepts encoding and errors
|
||||||
|
arguments. Patch by Lucas Maystre.
|
||||||
|
|
||||||
- Issue #16488: epoll() objects now support the `with` statement. Patch
|
- Issue #16488: epoll() objects now support the `with` statement. Patch
|
||||||
by Serhiy Storchaka.
|
by Serhiy Storchaka.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue