Commit 09fbcd60 authored by Pablo Galindo's avatar Pablo Galindo Committed by GitHub

bpo-35942: Improve the error message if __fspath__ returns invalid types in...

bpo-35942: Improve the error message if __fspath__ returns invalid types in path_converter (GH-11831)

The error message emitted when returning invalid types from __fspath__ in interfaces that allow passing PathLike objects has been improved and now it does explain the origin of the error.
parent ac28147e
...@@ -3344,7 +3344,7 @@ class PathTConverterTests(unittest.TestCase): ...@@ -3344,7 +3344,7 @@ class PathTConverterTests(unittest.TestCase):
cleanup_fn(result) cleanup_fn(result)
with self.assertRaisesRegex( with self.assertRaisesRegex(
TypeError, 'should be string, bytes'): TypeError, 'to return str or bytes'):
fn(int_fspath, *extra_args) fn(int_fspath, *extra_args)
if allow_fd: if allow_fd:
...@@ -3357,6 +3357,23 @@ class PathTConverterTests(unittest.TestCase): ...@@ -3357,6 +3357,23 @@ class PathTConverterTests(unittest.TestCase):
'os.PathLike'): 'os.PathLike'):
fn(fd, *extra_args) fn(fd, *extra_args)
def test_path_t_converter_and_custom_class(self):
with self.assertRaisesRegex(
TypeError,
'__fspath__\(\) to return str or bytes, not int'
):
os.stat(FakePath(2))
with self.assertRaisesRegex(
TypeError,
'__fspath__\(\) to return str or bytes, not float'
):
os.stat(FakePath(2.34))
with self.assertRaisesRegex(
TypeError,
'__fspath__\(\) to return str or bytes, not object'
):
os.stat(FakePath(object()))
@unittest.skipUnless(hasattr(os, 'get_blocking'), @unittest.skipUnless(hasattr(os, 'get_blocking'),
'needs os.get_blocking() and os.set_blocking()') 'needs os.get_blocking() and os.set_blocking()')
......
The error message emmited when returning invalid types from ``__fspath__``
in interfaces that allow passing :class:`~os.PathLike` objects has been
improved and now it does explain the origin of the error.
...@@ -954,28 +954,35 @@ path_converter(PyObject *o, void *p) ...@@ -954,28 +954,35 @@ path_converter(PyObject *o, void *p)
if (!is_index && !is_buffer && !is_unicode && !is_bytes) { if (!is_index && !is_buffer && !is_unicode && !is_bytes) {
/* Inline PyOS_FSPath() for better error messages. */ /* Inline PyOS_FSPath() for better error messages. */
_Py_IDENTIFIER(__fspath__); _Py_IDENTIFIER(__fspath__);
PyObject *func = NULL; PyObject *func, *res;
func = _PyObject_LookupSpecial(o, &PyId___fspath__); func = _PyObject_LookupSpecial(o, &PyId___fspath__);
if (NULL == func) { if (NULL == func) {
goto error_format; goto error_format;
} }
/* still owns a reference to the original object */ res = _PyObject_CallNoArg(func);
Py_DECREF(o);
o = _PyObject_CallNoArg(func);
Py_DECREF(func); Py_DECREF(func);
if (NULL == o) { if (NULL == res) {
goto error_exit; goto error_exit;
} }
else if (PyUnicode_Check(o)) { else if (PyUnicode_Check(res)) {
is_unicode = 1; is_unicode = 1;
} }
else if (PyBytes_Check(o)) { else if (PyBytes_Check(res)) {
is_bytes = 1; is_bytes = 1;
} }
else { else {
goto error_format; PyErr_Format(PyExc_TypeError,
"expected %.200s.__fspath__() to return str or bytes, "
"not %.200s", Py_TYPE(o)->tp_name,
Py_TYPE(res)->tp_name);
Py_DECREF(res);
goto error_exit;
} }
/* still owns a reference to the original object */
Py_DECREF(o);
o = res;
} }
if (is_unicode) { if (is_unicode) {
......
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