Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 410ef8e

Browse files
committed
issue27186: add C version of os.fspath(); patch by Jelle Zijlstra
1 parent c55014f commit 410ef8e

6 files changed

Lines changed: 125 additions & 18 deletions

File tree

Include/Python.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
#include "pylifecycle.h"
117117
#include "ceval.h"
118118
#include "sysmodule.h"
119+
#include "osmodule.h"
119120
#include "intrcheck.h"
120121
#include "import.h"
121122

Include/osmodule.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
/* os module interface */
3+
4+
#ifndef Py_OSMODULE_H
5+
#define Py_OSMODULE_H
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
PyAPI_FUNC(PyObject *) PyOS_FSPath(PyObject *path);
11+
12+
#ifdef __cplusplus
13+
}
14+
#endif
15+
#endif /* !Py_OSMODULE_H */

Lib/os.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,23 +1104,24 @@ def fdopen(fd, *args, **kwargs):
11041104
import io
11051105
return io.open(fd, *args, **kwargs)
11061106

1107-
# Supply os.fspath()
1108-
def fspath(path):
1109-
"""Return the string representation of the path.
1107+
# Supply os.fspath() if not defined in C
1108+
if not _exists('fspath'):
1109+
def fspath(path):
1110+
"""Return the string representation of the path.
11101111
1111-
If str or bytes is passed in, it is returned unchanged.
1112-
"""
1113-
if isinstance(path, (str, bytes)):
1114-
return path
1112+
If str or bytes is passed in, it is returned unchanged.
1113+
"""
1114+
if isinstance(path, (str, bytes)):
1115+
return path
11151116

1116-
# Work from the object's type to match method resolution of other magic
1117-
# methods.
1118-
path_type = type(path)
1119-
try:
1120-
return path_type.__fspath__(path)
1121-
except AttributeError:
1122-
if hasattr(path_type, '__fspath__'):
1123-
raise
1117+
# Work from the object's type to match method resolution of other magic
1118+
# methods.
1119+
path_type = type(path)
1120+
try:
1121+
return path_type.__fspath__(path)
1122+
except AttributeError:
1123+
if hasattr(path_type, '__fspath__'):
1124+
raise
11241125

1125-
raise TypeError("expected str, bytes or os.PathLike object, not "
1126-
+ path_type.__name__)
1126+
raise TypeError("expected str, bytes or os.PathLike object, not "
1127+
+ path_type.__name__)

Lib/test/test_os.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3121,6 +3121,13 @@ def __fspath__(self):
31213121
self.assertEqual(b"path/like/object", os.fsencode(pathlike))
31223122
self.assertEqual("path/like/object", os.fsdecode(pathlike))
31233123

3124+
def test_fspathlike(self):
3125+
class PathLike(object):
3126+
def __fspath__(self):
3127+
return '#feelthegil'
3128+
3129+
self.assertEqual('#feelthegil', os.fspath(PathLike()))
3130+
31243131
def test_garbage_in_exception_out(self):
31253132
vapor = type('blah', (), {})
31263133
for o in int, type, os, vapor():

Modules/clinic/posixmodule.c.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5321,6 +5321,38 @@ os_set_handle_inheritable(PyModuleDef *module, PyObject *args)
53215321

53225322
#endif /* defined(MS_WINDOWS) */
53235323

5324+
PyDoc_STRVAR(os_fspath__doc__,
5325+
"fspath($module, /, path)\n"
5326+
"--\n"
5327+
"\n"
5328+
"Return the file system path representation of the object.\n"
5329+
"\n"
5330+
"If the object is str or bytes, then allow it to pass through with\n"
5331+
"an incremented refcount. If the object defines __fspath__(), then\n"
5332+
"return the result of that method. All other types raise a TypeError.");
5333+
5334+
#define OS_FSPATH_METHODDEF \
5335+
{"fspath", (PyCFunction)os_fspath, METH_VARARGS|METH_KEYWORDS, os_fspath__doc__},
5336+
5337+
static PyObject *
5338+
os_fspath_impl(PyModuleDef *module, PyObject *path);
5339+
5340+
static PyObject *
5341+
os_fspath(PyModuleDef *module, PyObject *args, PyObject *kwargs)
5342+
{
5343+
PyObject *return_value = NULL;
5344+
static char *_keywords[] = {"path", NULL};
5345+
PyObject *path;
5346+
5347+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:fspath", _keywords,
5348+
&path))
5349+
goto exit;
5350+
return_value = os_fspath_impl(module, path);
5351+
5352+
exit:
5353+
return return_value;
5354+
}
5355+
53245356
#ifndef OS_TTYNAME_METHODDEF
53255357
#define OS_TTYNAME_METHODDEF
53265358
#endif /* !defined(OS_TTYNAME_METHODDEF) */
@@ -5792,4 +5824,4 @@ os_set_handle_inheritable(PyModuleDef *module, PyObject *args)
57925824
#ifndef OS_SET_HANDLE_INHERITABLE_METHODDEF
57935825
#define OS_SET_HANDLE_INHERITABLE_METHODDEF
57945826
#endif /* !defined(OS_SET_HANDLE_INHERITABLE_METHODDEF) */
5795-
/*[clinic end generated code: output=a5c9bef9ad11a20b input=a9049054013a1b77]*/
5827+
/*[clinic end generated code: output=e64e246b8270abda input=a9049054013a1b77]*/

Modules/posixmodule.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12284,6 +12284,56 @@ posix_scandir(PyObject *self, PyObject *args, PyObject *kwargs)
1228412284
return NULL;
1228512285
}
1228612286

12287+
/*
12288+
Return the file system path representation of the object.
12289+
12290+
If the object is str or bytes, then allow it to pass through with
12291+
an incremented refcount. If the object defines __fspath__(), then
12292+
return the result of that method. All other types raise a TypeError.
12293+
*/
12294+
PyObject *
12295+
PyOS_FSPath(PyObject *path)
12296+
{
12297+
_Py_IDENTIFIER(__fspath__);
12298+
PyObject *func = NULL;
12299+
PyObject *path_repr = NULL;
12300+
12301+
if (PyUnicode_Check(path) || PyBytes_Check(path)) {
12302+
Py_INCREF(path);
12303+
return path;
12304+
}
12305+
12306+
func = _PyObject_LookupSpecial(path, &PyId___fspath__);
12307+
if (NULL == func) {
12308+
return PyErr_Format(PyExc_TypeError,
12309+
"expected str, bytes or os.PathLike object, "
12310+
"not %S",
12311+
path->ob_type);
12312+
}
12313+
12314+
path_repr = PyObject_CallFunctionObjArgs(func, NULL);
12315+
Py_DECREF(func);
12316+
return path_repr;
12317+
}
12318+
12319+
/*[clinic input]
12320+
os.fspath
12321+
12322+
path: object
12323+
12324+
Return the file system path representation of the object.
12325+
12326+
If the object is str or bytes, then allow it to pass through with
12327+
an incremented refcount. If the object defines __fspath__(), then
12328+
return the result of that method. All other types raise a TypeError.
12329+
[clinic start generated code]*/
12330+
12331+
static PyObject *
12332+
os_fspath_impl(PyModuleDef *module, PyObject *path)
12333+
/*[clinic end generated code: output=51ef0c2772c1932a input=652c7c37e4be1c13]*/
12334+
{
12335+
return PyOS_FSPath(path);
12336+
}
1228712337

1228812338
#include "clinic/posixmodule.c.h"
1228912339

@@ -12484,6 +12534,7 @@ static PyMethodDef posix_methods[] = {
1248412534
{"scandir", (PyCFunction)posix_scandir,
1248512535
METH_VARARGS | METH_KEYWORDS,
1248612536
posix_scandir__doc__},
12537+
OS_FSPATH_METHODDEF
1248712538
{NULL, NULL} /* Sentinel */
1248812539
};
1248912540

0 commit comments

Comments
 (0)