Commit a5711204 authored by Brett Cannon's avatar Brett Cannon

Issue #27182: Add support for path-like objects to PyUnicode_FSDecoder().

parent a439191e
...@@ -826,13 +826,17 @@ used, passing :c:func:`PyUnicode_FSDecoder` as the conversion function: ...@@ -826,13 +826,17 @@ used, passing :c:func:`PyUnicode_FSDecoder` as the conversion function:
.. c:function:: int PyUnicode_FSDecoder(PyObject* obj, void* result) .. c:function:: int PyUnicode_FSDecoder(PyObject* obj, void* result)
ParseTuple converter: decode :class:`bytes` objects to :class:`str` using ParseTuple converter: decode :class:`bytes` objects -- obtained either
:c:func:`PyUnicode_DecodeFSDefaultAndSize`; :class:`str` objects are output directly or indirectly through the :class:`os.PathLike` interface -- to
as-is. *result* must be a :c:type:`PyUnicodeObject*` which must be released :class:`str` using :c:func:`PyUnicode_DecodeFSDefaultAndSize`; :class:`str`
when it is no longer used. objects are output as-is. *result* must be a :c:type:`PyUnicodeObject*` which
must be released when it is no longer used.
.. versionadded:: 3.2 .. versionadded:: 3.2
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
.. c:function:: PyObject* PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size) .. c:function:: PyObject* PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size)
......
...@@ -160,14 +160,18 @@ object. ...@@ -160,14 +160,18 @@ object.
The built-in :func:`open` function has been updated to accept The built-in :func:`open` function has been updated to accept
:class:`os.PathLike` objects as have all relevant functions in the :class:`os.PathLike` objects as have all relevant functions in the
:mod:`os` and :mod:`os.path` modules. The :class:`os.DirEntry` class :mod:`os` and :mod:`os.path` modules. :c:func:`PyUnicode_FSConverter`
and :c:func:`PyUnicode_FSConverter` have been changed to accept
path-like objects. The :class:`os.DirEntry` class
and relevant classes in :mod:`pathlib` have also been updated to and relevant classes in :mod:`pathlib` have also been updated to
implement :class:`os.PathLike`. The hope is that updating the implement :class:`os.PathLike`.
fundamental functions for operating on file system paths will lead
to third-party code to implicitly support all The hope in is that updating the fundamental functions for operating
:term:`path-like objects <path-like object>` without any code changes on file system paths will lead to third-party code to implicitly
or at least very minimal ones (e.g. calling :func:`os.fspath` at the support all :term:`path-like objects <path-like object>` without any
beginning of code before operating on a path-like object). code changes or at least very minimal ones (e.g. calling
:func:`os.fspath` at the beginning of code before operating on a
path-like object).
Here are some examples of how the new interface allows for Here are some examples of how the new interface allows for
:class:`pathlib.Path` to be used more easily and transparently with :class:`pathlib.Path` to be used more easily and transparently with
......
...@@ -664,6 +664,16 @@ if 1: ...@@ -664,6 +664,16 @@ if 1:
self.assertTrue(f1(0)) self.assertTrue(f1(0))
self.assertTrue(f2(0.0)) self.assertTrue(f2(0.0))
def test_path_like_objects(self):
# An implicit test for PyUnicode_FSDecoder().
class PathLike:
def __init__(self, path):
self._path = path
def __fspath__(self):
return self._path
compile("42", PathLike("test_compile_pathlike"), "single")
class TestStackSize(unittest.TestCase): class TestStackSize(unittest.TestCase):
# These tests check that the computed stack size for a code object # These tests check that the computed stack size for a code object
......
...@@ -202,7 +202,8 @@ Library ...@@ -202,7 +202,8 @@ Library
C API C API
----- -----
- Issue #26027: Add support for path-like objects in PyUnicode_FSConverter(). - Issue #26027: Add support for path-like objects in PyUnicode_FSConverter() &
PyUnicode_FSDecoder().
Tests Tests
----- -----
......
...@@ -3882,37 +3882,60 @@ PyUnicode_FSConverter(PyObject* arg, void* addr) ...@@ -3882,37 +3882,60 @@ PyUnicode_FSConverter(PyObject* arg, void* addr)
int int
PyUnicode_FSDecoder(PyObject* arg, void* addr) PyUnicode_FSDecoder(PyObject* arg, void* addr)
{ {
int is_buffer = 0;
PyObject *path = NULL;
PyObject *output = NULL; PyObject *output = NULL;
if (arg == NULL) { if (arg == NULL) {
Py_DECREF(*(PyObject**)addr); Py_DECREF(*(PyObject**)addr);
return 1; return 1;
} }
if (PyUnicode_Check(arg)) {
if (PyUnicode_READY(arg) == -1) is_buffer = PyObject_CheckBuffer(arg);
if (!is_buffer) {
path = PyOS_FSPath(arg);
if (path == NULL) {
return 0;
}
}
else {
path = arg;
Py_INCREF(arg);
}
if (PyUnicode_Check(path)) {
if (PyUnicode_READY(path) == -1) {
Py_DECREF(path);
return 0; return 0;
output = arg; }
Py_INCREF(output); output = path;
} }
else if (PyBytes_Check(arg) || PyObject_CheckBuffer(arg)) { else if (PyBytes_Check(path) || is_buffer) {
if (!PyBytes_Check(arg) && PyObject *path_bytes = NULL;
if (!PyBytes_Check(path) &&
PyErr_WarnFormat(PyExc_DeprecationWarning, 1, PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"path should be string or bytes, not %.200s", "path should be string, bytes, or os.PathLike, not %.200s",
Py_TYPE(arg)->tp_name)) { Py_TYPE(arg)->tp_name)) {
Py_DECREF(path);
return 0; return 0;
} }
arg = PyBytes_FromObject(arg); path_bytes = PyBytes_FromObject(path);
if (!arg) Py_DECREF(path);
if (!path_bytes) {
return 0; return 0;
output = PyUnicode_DecodeFSDefaultAndSize(PyBytes_AS_STRING(arg), }
PyBytes_GET_SIZE(arg)); output = PyUnicode_DecodeFSDefaultAndSize(PyBytes_AS_STRING(path_bytes),
Py_DECREF(arg); PyBytes_GET_SIZE(path_bytes));
if (!output) Py_DECREF(path_bytes);
if (!output) {
return 0; return 0;
}
} }
else { else {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"path should be string or bytes, not %.200s", "path should be string, bytes, or os.PathLike, not %.200s",
Py_TYPE(arg)->tp_name); Py_TYPE(arg)->tp_name);
Py_DECREF(path);
return 0; return 0;
} }
if (PyUnicode_READY(output) == -1) { if (PyUnicode_READY(output) == -1) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment