gh-105280: Ensure isinstance([], collections.abc.Mapping)
always evaluates to False
(#105281)
This commit is contained in:
parent
058b960535
commit
08756dbba6
@ -3,6 +3,7 @@ import collections
|
|||||||
import collections.abc
|
import collections.abc
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from functools import lru_cache, wraps
|
from functools import lru_cache, wraps
|
||||||
|
import gc
|
||||||
import inspect
|
import inspect
|
||||||
import itertools
|
import itertools
|
||||||
import pickle
|
import pickle
|
||||||
@ -2758,6 +2759,19 @@ class ProtocolTests(BaseTestCase):
|
|||||||
with self.assertRaisesRegex(TypeError, only_classes_allowed):
|
with self.assertRaisesRegex(TypeError, only_classes_allowed):
|
||||||
issubclass(1, BadPG)
|
issubclass(1, BadPG)
|
||||||
|
|
||||||
|
def test_isinstance_checks_not_at_whim_of_gc(self):
|
||||||
|
self.addCleanup(gc.enable)
|
||||||
|
gc.disable()
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
TypeError,
|
||||||
|
"Protocols can only inherit from other protocols"
|
||||||
|
):
|
||||||
|
class Foo(collections.abc.Mapping, Protocol):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertNotIsInstance([], collections.abc.Mapping)
|
||||||
|
|
||||||
def test_issubclass_and_isinstance_on_Protocol_itself(self):
|
def test_issubclass_and_isinstance_on_Protocol_itself(self):
|
||||||
class C:
|
class C:
|
||||||
def x(self): pass
|
def x(self): pass
|
||||||
|
@ -1771,6 +1771,25 @@ del _pickle_psargs, _pickle_pskwargs
|
|||||||
class _ProtocolMeta(ABCMeta):
|
class _ProtocolMeta(ABCMeta):
|
||||||
# This metaclass is somewhat unfortunate,
|
# This metaclass is somewhat unfortunate,
|
||||||
# but is necessary for several reasons...
|
# but is necessary for several reasons...
|
||||||
|
def __new__(mcls, name, bases, namespace, /, **kwargs):
|
||||||
|
if name == "Protocol" and bases == (Generic,):
|
||||||
|
pass
|
||||||
|
elif Protocol in bases:
|
||||||
|
for base in bases:
|
||||||
|
if not (
|
||||||
|
base in {object, Generic}
|
||||||
|
or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, [])
|
||||||
|
or (
|
||||||
|
issubclass(base, Generic)
|
||||||
|
and getattr(base, "_is_protocol", False)
|
||||||
|
)
|
||||||
|
):
|
||||||
|
raise TypeError(
|
||||||
|
f"Protocols can only inherit from other protocols, "
|
||||||
|
f"got {base!r}"
|
||||||
|
)
|
||||||
|
return super().__new__(mcls, name, bases, namespace, **kwargs)
|
||||||
|
|
||||||
def __init__(cls, *args, **kwargs):
|
def __init__(cls, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if getattr(cls, "_is_protocol", False):
|
if getattr(cls, "_is_protocol", False):
|
||||||
@ -1906,14 +1925,7 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
|
|||||||
if not cls._is_protocol:
|
if not cls._is_protocol:
|
||||||
return
|
return
|
||||||
|
|
||||||
# ... otherwise check consistency of bases, and prohibit instantiation.
|
# ... otherwise prohibit instantiation.
|
||||||
for base in cls.__bases__:
|
|
||||||
if not (base in (object, Generic) or
|
|
||||||
base.__module__ in _PROTO_ALLOWLIST and
|
|
||||||
base.__name__ in _PROTO_ALLOWLIST[base.__module__] or
|
|
||||||
issubclass(base, Generic) and getattr(base, '_is_protocol', False)):
|
|
||||||
raise TypeError('Protocols can only inherit from other'
|
|
||||||
' protocols, got %r' % base)
|
|
||||||
if cls.__init__ is Protocol.__init__:
|
if cls.__init__ is Protocol.__init__:
|
||||||
cls.__init__ = _no_init_or_replace_init
|
cls.__init__ = _no_init_or_replace_init
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
Fix bug where ``isinstance([], collections.abc.Mapping)`` could evaluate to
|
||||||
|
``True`` if garbage collection happened at the wrong time. The bug was
|
||||||
|
caused by changes to the implementation of :class:`typing.Protocol` in
|
||||||
|
Python 3.12.
|
Loading…
x
Reference in New Issue
Block a user