mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
Close #11022: TextIOWrapper doesn't call locale.setlocale() anymore
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.
This commit is contained in:
parent
91c5a34613
commit
f86a5e8a93
8 changed files with 84 additions and 29 deletions
|
@ -800,9 +800,10 @@ are always available. They are listed here in alphabetical order.
|
||||||
already exists), ``'x'`` for exclusive creation and ``'a'`` for appending
|
already exists), ``'x'`` for exclusive creation and ``'a'`` for appending
|
||||||
(which on *some* Unix systems, means that *all* writes append to the end of
|
(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
|
the file regardless of the current seek position). In text mode, if
|
||||||
*encoding* is not specified the encoding used is platform dependent. (For
|
*encoding* is not specified the encoding used is platform dependent:
|
||||||
reading and writing raw bytes use binary mode and leave *encoding*
|
``locale.getpreferredencoding(False)`` is called to get the current locale
|
||||||
unspecified.) The available modes are:
|
encoding. (For reading and writing raw bytes use binary mode and leave
|
||||||
|
*encoding* unspecified.) The available modes are:
|
||||||
|
|
||||||
========= ===============================================================
|
========= ===============================================================
|
||||||
Character Meaning
|
Character Meaning
|
||||||
|
|
|
@ -752,7 +752,7 @@ Text I/O
|
||||||
It inherits :class:`TextIOBase`.
|
It inherits :class:`TextIOBase`.
|
||||||
|
|
||||||
*encoding* gives the name of the encoding that the stream will be decoded or
|
*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* is an optional string that specifies how encoding and decoding
|
||||||
errors are to be handled. Pass ``'strict'`` to raise a :exc:`ValueError`
|
errors are to be handled. Pass ``'strict'`` to raise a :exc:`ValueError`
|
||||||
|
@ -784,6 +784,12 @@ Text I/O
|
||||||
.. versionchanged:: 3.3
|
.. versionchanged:: 3.3
|
||||||
The *write_through* argument has been added.
|
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:`TextIOWrapper` provides one attribute in addition to those of
|
||||||
:class:`TextIOBase` and its parents:
|
:class:`TextIOBase` and its parents:
|
||||||
|
|
||||||
|
|
|
@ -1448,7 +1448,7 @@ class TextIOWrapper(TextIOBase):
|
||||||
r"""Character and line based layer over a BufferedIOBase object, buffer.
|
r"""Character and line based layer over a BufferedIOBase object, buffer.
|
||||||
|
|
||||||
encoding gives the name of the encoding that the stream will be
|
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
|
errors determines the strictness of encoding and decoding (see the
|
||||||
codecs.register) and defaults to "strict".
|
codecs.register) and defaults to "strict".
|
||||||
|
@ -1487,7 +1487,7 @@ class TextIOWrapper(TextIOBase):
|
||||||
# Importing locale may fail if Python is being built
|
# Importing locale may fail if Python is being built
|
||||||
encoding = "ascii"
|
encoding = "ascii"
|
||||||
else:
|
else:
|
||||||
encoding = locale.getpreferredencoding()
|
encoding = locale.getpreferredencoding(False)
|
||||||
|
|
||||||
if not isinstance(encoding, str):
|
if not isinstance(encoding, str):
|
||||||
raise ValueError("invalid encoding: %r" % encoding)
|
raise ValueError("invalid encoding: %r" % encoding)
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
# Python test set -- built-in functions
|
# Python test set -- built-in functions
|
||||||
|
|
||||||
import platform
|
import ast
|
||||||
import unittest
|
import builtins
|
||||||
import sys
|
|
||||||
import warnings
|
|
||||||
import collections
|
import collections
|
||||||
import io
|
import io
|
||||||
|
import locale
|
||||||
import os
|
import os
|
||||||
import ast
|
|
||||||
import types
|
|
||||||
import builtins
|
|
||||||
import random
|
|
||||||
import traceback
|
|
||||||
from test.support import TESTFN, unlink, run_unittest, check_warnings
|
|
||||||
from operator import neg
|
|
||||||
import pickle
|
import pickle
|
||||||
|
import platform
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import types
|
||||||
|
import unittest
|
||||||
|
import warnings
|
||||||
|
from operator import neg
|
||||||
|
from test.support import TESTFN, unlink, run_unittest, check_warnings
|
||||||
try:
|
try:
|
||||||
import pty, signal
|
import pty, signal
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -961,6 +962,27 @@ class BuiltinTest(unittest.TestCase):
|
||||||
fp.close()
|
fp.close()
|
||||||
unlink(TESTFN)
|
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):
|
def test_ord(self):
|
||||||
self.assertEqual(ord(' '), 32)
|
self.assertEqual(ord(' '), 32)
|
||||||
self.assertEqual(ord('A'), 65)
|
self.assertEqual(ord('A'), 65)
|
||||||
|
|
|
@ -19,20 +19,21 @@
|
||||||
# test both implementations. This file has lots of examples.
|
# test both implementations. This file has lots of examples.
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
import abc
|
||||||
|
import array
|
||||||
|
import errno
|
||||||
|
import locale
|
||||||
import os
|
import os
|
||||||
|
import pickle
|
||||||
|
import random
|
||||||
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import array
|
|
||||||
import random
|
|
||||||
import unittest
|
import unittest
|
||||||
import weakref
|
|
||||||
import abc
|
|
||||||
import signal
|
|
||||||
import errno
|
|
||||||
import warnings
|
import warnings
|
||||||
import pickle
|
import weakref
|
||||||
from itertools import cycle, count
|
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
from itertools import cycle, count
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
|
@ -1881,6 +1882,24 @@ class TextIOWrapperTest(unittest.TestCase):
|
||||||
t.write("A\rB")
|
t.write("A\rB")
|
||||||
self.assertEqual(r.getvalue(), b"XY\nZA\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):
|
def test_encoding(self):
|
||||||
# Check the encoding attribute is always set, and valid
|
# Check the encoding attribute is always set, and valid
|
||||||
b = self.BytesIO()
|
b = self.BytesIO()
|
||||||
|
|
|
@ -10,6 +10,12 @@ What's New in Python 3.3.0 Beta 1?
|
||||||
Core and Builtins
|
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.
|
- Issue #14673: Add Eric Snow's sys.implementation implementation.
|
||||||
|
|
||||||
Library
|
Library
|
||||||
|
|
|
@ -112,8 +112,9 @@ PyDoc_STRVAR(open_doc,
|
||||||
"'a' for appending (which on some Unix systems, means that all writes\n"
|
"'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"
|
"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"
|
"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"
|
"dependent: locale.getpreferredencoding(False) is called to get the\n"
|
||||||
"encoding unspecified.) The available modes are:\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"
|
||||||
"========= ===============================================================\n"
|
"========= ===============================================================\n"
|
||||||
"Character Meaning\n"
|
"Character Meaning\n"
|
||||||
|
|
|
@ -630,7 +630,7 @@ PyDoc_STRVAR(textiowrapper_doc,
|
||||||
"Character and line based layer over a BufferedIOBase object, buffer.\n"
|
"Character and line based layer over a BufferedIOBase object, buffer.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"encoding gives the name of the encoding that the stream will be\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"
|
"\n"
|
||||||
"errors determines the strictness of encoding and decoding (see the\n"
|
"errors determines the strictness of encoding and decoding (see the\n"
|
||||||
"codecs.register) and defaults to \"strict\".\n"
|
"codecs.register) and defaults to \"strict\".\n"
|
||||||
|
@ -898,7 +898,7 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
|
||||||
else {
|
else {
|
||||||
use_locale:
|
use_locale:
|
||||||
self->encoding = _PyObject_CallMethodId(
|
self->encoding = _PyObject_CallMethodId(
|
||||||
state->locale_module, &PyId_getpreferredencoding, NULL);
|
state->locale_module, &PyId_getpreferredencoding, "O", Py_False);
|
||||||
if (self->encoding == NULL) {
|
if (self->encoding == NULL) {
|
||||||
catch_ImportError:
|
catch_ImportError:
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue