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

Pablo Galindo webhook-mailer at python.org
Mon Feb 18 05:46:49 EST 2019


https://github.com/python/cpython/commit/09fbcd6085e18b534fd4161844ff39f77eb4a082
commit: 09fbcd6085e18b534fd4161844ff39f77eb4a082
branch: master
author: Pablo Galindo <Pablogsal at gmail.com>
committer: GitHub <noreply at github.com>
date: 2019-02-18T10:46:34Z
summary:

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.

files:
A Misc/NEWS.d/next/Core and Builtins/2019-02-18-09-30-55.bpo-35942.oLhL2v.rst
M Lib/test/test_os.py
M Modules/posixmodule.c

diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index b7e1c45c7999..d478c64038c2 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -3344,7 +3344,7 @@ def test_path_t_converter(self):
                             cleanup_fn(result)
 
                 with self.assertRaisesRegex(
-                        TypeError, 'should be string, bytes'):
+                        TypeError, 'to return str or bytes'):
                     fn(int_fspath, *extra_args)
 
                 if allow_fd:
@@ -3357,6 +3357,23 @@ def test_path_t_converter(self):
                             'os.PathLike'):
                         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'),
                      'needs os.get_blocking() and os.set_blocking()')
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-02-18-09-30-55.bpo-35942.oLhL2v.rst b/Misc/NEWS.d/next/Core and Builtins/2019-02-18-09-30-55.bpo-35942.oLhL2v.rst
new file mode 100644
index 000000000000..6ad4c0df2a81
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-02-18-09-30-55.bpo-35942.oLhL2v.rst	
@@ -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.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 5995958fccd3..05afe9efa188 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -954,28 +954,35 @@ path_converter(PyObject *o, void *p)
     if (!is_index && !is_buffer && !is_unicode && !is_bytes) {
         /* Inline PyOS_FSPath() for better error messages. */
         _Py_IDENTIFIER(__fspath__);
-        PyObject *func = NULL;
+        PyObject *func, *res;
 
         func = _PyObject_LookupSpecial(o, &PyId___fspath__);
         if (NULL == func) {
             goto error_format;
         }
-        /* still owns a reference to the original object */
-        Py_DECREF(o);
-        o = _PyObject_CallNoArg(func);
+        res = _PyObject_CallNoArg(func);
         Py_DECREF(func);
-        if (NULL == o) {
+        if (NULL == res) {
             goto error_exit;
         }
-        else if (PyUnicode_Check(o)) {
+        else if (PyUnicode_Check(res)) {
             is_unicode = 1;
         }
-        else if (PyBytes_Check(o)) {
+        else if (PyBytes_Check(res)) {
             is_bytes = 1;
         }
         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) {



More information about the Python-checkins mailing list