Skip to content

Commit d1cd4d4

Browse files
committed
Set sys.stdout.encoding properly.
Always set LC_CTYPE on interpreter startup. Add device_encoding function.
1 parent 79c3208 commit d1cd4d4

File tree

4 files changed

+59
-9
lines changed

4 files changed

+59
-9
lines changed

Lib/io.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -971,8 +971,13 @@ def __init__(self, buffer, encoding=None, newline=None):
971971
if newline not in (None, "\n", "\r\n"):
972972
raise ValueError("illegal newline value: %r" % (newline,))
973973
if encoding is None:
974-
# XXX This is questionable
975-
encoding = sys.getfilesystemencoding() or "latin-1"
974+
try:
975+
encoding = os.device_encoding(buffer.fileno())
976+
except AttributeError:
977+
pass
978+
if encoding is None:
979+
import locale
980+
encoding = locale.getpreferredencoding()
976981

977982
self.buffer = buffer
978983
self._encoding = encoding

Modules/_localemodule.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/***********************************************************
2-
Copyright (C) 1997, 2002, 2003 Martin von Loewis
2+
Copyright (C) 1997, 2002, 2003, 2007 Martin von Loewis
33
44
Permission to use, copy, modify, and distribute this software and its
55
documentation for any purpose and without fee is hereby granted,
@@ -562,7 +562,8 @@ PyLocale_nl_langinfo(PyObject* self, PyObject* args)
562562
/* Check NULL as a workaround for GNU libc's returning NULL
563563
instead of an empty string for nl_langinfo(ERA). */
564564
const char *result = nl_langinfo(item);
565-
return PyString_FromString(result != NULL ? result : "");
565+
/* XXX may have to convert this to wcs first. */
566+
return PyUnicode_FromString(result != NULL ? result : "");
566567
}
567568
PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant");
568569
return NULL;

Modules/posixmodule.c

+42
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ corresponding Unix manual entries for more information on calls.");
9292
#include <sys/loadavg.h>
9393
#endif
9494

95+
#ifdef HAVE_LANGINFO_H
96+
#include <langinfo.h>
97+
#endif
98+
9599
/* Various compilers have only certain posix functions */
96100
/* XXX Gosh I wish these were all moved into pyconfig.h */
97101
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
@@ -6581,6 +6585,43 @@ win32_urandom(PyObject *self, PyObject *args)
65816585
}
65826586
#endif
65836587

6588+
PyDoc_STRVAR(device_encoding__doc__,
6589+
"device_encoding(fd) -> str\n\n\
6590+
Return a string describing the encoding of the device\n\
6591+
if the output is a terminal; else return None.");
6592+
6593+
static PyObject *
6594+
device_encoding(PyObject *self, PyObject *args)
6595+
{
6596+
int fd;
6597+
if (!PyArg_ParseTuple(args, "i:device_encoding", &fd))
6598+
return NULL;
6599+
if (!isatty(fd)) {
6600+
Py_INCREF(Py_None);
6601+
return Py_None;
6602+
}
6603+
#if defined(MS_WINDOWS) || defined(MS_WIN64)
6604+
if (fd == 0) {
6605+
char buf[100];
6606+
sprintf(buf, "cp%d", GetConsoleCP());
6607+
return PyUnicode_FromString(buf);
6608+
}
6609+
if (fd == 1 || fd == 2) {
6610+
char buf[100];
6611+
sprintf(buf, "cp%d", GetConsoleOutputCP());
6612+
return PyUnicode_FromString(buf);
6613+
}
6614+
#elif defined(CODESET)
6615+
{
6616+
char *codeset = nl_langinfo(CODESET);
6617+
if (codeset)
6618+
return PyUnicode_FromString(codeset);
6619+
}
6620+
#endif
6621+
Py_INCREF(Py_None);
6622+
return Py_None;
6623+
}
6624+
65846625
#ifdef __VMS
65856626
/* Use openssl random routine */
65866627
#include <openssl/rand.h>
@@ -6793,6 +6834,7 @@ static PyMethodDef posix_methods[] = {
67936834
#endif /* HAVE_TCSETPGRP */
67946835
{"open", posix_open, METH_VARARGS, posix_open__doc__},
67956836
{"close", posix_close, METH_VARARGS, posix_close__doc__},
6837+
{"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__},
67966838
{"dup", posix_dup, METH_VARARGS, posix_dup__doc__},
67976839
{"dup2", posix_dup2, METH_VARARGS, posix_dup2__doc__},
67986840
{"lseek", posix_lseek, METH_VARARGS, posix_lseek__doc__},

Python/pythonrun.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,20 @@ Py_InitializeEx(int install_sigs)
154154
char *p;
155155
#if defined(HAVE_LANGINFO_H) && defined(CODESET)
156156
char *codeset;
157-
char *saved_locale;
158157
#endif
159158
extern void _Py_ReadyTypes(void);
160159

161160
if (initialized)
162161
return;
163162
initialized = 1;
164163

164+
#ifdef HAVE_SETLOCALE
165+
/* Set up the LC_CTYPE locale, so we can obtain
166+
the locale's charset without having to switch
167+
locales. */
168+
setlocale(LC_CTYPE, "");
169+
#endif
170+
165171
if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0')
166172
Py_DebugFlag = add_flag(Py_DebugFlag, p);
167173
if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0')
@@ -254,8 +260,6 @@ Py_InitializeEx(int install_sigs)
254260
initialized by other means. Also set the encoding of
255261
stdin and stdout if these are terminals. */
256262

257-
saved_locale = strdup(setlocale(LC_CTYPE, NULL));
258-
setlocale(LC_CTYPE, "");
259263
codeset = nl_langinfo(CODESET);
260264
if (codeset && *codeset) {
261265
PyObject *enc = PyCodec_Encoder(codeset);
@@ -268,8 +272,6 @@ Py_InitializeEx(int install_sigs)
268272
}
269273
} else
270274
codeset = NULL;
271-
setlocale(LC_CTYPE, saved_locale);
272-
free(saved_locale);
273275

274276
if (codeset) {
275277
if (!Py_FileSystemDefaultEncoding)

0 commit comments

Comments
 (0)