From efb00c0cc189c1fdee329e8b7fdd07b3fd4a54cf Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 29 Feb 2012 18:31:31 -0500 Subject: Issue #14153 Create _Py_device_encoding() to prevent _io from having to import the os module. --- Include/fileutils.h | 2 ++ Lib/test/test_os.py | 19 +++++++++++++++++++ Modules/_io/_iomodule.c | 14 +++----------- Modules/_io/_iomodule.h | 5 ++--- Modules/_io/textio.c | 11 +++++++---- Modules/posixmodule.c | 30 +++--------------------------- Python/fileutils.c | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 70 insertions(+), 45 deletions(-) diff --git a/Include/fileutils.h b/Include/fileutils.h index 2fade9b..7c18cf2 100644 --- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -5,6 +5,8 @@ extern "C" { #endif +PyAPI_FUNC(PyObject *) _Py_device_encoding(int); + PyAPI_FUNC(wchar_t *) _Py_char2wchar( const char *arg, size_t *size); diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index a0f13fd..5959d1e 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -22,6 +22,8 @@ import asynchat import socket import itertools import stat +import locale +import codecs try: import threading except ImportError: @@ -1424,6 +1426,22 @@ class FSEncodingTests(unittest.TestCase): self.assertEqual(os.fsdecode(bytesfn), fn) + +class DeviceEncodingTests(unittest.TestCase): + + def test_bad_fd(self): + # Return None when an fd doesn't actually exist. + self.assertIsNone(os.device_encoding(123456)) + + @unittest.skipUnless(sys.platform.startswith('win') or + (hasattr(locale, 'nl_langinfo') and hasattr(locale, 'CODESET')), + 'test requires either Windows or nl_langinfo(CODESET)') + def test_device_encoding(self): + encoding = os.device_encoding(0) + self.assertIsNotNone(encoding) + self.assertTrue(codecs.lookup(encoding)) + + class PidTests(unittest.TestCase): @unittest.skipUnless(hasattr(os, 'getppid'), "test needs os.getppid") def test_getppid(self): @@ -1923,6 +1941,7 @@ def test_main(): Win32KillTests, Win32SymlinkTests, FSEncodingTests, + DeviceEncodingTests, PidTests, LoginTests, LinkTests, diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 9aad479..31eea3c 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -1,9 +1,9 @@ /* An implementation of the new I/O lib as defined by PEP 3116 - "New I/O" - + Classes defined here: UnsupportedOperation, BlockingIOError. Functions defined here: open(). - + Mostly written by Amaury Forgeot d'Arc */ @@ -510,7 +510,7 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err) /* Basically the "n" format code with the ability to turn None into -1. */ -int +int _PyIO_ConvertSsize_t(PyObject *obj, void *result) { Py_ssize_t limit; if (obj == Py_None) { @@ -537,7 +537,6 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { _PyIO_State *state = IO_MOD_STATE(mod); if (!state->initialized) return 0; - Py_VISIT(state->os_module); if (state->locale_module != NULL) { Py_VISIT(state->locale_module); } @@ -551,7 +550,6 @@ iomodule_clear(PyObject *mod) { _PyIO_State *state = IO_MOD_STATE(mod); if (!state->initialized) return 0; - Py_CLEAR(state->os_module); if (state->locale_module != NULL) Py_CLEAR(state->locale_module); Py_CLEAR(state->unsupported_operation); @@ -595,11 +593,6 @@ PyInit__io(void) state = IO_MOD_STATE(m); state->initialized = 0; - /* put os in the module state */ - state->os_module = PyImport_ImportModule("os"); - if (state->os_module == NULL) - goto fail; - #define ADD_TYPE(type, name) \ if (PyType_Ready(type) < 0) \ goto fail; \ @@ -725,7 +718,6 @@ PyInit__io(void) return m; fail: - Py_XDECREF(state->os_module); Py_XDECREF(state->unsupported_operation); Py_DECREF(m); return NULL; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index b3a8471..987aac8 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -50,8 +50,8 @@ extern PyObject *_PyIncrementalNewlineDecoder_decode( `*consumed`. If not found, returns -1 and sets `*consumed` to the number of characters which can be safely put aside until another search. - - NOTE: for performance reasons, `end` must point to a NUL character ('\0'). + + NOTE: for performance reasons, `end` must point to a NUL character ('\0'). Otherwise, the function will scan further and return garbage. */ extern Py_ssize_t _PyIO_find_line_ending( int translated, int universal, PyObject *readnl, @@ -124,7 +124,6 @@ extern PyModuleDef _PyIO_Module; typedef struct { int initialized; - PyObject *os_module; PyObject *locale_module; PyObject *unsupported_operation; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 79c64ba..833a527 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -14,7 +14,6 @@ _Py_IDENTIFIER(close); _Py_IDENTIFIER(_dealloc_warn); _Py_IDENTIFIER(decode); -_Py_IDENTIFIER(device_encoding); _Py_IDENTIFIER(fileno); _Py_IDENTIFIER(flush); _Py_IDENTIFIER(getpreferredencoding); @@ -875,9 +874,13 @@ textiowrapper_init(textio *self, PyObject *args, PyObject *kwds) } } else { - self->encoding = _PyObject_CallMethodId(state->os_module, - &PyId_device_encoding, - "N", fileno); + int fd = (int) PyLong_AsLong(fileno); + Py_DECREF(fileno); + if (fd == -1 && PyErr_Occurred()) { + goto error; + } + + self->encoding = _Py_device_encoding(fd); if (self->encoding == NULL) goto error; else if (!PyUnicode_Check(self->encoding)) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index dbace1a..628b0b9 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9326,35 +9326,11 @@ static PyObject * device_encoding(PyObject *self, PyObject *args) { int fd; -#if defined(MS_WINDOWS) || defined(MS_WIN64) - UINT cp; -#endif + if (!PyArg_ParseTuple(args, "i:device_encoding", &fd)) return NULL; - if (!_PyVerify_fd(fd) || !isatty(fd)) { - Py_INCREF(Py_None); - return Py_None; - } -#if defined(MS_WINDOWS) || defined(MS_WIN64) - if (fd == 0) - cp = GetConsoleCP(); - else if (fd == 1 || fd == 2) - cp = GetConsoleOutputCP(); - else - cp = 0; - /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application - has no console */ - if (cp != 0) - return PyUnicode_FromFormat("cp%u", (unsigned int)cp); -#elif defined(CODESET) - { - char *codeset = nl_langinfo(CODESET); - if (codeset != NULL && codeset[0] != 0) - return PyUnicode_FromString(codeset); - } -#endif - Py_INCREF(Py_None); - return Py_None; + + return _Py_device_encoding(fd); } #ifdef __VMS diff --git a/Python/fileutils.c b/Python/fileutils.c index 8993c8c..501cb8c 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -3,6 +3,40 @@ # include #endif +#ifdef HAVE_LANGINFO_H +#include +#endif + +PyObject * +_Py_device_encoding(int fd) +{ +#if defined(MS_WINDOWS) || defined(MS_WIN64) + UINT cp; +#endif + if (!_PyVerify_fd(fd) || !isatty(fd)) { + Py_RETURN_NONE; + } +#if defined(MS_WINDOWS) || defined(MS_WIN64) + if (fd == 0) + cp = GetConsoleCP(); + else if (fd == 1 || fd == 2) + cp = GetConsoleOutputCP(); + else + cp = 0; + /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application + has no console */ + if (cp != 0) + return PyUnicode_FromFormat("cp%u", (unsigned int)cp); +#elif defined(CODESET) + { + char *codeset = nl_langinfo(CODESET); + if (codeset != NULL && codeset[0] != 0) + return PyUnicode_FromString(codeset); + } +#endif + Py_RETURN_NONE; +} + #ifdef HAVE_STAT /* Decode a byte string from the locale encoding with the -- cgit v0.12