Skip to content

Commit

Permalink
pythongh-106046: Improve error message from os.fspath if `__fspath_…
Browse files Browse the repository at this point in the history
…_` is set to `None`
  • Loading branch information
AlexWaygood committed Jun 25, 2023
1 parent 8c24a83 commit 3ec02c8
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 7 deletions.
6 changes: 6 additions & 0 deletions Lib/os.py
Expand Up @@ -1061,6 +1061,12 @@ def _fspath(path):
else:
raise TypeError("expected str, bytes or os.PathLike object, "
"not " + path_type.__name__)
except TypeError:
if path_type.__fspath__ is None:
raise TypeError("expected str, bytes or os.PathLike object, "
"not " + path_type.__name__) from None
else:
raise
if isinstance(path_repr, (str, bytes)):
return path_repr
else:
Expand Down
35 changes: 35 additions & 0 deletions Lib/test/test_os.py
Expand Up @@ -4647,6 +4647,41 @@ def __fspath__(self):
return ''
self.assertFalse(hasattr(A(), '__dict__'))

def test_fspath_set_to_None(self):
class Foo:
__fspath__ = None

class Bar:
def __fspath__(self):
return 'bar'

class Baz(Bar):
__fspath__ = None

good_error_msg = (
r"((expected)|(should be)) str, bytes or os.PathLike( object)?, not {}".format
)

with self.assertRaisesRegex(TypeError, good_error_msg("Foo")):
self.fspath(Foo())

self.assertEqual(self.fspath(Bar()), 'bar')

with self.assertRaisesRegex(TypeError, good_error_msg("Baz")):
self.fspath(Baz())

with self.assertRaisesRegex(TypeError, good_error_msg("Foo")):
open(Foo())

with self.assertRaisesRegex(TypeError, good_error_msg("Baz")):
open(Baz())

with self.assertRaisesRegex(TypeError, good_error_msg("Foo")):
os.rename(Foo(), "foooo")

with self.assertRaisesRegex(TypeError, good_error_msg("Baz")):
os.rename(Baz(), "bazzz")

class TimesTests(unittest.TestCase):
def test_times(self):
times = os.times()
Expand Down
@@ -0,0 +1,2 @@
Improve the error message from :func:`os.fspath` if called on an object
where ``__fspath__`` is set to ``None``. Patch by Alex Waygood.
14 changes: 7 additions & 7 deletions Modules/posixmodule.c
Expand Up @@ -1197,7 +1197,7 @@ path_converter(PyObject *o, void *p)
PyObject *func, *res;

func = _PyObject_LookupSpecial(o, &_Py_ID(__fspath__));
if (NULL == func) {
if ((NULL == func) || (func == Py_None)) {
goto error_format;
}
res = _PyObject_CallNoArgs(func);
Expand Down Expand Up @@ -1271,11 +1271,11 @@ path_converter(PyObject *o, void *p)
path->function_name ? path->function_name : "",
path->function_name ? ": " : "",
path->argument_name ? path->argument_name : "path",
path->allow_fd && path->nullable ? "string, bytes, os.PathLike, "
"integer or None" :
path->allow_fd ? "string, bytes, os.PathLike or integer" :
path->nullable ? "string, bytes, os.PathLike or None" :
"string, bytes or os.PathLike",
path->allow_fd && path->nullable ? "str, bytes, os.PathLike, "
"int or None" :
path->allow_fd ? "str, bytes, os.PathLike or int" :
path->nullable ? "str, bytes, os.PathLike or None" :
"str, bytes or os.PathLike",
_PyType_Name(Py_TYPE(o)));
goto error_exit;
}
Expand Down Expand Up @@ -15430,7 +15430,7 @@ PyOS_FSPath(PyObject *path)
}

func = _PyObject_LookupSpecial(path, &_Py_ID(__fspath__));
if (NULL == func) {
if ((NULL == func) || (func == Py_None)) {
return PyErr_Format(PyExc_TypeError,
"expected str, bytes or os.PathLike object, "
"not %.200s",
Expand Down

0 comments on commit 3ec02c8

Please sign in to comment.