mirror of https://github.com/python/cpython
issue27186: add C version of os.fspath(); patch by Jelle Zijlstra
This commit is contained in:
parent
c55014f371
commit
410ef8e230
|
@ -116,6 +116,7 @@
|
||||||
#include "pylifecycle.h"
|
#include "pylifecycle.h"
|
||||||
#include "ceval.h"
|
#include "ceval.h"
|
||||||
#include "sysmodule.h"
|
#include "sysmodule.h"
|
||||||
|
#include "osmodule.h"
|
||||||
#include "intrcheck.h"
|
#include "intrcheck.h"
|
||||||
#include "import.h"
|
#include "import.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 */
|
35
Lib/os.py
35
Lib/os.py
|
@ -1104,23 +1104,24 @@ def fdopen(fd, *args, **kwargs):
|
||||||
import io
|
import io
|
||||||
return io.open(fd, *args, **kwargs)
|
return io.open(fd, *args, **kwargs)
|
||||||
|
|
||||||
# Supply os.fspath()
|
# Supply os.fspath() if not defined in C
|
||||||
def fspath(path):
|
if not _exists('fspath'):
|
||||||
"""Return the string representation of the path.
|
def fspath(path):
|
||||||
|
"""Return the string representation of the path.
|
||||||
|
|
||||||
If str or bytes is passed in, it is returned unchanged.
|
If str or bytes is passed in, it is returned unchanged.
|
||||||
"""
|
"""
|
||||||
if isinstance(path, (str, bytes)):
|
if isinstance(path, (str, bytes)):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
# Work from the object's type to match method resolution of other magic
|
# Work from the object's type to match method resolution of other magic
|
||||||
# methods.
|
# methods.
|
||||||
path_type = type(path)
|
path_type = type(path)
|
||||||
try:
|
try:
|
||||||
return path_type.__fspath__(path)
|
return path_type.__fspath__(path)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if hasattr(path_type, '__fspath__'):
|
if hasattr(path_type, '__fspath__'):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
raise TypeError("expected str, bytes or os.PathLike object, not "
|
raise TypeError("expected str, bytes or os.PathLike object, not "
|
||||||
+ path_type.__name__)
|
+ path_type.__name__)
|
||||||
|
|
|
@ -3121,6 +3121,13 @@ class TestPEP519(unittest.TestCase):
|
||||||
self.assertEqual(b"path/like/object", os.fsencode(pathlike))
|
self.assertEqual(b"path/like/object", os.fsencode(pathlike))
|
||||||
self.assertEqual("path/like/object", os.fsdecode(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):
|
def test_garbage_in_exception_out(self):
|
||||||
vapor = type('blah', (), {})
|
vapor = type('blah', (), {})
|
||||||
for o in int, type, os, vapor():
|
for o in int, type, os, vapor():
|
||||||
|
|
|
@ -5321,6 +5321,38 @@ exit:
|
||||||
|
|
||||||
#endif /* defined(MS_WINDOWS) */
|
#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
|
#ifndef OS_TTYNAME_METHODDEF
|
||||||
#define OS_TTYNAME_METHODDEF
|
#define OS_TTYNAME_METHODDEF
|
||||||
#endif /* !defined(OS_TTYNAME_METHODDEF) */
|
#endif /* !defined(OS_TTYNAME_METHODDEF) */
|
||||||
|
@ -5792,4 +5824,4 @@ exit:
|
||||||
#ifndef OS_SET_HANDLE_INHERITABLE_METHODDEF
|
#ifndef OS_SET_HANDLE_INHERITABLE_METHODDEF
|
||||||
#define OS_SET_HANDLE_INHERITABLE_METHODDEF
|
#define OS_SET_HANDLE_INHERITABLE_METHODDEF
|
||||||
#endif /* !defined(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]*/
|
||||||
|
|
|
@ -12284,6 +12284,56 @@ error:
|
||||||
return NULL;
|
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"
|
#include "clinic/posixmodule.c.h"
|
||||||
|
|
||||||
|
@ -12484,6 +12534,7 @@ static PyMethodDef posix_methods[] = {
|
||||||
{"scandir", (PyCFunction)posix_scandir,
|
{"scandir", (PyCFunction)posix_scandir,
|
||||||
METH_VARARGS | METH_KEYWORDS,
|
METH_VARARGS | METH_KEYWORDS,
|
||||||
posix_scandir__doc__},
|
posix_scandir__doc__},
|
||||||
|
OS_FSPATH_METHODDEF
|
||||||
{NULL, NULL} /* Sentinel */
|
{NULL, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue