]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-101162: Forbid using issubclass() with GenericAlias as the 1st arg (GH-103369)
authorNikita Sobolev <mail@sobolevn.me>
Fri, 11 Aug 2023 19:12:11 +0000 (22:12 +0300)
committerGitHub <noreply@github.com>
Fri, 11 Aug 2023 19:12:11 +0000 (22:12 +0300)
Lib/test/test_typing.py
Misc/NEWS.d/next/Library/2023-04-08-12-43-52.gh-issue-101162.yOCd_J.rst [new file with mode: 0644]
Objects/abstract.c
Objects/genericaliasobject.c

index 0450a87577eceab6b28272edddf350a2e0df4115..fa39c7961979590578d9edead0b73489d350949f 100644 (file)
@@ -4091,6 +4091,22 @@ class GenericTests(BaseTestCase):
         with self.assertRaises(TypeError):
             C[()]
 
+    def test_generic_subclass_checks(self):
+        for typ in [list[int], List[int],
+                    tuple[int, str], Tuple[int, str],
+                    typing.Callable[..., None],
+                    collections.abc.Callable[..., None]]:
+            with self.subTest(typ=typ):
+                self.assertRaises(TypeError, issubclass, typ, object)
+                self.assertRaises(TypeError, issubclass, typ, type)
+                self.assertRaises(TypeError, issubclass, typ, typ)
+                self.assertRaises(TypeError, issubclass, object, typ)
+
+                # isinstance is fine:
+                self.assertTrue(isinstance(typ, object))
+                # but, not when the right arg is also a generic:
+                self.assertRaises(TypeError, isinstance, typ, typ)
+
     def test_init(self):
         T = TypeVar('T')
         S = TypeVar('S')
diff --git a/Misc/NEWS.d/next/Library/2023-04-08-12-43-52.gh-issue-101162.yOCd_J.rst b/Misc/NEWS.d/next/Library/2023-04-08-12-43-52.gh-issue-101162.yOCd_J.rst
new file mode 100644 (file)
index 0000000..e9fadc8
--- /dev/null
@@ -0,0 +1,2 @@
+Forbid using :func:`builtins.issubclass` with :class:`types.GenericAlias` as
+the first argument.
index b4edcec6007710274851ed37a5e1d4e1e8627a8d..c113364a88a26a264da6995e4e691371246d7934 100644 (file)
@@ -2812,7 +2812,7 @@ object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
         return -1;
     }
 
-    /* Probably never reached anymore. */
+    /* Can be reached when infinite recursion happens. */
     return recursive_issubclass(derived, cls);
 }
 
index df8873454aeb362cc687a8157981699a14d747f5..faf517b66b9350811f617ff81a694bc0ba3de518 100644 (file)
@@ -626,6 +626,7 @@ ga_vectorcall(PyObject *self, PyObject *const *args,
 
 static const char* const attr_exceptions[] = {
     "__class__",
+    "__bases__",
     "__origin__",
     "__args__",
     "__unpacked__",