diff options
author | Benjamin Peterson <benjamin@python.org> | 2012-12-15 20:46:20 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2012-12-15 20:46:20 (GMT) |
commit | 3a31ecd8276397fed6703581a07a47ed15b28299 (patch) | |
tree | 68194410d40269288057190b2baef8ca9b24cfdd | |
parent | 6a020e8065f13737ff5f1380c132be097b4b02f9 (diff) | |
parent | 74d6c250e1ce0e5efc03575eaaa1b8cab66241eb (diff) | |
download | cpython-3a31ecd8276397fed6703581a07a47ed15b28299.zip cpython-3a31ecd8276397fed6703581a07a47ed15b28299.tar.gz cpython-3a31ecd8276397fed6703581a07a47ed15b28299.tar.bz2 |
merge heads
-rw-r--r-- | Doc/library/argparse.rst | 20 | ||||
-rw-r--r-- | Lib/argparse.py | 16 | ||||
-rw-r--r-- | Lib/test/test_argparse.py | 32 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
5 files changed, 60 insertions, 12 deletions
diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 9f6a1ea..584f4f7 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -976,9 +976,9 @@ See the section on the default_ keyword argument for information on when the ``type`` argument is applied to default arguments. 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 -:func:`open` function. For example, ``FileType('w')`` can be used to create a -writable file:: +factory FileType which takes the ``mode=``, ``bufsize=``, ``encoding=`` and +``errors=`` arguments of the :func:`open` function. For example, +``FileType('w')`` can be used to create a writable file:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('bar', type=argparse.FileType('w')) @@ -1617,17 +1617,19 @@ Sub-commands 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 argument of :meth:`ArgumentParser.add_argument`. Arguments that have - :class:`FileType` objects as their type will open command-line arguments as files - with the requested modes and buffer sizes:: + :class:`FileType` objects as their type will open command-line arguments as + files with the requested modes, buffer sizes, encodings and error handling + (see the :func:`open` function for more details):: >>> parser = argparse.ArgumentParser() - >>> parser.add_argument('--output', type=argparse.FileType('wb', 0)) - >>> parser.parse_args(['--output', 'out']) - Namespace(output=<_io.BufferedWriter name='out'>) + >>> parser.add_argument('--raw', type=argparse.FileType('wb', 0)) + >>> parser.add_argument('out', type=argparse.FileType('w', encoding='UTF-8')) + >>> 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 convert this into ``sys.stdin`` for readable :class:`FileType` objects and diff --git a/Lib/argparse.py b/Lib/argparse.py index 202f2cb..3b1a079 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1140,11 +1140,17 @@ class FileType(object): same values as the builtin open() function. - bufsize -- The file's desired buffer size. Accepts the same values as 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._bufsize = bufsize + self._encoding = encoding + self._errors = errors def __call__(self, string): # the special argument "-" means sys.std{in,out} @@ -1159,14 +1165,18 @@ class FileType(object): # all other arguments are used as file names try: - return open(string, self._mode, self._bufsize) + return open(string, self._mode, self._bufsize, self._encoding, + self._errors) except IOError as e: message = _("can't open '%s': %s") raise ArgumentTypeError(message % (string, e)) def __repr__(self): 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) # =========================== diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index c06c940..00cde2e 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -14,6 +14,7 @@ import argparse from io import StringIO from test import support +from unittest import mock class StdIOBuffer(StringIO): pass @@ -1421,6 +1422,19 @@ class TestFileTypeRepr(TestCase): type = argparse.FileType('wb', 1) 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): 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): """Test some callables as option/argument types""" @@ -768,6 +768,7 @@ Laura Matson Graham Matthews Dieter Maurer Daniel May +Lucas Maystre Arnaud Mazin Rebecca McCreary Kirk McDonald @@ -167,6 +167,9 @@ Core and Builtins 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 by Serhiy Storchaka. |