Skip to content

Commit c40486a

Browse files
authored
bpo-38908: Fix issue when non runtime_protocol failed to raise TypeError (#26067)
1 parent 9b06e4b commit c40486a

File tree

3 files changed

+23
-2
lines changed

3 files changed

+23
-2
lines changed

Lib/test/test_typing.py

+8
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,14 @@ class CustomProtocol(TestCase, Protocol):
14221422
class CustomContextManager(typing.ContextManager, Protocol):
14231423
pass
14241424

1425+
def test_non_runtime_protocol_isinstance_check(self):
1426+
class P(Protocol):
1427+
x: int
1428+
1429+
with self.assertRaisesRegex(TypeError, "@runtime_checkable"):
1430+
isinstance(1, P)
1431+
1432+
14251433
class GenericTests(BaseTestCase):
14261434

14271435
def test_basics(self):

Lib/typing.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -1343,14 +1343,14 @@ def _no_init(self, *args, **kwargs):
13431343
raise TypeError('Protocols cannot be instantiated')
13441344

13451345

1346-
def _allow_reckless_class_checks():
1346+
def _allow_reckless_class_checks(depth=3):
13471347
"""Allow instance and class checks for special stdlib modules.
13481348
13491349
The abc and functools modules indiscriminately call isinstance() and
13501350
issubclass() on the whole MRO of a user class, which may contain protocols.
13511351
"""
13521352
try:
1353-
return sys._getframe(3).f_globals['__name__'] in ['abc', 'functools']
1353+
return sys._getframe(depth).f_globals['__name__'] in ['abc', 'functools']
13541354
except (AttributeError, ValueError): # For platforms without _getframe().
13551355
return True
13561356

@@ -1370,6 +1370,14 @@ class _ProtocolMeta(ABCMeta):
13701370
def __instancecheck__(cls, instance):
13711371
# We need this method for situations where attributes are
13721372
# assigned in __init__.
1373+
if (
1374+
getattr(cls, '_is_protocol', False) and
1375+
not getattr(cls, '_is_runtime_protocol', False) and
1376+
not _allow_reckless_class_checks(depth=2)
1377+
):
1378+
raise TypeError("Instance and class checks can only be used with"
1379+
" @runtime_checkable protocols")
1380+
13731381
if ((not getattr(cls, '_is_protocol', False) or
13741382
_is_callable_members_only(cls)) and
13751383
issubclass(instance.__class__, cls)):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix issue where :mod:`typing` protocols without the ``@runtime_checkable``
2+
decorator did not raise a ``TypeError`` when used with ``issubclass`` and
3+
``isinstance``. Now, subclassses of ``typing.Protocol`` will raise a
4+
``TypeError`` when used with with those checks.
5+
Patch provided by Yurii Karabas.

0 commit comments

Comments
 (0)