summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/Python.h1
-rw-r--r--Include/osmodule.h15
-rw-r--r--Lib/os.py35
-rw-r--r--Lib/test/test_os.py7
-rw-r--r--Modules/clinic/posixmodule.c.h34
-rw-r--r--Modules/posixmodule.c51
6 files changed, 125 insertions, 18 deletions
diff --git a/Include/Python.h b/Include/Python.h
index 858dbd1..4c7c9a4 100644
--- a/Include/Python.h
+++ b/Include/Python.h
@@ -116,6 +116,7 @@
#include "pylifecycle.h"
#include "ceval.h"
#include "sysmodule.h"
+#include "osmodule.h"
#include "intrcheck.h"
#include "import.h"
diff --git a/Include/osmodule.h b/Include/osmodule.h
new file mode 100644
index 0000000..7146757
--- /dev/null
+++ b/Include/osmodule.h
@@ -0,0 +1,15 @@
+
+/* os module interface */
+
+#ifndef Py_OSMODULE_H
+#define Py_OSMODULE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PyAPI_FUNC(PyObject *) PyOS_FSPath(PyObject *path);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_OSMODULE_H */
diff --git a/Lib/os.py b/Lib/os.py
index 1318de6..0131ed8 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -1104,23 +1104,24 @@ def fdopen(fd, *args, **kwargs):
import io
return io.open(fd, *args, **kwargs)
-# Supply os.fspath()
-def fspath(path):
- """Return the string representation of the path.
+# Supply os.fspath() if not defined in C
+if not _exists('fspath'):
+ def fspath(path):
+ """Return the string representation of the path.
- If str or bytes is passed in, it is returned unchanged.
- """
- if isinstance(path, (str, bytes)):
- return path
+ If str or bytes is passed in, it is returned unchanged.
+ """
+ if isinstance(path, (str, bytes)):
+ return path
- # Work from the object's type to match method resolution of other magic
- # methods.
- path_type = type(path)
- try:
- return path_type.__fspath__(path)
- except AttributeError:
- if hasattr(path_type, '__fspath__'):
- raise
+ # Work from the object's type to match method resolution of other magic
+ # methods.
+ path_type = type(path)
+ try:
+ return path_type.__fspath__(path)
+ except AttributeError:
+ if hasattr(path_type, '__fspath__'):
+ raise
- raise TypeError("expected str, bytes or os.PathLike object, not "
- + path_type.__name__)
+ raise TypeError("expected str, bytes or os.PathLike object, not "
+ + path_type.__name__)
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 84ef150..bf06438 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -3121,6 +3121,13 @@ class TestPEP519(unittest.TestCase):
self.assertEqual(b"path/like/object", os.fsencode(pathlike))
self.assertEqual("path/like/object", os.fsdecode(pathlike))
+ def test_fspathlike(self):
+ class PathLike(object):
+ def __fspath__(self):
+ return '#feelthegil'
+
+ self.assertEqual('#feelthegil', os.fspath(PathLike()))
+
def test_garbage_in_exception_out(self):
vapor = type('blah', (), {})
for o in int, type, os, vapor():
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index a48de6a..2758d48 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -5321,6 +5321,38 @@ exit:
#endif /* defined(MS_WINDOWS) */
+PyDoc_STRVAR(os_fspath__doc__,
+"fspath($module, /, path)\n"
+"--\n"
+"\n"
+"Return the file system path representation of the object.\n"
+"\n"
+"If the object is str or bytes, then allow it to pass through with\n"
+"an incremented refcount. If the object defines __fspath__(), then\n"
+"return the result of that method. All other types raise a TypeError.");
+
+#define OS_FSPATH_METHODDEF \
+ {"fspath", (PyCFunction)os_fspath, METH_VARARGS|METH_KEYWORDS, os_fspath__doc__},
+
+static PyObject *
+os_fspath_impl(PyModuleDef *module, PyObject *path);
+
+static PyObject *
+os_fspath(PyModuleDef *module, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ static char *_keywords[] = {"path", NULL};
+ PyObject *path;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:fspath", _keywords,
+ &path))
+ goto exit;
+ return_value = os_fspath_impl(module, path);
+
+exit:
+ return return_value;
+}
+
#ifndef OS_TTYNAME_METHODDEF
#define OS_TTYNAME_METHODDEF
#endif /* !defined(OS_TTYNAME_METHODDEF) */
@@ -5792,4 +5824,4 @@ exit:
#ifndef OS_SET_HANDLE_INHERITABLE_METHODDEF
#define OS_SET_HANDLE_INHERITABLE_METHODDEF
#endif /* !defined(OS_SET_HANDLE_INHERITABLE_METHODDEF) */
-/*[clinic end generated code: output=a5c9bef9ad11a20b input=a9049054013a1b77]*/
+/*[clinic end generated code: output=e64e246b8270abda input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index ded6d71..c552265 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -12284,6 +12284,56 @@ error:
return NULL;
}
+/*
+ Return the file system path representation of the object.
+
+ If the object is str or bytes, then allow it to pass through with
+ an incremented refcount. If the object defines __fspath__(), then
+ return the result of that method. All other types raise a TypeError.
+*/
+PyObject *
+PyOS_FSPath(PyObject *path)
+{
+ _Py_IDENTIFIER(__fspath__);
+ PyObject *func = NULL;
+ PyObject *path_repr = NULL;
+
+ if (PyUnicode_Check(path) || PyBytes_Check(path)) {
+ Py_INCREF(path);
+ return path;
+ }
+
+ func = _PyObject_LookupSpecial(path, &PyId___fspath__);
+ if (NULL == func) {
+ return PyErr_Format(PyExc_TypeError,
+ "expected str, bytes or os.PathLike object, "
+ "not %S",
+ path->ob_type);
+ }
+
+ path_repr = PyObject_CallFunctionObjArgs(func, NULL);
+ Py_DECREF(func);
+ return path_repr;
+}
+
+/*[clinic input]
+os.fspath
+
+ path: object
+
+Return the file system path representation of the object.
+
+If the object is str or bytes, then allow it to pass through with
+an incremented refcount. If the object defines __fspath__(), then
+return the result of that method. All other types raise a TypeError.
+[clinic start generated code]*/
+
+static PyObject *
+os_fspath_impl(PyModuleDef *module, PyObject *path)
+/*[clinic end generated code: output=51ef0c2772c1932a input=652c7c37e4be1c13]*/
+{
+ return PyOS_FSPath(path);
+}
#include "clinic/posixmodule.c.h"
@@ -12484,6 +12534,7 @@ static PyMethodDef posix_methods[] = {
{"scandir", (PyCFunction)posix_scandir,
METH_VARARGS | METH_KEYWORDS,
posix_scandir__doc__},
+ OS_FSPATH_METHODDEF
{NULL, NULL} /* Sentinel */
};