]> granicus.if.org Git - python/commitdiff
Close #11022: TextIOWrapper doesn't call locale.setlocale() anymore
authorVictor Stinner <victor.stinner@gmail.com>
Tue, 5 Jun 2012 11:43:22 +0000 (13:43 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Tue, 5 Jun 2012 11:43:22 +0000 (13:43 +0200)
open() and io.TextIOWrapper are now calling locale.getpreferredencoding(False)
instead of locale.getpreferredencoding() in text mode if the encoding is not
specified. Don't change temporary the locale encoding using locale.setlocale(),
use the current locale encoding instead of the user preferred encoding.

Explain also in open() documentation that locale.getpreferredencoding(False) is
called if the encoding is not specified.

Doc/library/functions.rst
Doc/library/io.rst
Lib/_pyio.py
Lib/test/test_builtin.py
Lib/test/test_io.py
Misc/NEWS
Modules/_io/_iomodule.c
Modules/_io/textio.c

index d5ac23eb1fd08c815dd9f260d2b67e1d612d22d4..5254299fc626ae0196e794cad8dd521c66a174ef 100644 (file)
@@ -800,9 +800,10 @@ are always available.  They are listed here in alphabetical order.
    already exists), ``'x'`` for exclusive creation and ``'a'`` for appending
    (which on *some* Unix systems, means that *all* writes append to the end of
    the file regardless of the current seek position).  In text mode, if
-   *encoding* is not specified the encoding used is platform dependent. (For
-   reading and writing raw bytes use binary mode and leave *encoding*
-   unspecified.)  The available modes are:
+   *encoding* is not specified the encoding used is platform dependent:
+   ``locale.getpreferredencoding(False)`` is called to get the current locale
+   encoding. (For reading and writing raw bytes use binary mode and leave
+   *encoding* unspecified.)  The available modes are:
 
    ========= ===============================================================
    Character Meaning
index 4d564bb3f9011d3cc95f0ca642bfd8c92252d9c4..e30a016d9605ef1c457fb75363500a7dfbabbcb4 100644 (file)
@@ -752,7 +752,7 @@ Text I/O
    It inherits :class:`TextIOBase`.
 
    *encoding* gives the name of the encoding that the stream will be decoded or
-   encoded with.  It defaults to :func:`locale.getpreferredencoding`.
+   encoded with.  It defaults to ``locale.getpreferredencoding(False)``.
 
    *errors* is an optional string that specifies how encoding and decoding
    errors are to be handled.  Pass ``'strict'`` to raise a :exc:`ValueError`
@@ -784,6 +784,12 @@ Text I/O
    .. versionchanged:: 3.3
       The *write_through* argument has been added.
 
+   .. versionchanged:: 3.3
+      The default *encoding* is now ``locale.getpreferredencoding(False)``
+      instead of ``locale.getpreferredencoding()``. Don't change temporary the
+      locale encoding using :func:`locale.setlocale`, use the current locale
+      encoding instead of the user preferred encoding.
+
    :class:`TextIOWrapper` provides one attribute in addition to those of
    :class:`TextIOBase` and its parents:
 
index f66290fa51aa5345efbbeca908fbe1b70ca6336c..b684a9f7cb159c919a3fa24f1791cfb4bb4c1d14 100644 (file)
@@ -1448,7 +1448,7 @@ class TextIOWrapper(TextIOBase):
     r"""Character and line based layer over a BufferedIOBase object, buffer.
 
     encoding gives the name of the encoding that the stream will be
-    decoded or encoded with. It defaults to locale.getpreferredencoding.
+    decoded or encoded with. It defaults to locale.getpreferredencoding(False).
 
     errors determines the strictness of encoding and decoding (see the
     codecs.register) and defaults to "strict".
@@ -1487,7 +1487,7 @@ class TextIOWrapper(TextIOBase):
                     # Importing locale may fail if Python is being built
                     encoding = "ascii"
                 else:
-                    encoding = locale.getpreferredencoding()
+                    encoding = locale.getpreferredencoding(False)
 
         if not isinstance(encoding, str):
             raise ValueError("invalid encoding: %r" % encoding)
index dfe64bf09c335b6dabc9ad5c8dcd89df8b1f4568..d0d17c76dfd9dc78b6994f492188d6ab160154c8 100644 (file)
@@ -1,20 +1,21 @@
 # Python test set -- built-in functions
 
-import platform
-import unittest
-import sys
-import warnings
+import ast
+import builtins
 import collections
 import io
+import locale
 import os
-import ast
-import types
-import builtins
+import pickle
+import platform
 import random
+import sys
 import traceback
-from test.support import TESTFN, unlink,  run_unittest, check_warnings
+import types
+import unittest
+import warnings
 from operator import neg
-import pickle
+from test.support import TESTFN, unlink,  run_unittest, check_warnings
 try:
     import pty, signal
 except ImportError:
@@ -961,6 +962,27 @@ class BuiltinTest(unittest.TestCase):
             fp.close()
         unlink(TESTFN)
 
+    def test_open_default_encoding(self):
+        old_environ = dict(os.environ)
+        try:
+            # try to get a user preferred encoding different than the current
+            # locale encoding to check that open() uses the current locale
+            # encoding and not the user preferred encoding
+            for key in ('LC_ALL', 'LANG', 'LC_CTYPE'):
+                if key in os.environ:
+                    del os.environ[key]
+
+            self.write_testfile()
+            current_locale_encoding = locale.getpreferredencoding(False)
+            fp = open(TESTFN, 'w')
+            try:
+                self.assertEqual(fp.encoding, current_locale_encoding)
+            finally:
+                fp.close()
+        finally:
+            os.environ.clear()
+            os.environ.update(old_environ)
+
     def test_ord(self):
         self.assertEqual(ord(' '), 32)
         self.assertEqual(ord('A'), 65)
index f5bb732ad9c4d8cfda466c9a7556d4667a2265fe..1951a06b9b6ec6aa4486e23f1831bf3a300fa606 100644 (file)
 # test both implementations. This file has lots of examples.
 ################################################################################
 
+import abc
+import array
+import errno
+import locale
 import os
+import pickle
+import random
+import signal
 import sys
 import time
-import array
-import random
 import unittest
-import weakref
-import abc
-import signal
-import errno
 import warnings
-import pickle
-from itertools import cycle, count
+import weakref
 from collections import deque
+from itertools import cycle, count
 from test import support
 
 import codecs
@@ -1881,6 +1882,24 @@ class TextIOWrapperTest(unittest.TestCase):
         t.write("A\rB")
         self.assertEqual(r.getvalue(), b"XY\nZA\rB")
 
+    def test_default_encoding(self):
+        old_environ = dict(os.environ)
+        try:
+            # try to get a user preferred encoding different than the current
+            # locale encoding to check that TextIOWrapper() uses the current
+            # locale encoding and not the user preferred encoding
+            for key in ('LC_ALL', 'LANG', 'LC_CTYPE'):
+                if key in os.environ:
+                    del os.environ[key]
+
+            current_locale_encoding = locale.getpreferredencoding(False)
+            b = self.BytesIO()
+            t = self.TextIOWrapper(b)
+            self.assertEqual(t.encoding, current_locale_encoding)
+        finally:
+            os.environ.clear()
+            os.environ.update(old_environ)
+
     def test_encoding(self):
         # Check the encoding attribute is always set, and valid
         b = self.BytesIO()
index b8d09285710f00af19fd64942ee4da29c7c2a2c9..332e4084db4e73c98ba296f4b3070527b184869f 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,12 @@ What's New in Python 3.3.0 Beta 1?
 Core and Builtins
 -----------------
 
+- Issue #11022: open() and io.TextIOWrapper are now calling
+  locale.getpreferredencoding(False) instead of locale.getpreferredencoding()
+  in text mode if the encoding is not specified. Don't change temporary the
+  locale encoding using locale.setlocale(), use the current locale encoding
+  instead of the user preferred encoding.
+
 - Issue #14673: Add Eric Snow's sys.implementation implementation.
 
 Library
index 31eea3cd03ea6857eac55d014647fef4e32858b4..61b9f529002bab5bc1c0e13e5a329057ead24c89 100644 (file)
@@ -112,8 +112,9 @@ PyDoc_STRVAR(open_doc,
 "'a' for appending (which on some Unix systems, means that all writes\n"
 "append to the end of the file regardless of the current seek position).\n"
 "In text mode, if encoding is not specified the encoding used is platform\n"
-"dependent. (For reading and writing raw bytes use binary mode and leave\n"
-"encoding unspecified.) The available modes are:\n"
+"dependent: locale.getpreferredencoding(False) is called to get the\n"
+"current locale encoding. (For reading and writing raw bytes use binary\n"
+"mode and leave encoding unspecified.) The available modes are:\n"
 "\n"
 "========= ===============================================================\n"
 "Character Meaning\n"
index ae105e53cc536451ca99232cac9cd1eda07657f8..287f165cb05cdf3cb37f2dafbb0b060dfc74dfc7 100644 (file)
@@ -630,7 +630,7 @@ PyDoc_STRVAR(textiowrapper_doc,
     "Character and line based layer over a BufferedIOBase object, buffer.\n"
     "\n"
     "encoding gives the name of the encoding that the stream will be\n"
-    "decoded or encoded with. It defaults to locale.getpreferredencoding.\n"
+    "decoded or encoded with. It defaults to locale.getpreferredencoding(False).\n"
     "\n"
     "errors determines the strictness of encoding and decoding (see the\n"
     "codecs.register) and defaults to \"strict\".\n"
@@ -898,7 +898,7 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
         else {
           use_locale:
             self->encoding = _PyObject_CallMethodId(
-                state->locale_module, &PyId_getpreferredencoding, NULL);
+                state->locale_module, &PyId_getpreferredencoding, "O", Py_False);
             if (self->encoding == NULL) {
               catch_ImportError:
                 /*