[Python-checkins] cpython (merge default -> default): merge heads

benjamin.peterson python-checkins at python.org
Sat Dec 15 21:46:32 CET 2012


http://hg.python.org/cpython/rev/3829339ee675
changeset:   80869:3829339ee675
parent:      80867:590caab5d6c7
parent:      80864:d5a0698a8354
user:        Benjamin Peterson <benjamin at python.org>
date:        Sat Dec 15 15:46:20 2012 -0500
summary:
  merge heads

files:
  Doc/library/argparse.rst  |  20 +++++++++-------
  Lib/argparse.py           |  16 ++++++++++--
  Lib/test/test_argparse.py |  32 +++++++++++++++++++++++++++
  Misc/ACKS                 |   1 +
  Misc/NEWS                 |   3 ++
  5 files changed, 60 insertions(+), 12 deletions(-)


diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst
--- a/Doc/library/argparse.rst
+++ b/Doc/library/argparse.rst
@@ -976,9 +976,9 @@
 ``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 @@
 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
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1140,11 +1140,17 @@
             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 @@
 
         # 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
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -14,6 +14,7 @@
 from io import StringIO
 
 from test import support
+from unittest import mock
 class StdIOBuffer(StringIO):
     pass
 
@@ -1421,6 +1422,19 @@
         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 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"""
 
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -768,6 +768,7 @@
 Graham Matthews
 Dieter Maurer
 Daniel May
+Lucas Maystre
 Arnaud Mazin
 Rebecca McCreary
 Kirk McDonald
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -167,6 +167,9 @@
 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.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list