From 0780d1c73bc1ab13c145c92ad85a892fc606eaf3 Mon Sep 17 00:00:00 2001 From: Ben Hsing Date: Wed, 29 May 2024 10:18:53 +0000 Subject: [PATCH 1/5] gh-116093: ABCMeta.__subclasscheck__ now initializes cls if it is not already initialized --- Lib/_py_abc.py | 8 ++++--- Lib/test/test_abc.py | 56 ++++++++++++++++++++++++++++++++++++++++++++ Modules/_abc.c | 10 ++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/Lib/_py_abc.py b/Lib/_py_abc.py index c870ae9048b4f1..291d4bfa756f8d 100644 --- a/Lib/_py_abc.py +++ b/Lib/_py_abc.py @@ -32,8 +32,7 @@ class ABCMeta(type): # external code. _abc_invalidation_counter = 0 - def __new__(mcls, name, bases, namespace, /, **kwargs): - cls = super().__new__(mcls, name, bases, namespace, **kwargs) + def __init__(cls, name, bases, namespace, /, **kwargs): # Compute set of abstract method names abstracts = {name for name, value in namespace.items() @@ -49,7 +48,6 @@ def __new__(mcls, name, bases, namespace, /, **kwargs): cls._abc_cache = WeakSet() cls._abc_negative_cache = WeakSet() cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter - return cls def register(cls, subclass): """Register a virtual subclass of an ABC. @@ -91,6 +89,8 @@ def _abc_caches_clear(cls): def __instancecheck__(cls, instance): """Override for isinstance(instance, cls).""" + if '_abc_cache' not in cls.__dict__: + cls.__class__.__init__(cls, cls.__name__, cls.__bases__, cls.__dict__) # Inline the cache checking subclass = instance.__class__ if subclass in cls._abc_cache: @@ -107,6 +107,8 @@ def __instancecheck__(cls, instance): def __subclasscheck__(cls, subclass): """Override for issubclass(subclass, cls).""" + if '_abc_cache' not in cls.__dict__: + cls.__class__.__init__(cls, cls.__name__, cls.__bases__, cls.__dict__) if not isinstance(subclass, type): raise TypeError('issubclass() arg 1 must be a class') # Check cache diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index 5ce57cc209ea85..439cbb56339962 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -682,6 +682,62 @@ class B(A, metaclass=abc_ABCMeta, name="test"): pass self.assertEqual(saved_kwargs, dict(name="test")) + + def test_subclasscheck_in_init_subclass1(self): + # test for gh-82266 + class A(metaclass=abc_ABCMeta): + pass + + class B(metaclass=abc_ABCMeta): + def __init_subclass__(cls): + assert not issubclass(cls, A) + + class C(A): + pass + + try: + class AB(A, B): + pass + except Exception: + pass + + self.assertTrue(issubclass(C, A)) + self.assertFalse(issubclass(C, B)) + + def test_subclasscheck_in_init_subclass2(self): + # test for gh-116093 + class A(metaclass=abc_ABCMeta): + pass + + class B(metaclass=abc_ABCMeta): + def __init_subclass__(cls, **kwargs): + super().__init_subclass__() + issubclass(A, A) + issubclass(A, B) + + class AB(A, B): + pass + + self.assertFalse(issubclass(A, B)) + + def test_subclasscheck_in_init_subclass3(self): + # test for gh-119699 + class A(metaclass=abc_ABCMeta): + pass + + class B(A): + def __init_subclass__(cls, **kwargs): + super().__init_subclass__() + issubclass(B, C) + + class C(A): + pass + + class BC(B, C): + pass + + self.assertTrue(issubclass(B, B)) + return TestLegacyAPI, TestABC, TestABCWithInitSubclass TestLegacyAPI_Py, TestABC_Py, TestABCWithInitSubclass_Py = test_factory(abc.ABCMeta, diff --git a/Modules/_abc.c b/Modules/_abc.c index 4f4b24b035db4a..4476655205ca1e 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -621,6 +621,11 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self, if (impl == NULL) { return NULL; } + PyObject *dict = _PyType_GetDict(self); + if (!PyDict_Contains(dict, &_Py_ID(_abc_impl))) { + _abc__abc_init(module, self); + impl = _get_impl(module, self); + } subclass = PyObject_GetAttr(instance, &_Py_ID(__class__)); if (subclass == NULL) { @@ -715,6 +720,11 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, if (impl == NULL) { return NULL; } + PyObject *dict = _PyType_GetDict(self); + if (!PyDict_Contains(dict, &_Py_ID(_abc_impl))) { + _abc__abc_init(module, self); + impl = _get_impl(module, self); + } /* 1. Check cache. */ incache = _in_weak_set(impl, &impl->_abc_cache, subclass); From 251c97919b89c6600a519827c7283aa627f81282 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 10:33:04 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst diff --git a/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst b/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst new file mode 100644 index 00000000000000..ef81b62d8b8f3e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst @@ -0,0 +1 @@ +Fixed an issue with `ABCMeta.__subclasscheck__` where it can be called within `__init_subclass__` before the subclass is initialized with the necessary ABC cache. From 1d7fd81f72050376b38ebda017297fc9e354d50c Mon Sep 17 00:00:00 2001 From: Ben Hsing Date: Wed, 29 May 2024 10:38:13 +0000 Subject: [PATCH 3/5] fixed blurb --- .../next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst b/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst index ef81b62d8b8f3e..21d38c54315c35 100644 --- a/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst +++ b/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst @@ -1 +1 @@ -Fixed an issue with `ABCMeta.__subclasscheck__` where it can be called within `__init_subclass__` before the subclass is initialized with the necessary ABC cache. +Fixed an issue with ``ABCMeta.__subclasscheck__`` where it can be called within ``__init_subclass__`` before the subclass is initialized with the necessary ABC cache. From 32c9ad5ef17d287a163076046b1003b4ce1dd8a0 Mon Sep 17 00:00:00 2001 From: blhsing Date: Wed, 29 May 2024 19:53:25 +0800 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Kirill Podoprigora --- Modules/_abc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_abc.c b/Modules/_abc.c index 4476655205ca1e..fc00de68001d55 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -621,7 +621,7 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self, if (impl == NULL) { return NULL; } - PyObject *dict = _PyType_GetDict(self); + PyObject *dict = _PyType_GetDict((PyTypeObject *)self); if (!PyDict_Contains(dict, &_Py_ID(_abc_impl))) { _abc__abc_init(module, self); impl = _get_impl(module, self); @@ -720,7 +720,7 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, if (impl == NULL) { return NULL; } - PyObject *dict = _PyType_GetDict(self); + PyObject *dict = _PyType_GetDict((PyTypeObject *)self); if (!PyDict_Contains(dict, &_Py_ID(_abc_impl))) { _abc__abc_init(module, self); impl = _get_impl(module, self); From d65db4227a854c6cc9a37e6852356fd2a0ed1d6d Mon Sep 17 00:00:00 2001 From: blhsing Date: Wed, 18 Sep 2024 09:32:37 +0800 Subject: [PATCH 5/5] Update 2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst Made references to methods proper links in news. --- .../Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst b/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst index 21d38c54315c35..73da45a5984b6a 100644 --- a/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst +++ b/Misc/NEWS.d/next/Library/2024-05-29-10-32-59.gh-issue-116093.Gcb6Md.rst @@ -1 +1,2 @@ -Fixed an issue with ``ABCMeta.__subclasscheck__`` where it can be called within ``__init_subclass__`` before the subclass is initialized with the necessary ABC cache. +Fixed an issue with :meth:`~class.__subclasscheck__` where it can be called within :meth:`~object.__init_subclass__` before the subclass is initialized with the necessary ABC cache. +Patch by Ben Hsing pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy