mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
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.
This commit is contained in:
parent
ac28147e78
commit
09fbcd6085
3 changed files with 36 additions and 9 deletions
|
@ -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):
|
||||||
'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()')
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
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)
|
||||||
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) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue