Skip to content

Commit 04dc25c

Browse files
committed
Issue #3187: Add sys.setfilesystemencoding.
1 parent efb14a8 commit 04dc25c

File tree

6 files changed

+58
-4
lines changed

6 files changed

+58
-4
lines changed

Doc/library/sys.rst

+8
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,14 @@ always available.
578578
:file:`/usr/include/dlfcn.h` using the :program:`h2py` script. Availability:
579579
Unix.
580580

581+
.. function:: setfilesystemencoding(enc)
582+
583+
Set the encoding used when converting Python strings to file names to *enc*.
584+
By default, Python tries to determine the encoding it should use automatically
585+
on Unix; on Windows, it avoids such conversion completely. This function can
586+
be used when Python's determination of the encoding needs to be overwritten,
587+
e.g. when not all file names on disk can be decoded using the encoding that
588+
Python had chosen.
581589

582590
.. function:: setprofile(profilefunc)
583591

Include/fileobject.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *);
2020
If non-NULL, this is different than the default encoding for strings
2121
*/
2222
PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding;
23-
PyAPI_DATA(const int) Py_HasFileSystemDefaultEncoding;
23+
PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding;
24+
PyAPI_FUNC(int) _Py_SetFileSystemEncoding(PyObject *);
2425

2526
/* Internal API
2627

Lib/test/test_sys.py

+5
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,11 @@ def test_pythontypes(self):
658658
# sys.flags
659659
check(sys.flags, size(vh) + self.P * len(sys.flags))
660660

661+
def test_setfilesystemencoding(self):
662+
old = sys.getfilesystemencoding()
663+
sys.setfilesystemencoding("iso-8859-1")
664+
self.assertEqual(sys.getfilesystemencoding(), "iso-8859-1")
665+
sys.setfilesystemencoding(old)
661666

662667
def test_main():
663668
test.support.run_unittest(SysModuleTest, SizeofTest)

Misc/NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Core and Builtins
2525
Library
2626
-------
2727

28+
- Issue #3187: Add sys.setfilesystemencoding.
29+
2830
- Issue #3187: Better support for "undecodable" filenames. Code by Victor
2931
Stinner, with small tweaks by GvR.
3032

Python/bltinmodule.c

+22-3
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,34 @@
1717
*/
1818
#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T)
1919
const char *Py_FileSystemDefaultEncoding = "mbcs";
20-
const int Py_HasFileSystemDefaultEncoding = 1;
20+
int Py_HasFileSystemDefaultEncoding = 1;
2121
#elif defined(__APPLE__)
2222
const char *Py_FileSystemDefaultEncoding = "utf-8";
23-
const int Py_HasFileSystemDefaultEncoding = 1;
23+
int Py_HasFileSystemDefaultEncoding = 1;
2424
#else
2525
const char *Py_FileSystemDefaultEncoding = NULL; /* use default */
26-
const int Py_HasFileSystemDefaultEncoding = 0;
26+
int Py_HasFileSystemDefaultEncoding = 0;
2727
#endif
2828

29+
int
30+
_Py_SetFileSystemEncoding(PyObject *s)
31+
{
32+
PyObject *defenc;
33+
if (!PyUnicode_Check(s)) {
34+
PyErr_BadInternalCall();
35+
return -1;
36+
}
37+
defenc = _PyUnicode_AsDefaultEncodedString(s, NULL);
38+
if (!defenc)
39+
return -1;
40+
if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding)
41+
/* A file system encoding was set at run-time */
42+
free((char*)Py_FileSystemDefaultEncoding);
43+
Py_FileSystemDefaultEncoding = strdup(PyBytes_AsString(defenc));
44+
Py_HasFileSystemDefaultEncoding = 0;
45+
return 0;
46+
}
47+
2948
static PyObject *
3049
builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds)
3150
{

Python/sysmodule.c

+19
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,24 @@ Return the encoding used to convert Unicode filenames in\n\
216216
operating system filenames."
217217
);
218218

219+
static PyObject *
220+
sys_setfilesystemencoding(PyObject *self, PyObject *args)
221+
{
222+
PyObject *new_encoding;
223+
if (!PyArg_ParseTuple(args, "U:setfilesystemencoding", &new_encoding))
224+
return NULL;
225+
if (_Py_SetFileSystemEncoding(new_encoding))
226+
return NULL;
227+
Py_INCREF(Py_None);
228+
return Py_None;
229+
}
219230

231+
PyDoc_STRVAR(setfilesystemencoding_doc,
232+
"setfilesystemencoding(string) -> None\n\
233+
\n\
234+
Set the encoding used to convert Unicode filenames in\n\
235+
operating system filenames."
236+
);
220237

221238
static PyObject *
222239
sys_intern(PyObject *self, PyObject *args)
@@ -872,6 +889,8 @@ static PyMethodDef sys_methods[] = {
872889
#endif
873890
{"setdefaultencoding", sys_setdefaultencoding, METH_VARARGS,
874891
setdefaultencoding_doc},
892+
{"setfilesystemencoding", sys_setfilesystemencoding, METH_VARARGS,
893+
setfilesystemencoding_doc},
875894
{"setcheckinterval", sys_setcheckinterval, METH_VARARGS,
876895
setcheckinterval_doc},
877896
{"getcheckinterval", sys_getcheckinterval, METH_NOARGS,

0 commit comments

Comments
 (0)