]> granicus.if.org Git - python/commitdiff
bpo-35942: Improve the error message if __fspath__ returns invalid types in path_conv...
authorPablo Galindo <Pablogsal@gmail.com>
Mon, 18 Feb 2019 10:46:34 +0000 (10:46 +0000)
committerGitHub <noreply@github.com>
Mon, 18 Feb 2019 10:46:34 +0000 (10:46 +0000)
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.

Lib/test/test_os.py
Misc/NEWS.d/next/Core and Builtins/2019-02-18-09-30-55.bpo-35942.oLhL2v.rst [new file with mode: 0644]
Modules/posixmodule.c

index b7e1c45c79993e40b40a55cb295f53f9ec1faca7..d478c64038c2d3ac7c50171683eeee8d5a4333a3 100644 (file)
@@ -3344,7 +3344,7 @@ class PathTConverterTests(unittest.TestCase):
                             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 @@ class PathTConverterTests(unittest.TestCase):
                             '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 (file)
index 0000000..6ad4c0d
--- /dev/null
@@ -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.
index 5995958fccd3faa4f3e6e26eea1d693f4069126f..05afe9efa188beea385185e64783231d1bb58ab1 100644 (file)
@@ -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) {