Skip to content

Commit 0adbbff

Browse files
committed
Add tests
No members are added to protocol classes to simplify testing. `issubclass` can only check method members.
1 parent 521a6a5 commit 0adbbff

File tree

1 file changed

+65
-3
lines changed

1 file changed

+65
-3
lines changed

Lib/test/test_typing.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
from test.support import (
5353
captured_stderr, cpython_only, requires_docstrings, import_helper, run_code,
54-
EqualToForwardRef,
54+
subTests, EqualToForwardRef,
5555
)
5656
from test.typinganndata import (
5757
ann_module695, mod_generics_cache, _typed_dict_helper,
@@ -3885,8 +3885,8 @@ def meth(self): pass
38853885
self.assertIsNot(get_protocol_members(PR), P.__protocol_attrs__)
38863886

38873887
acceptable_extra_attrs = {
3888-
'_is_protocol', '_is_runtime_protocol', '__parameters__',
3889-
'__init__', '__annotations__', '__subclasshook__', '__annotate__',
3888+
'_is_protocol', '_is_runtime_protocol', '_is_deprecated_inherited_runtime_protocol',
3889+
'__parameters__', '__init__', '__annotations__', '__subclasshook__', '__annotate__',
38903890
'__annotations_cache__', '__annotate_func__',
38913891
}
38923892
self.assertLessEqual(vars(NonP).keys(), vars(C).keys() | acceptable_extra_attrs)
@@ -4458,6 +4458,68 @@ class P(Protocol):
44584458
with self.assertRaisesRegex(TypeError, "@runtime_checkable"):
44594459
isinstance(1, P)
44604460

4461+
@subTests(['check_obj', 'check_func'], ([42, isinstance], [frozenset, issubclass]))
4462+
def test_inherited_runtime_protocol_deprecated(self, check_obj, check_func):
4463+
"""See GH-132604."""
4464+
4465+
class BareProto(Protocol):
4466+
"""I am runtime uncheckable."""
4467+
4468+
@runtime_checkable
4469+
class RCProto1(Protocol):
4470+
"""I am runtime-checkable."""
4471+
4472+
@runtime_checkable
4473+
class RCProto3(BareProto, Protocol):
4474+
"""Bare -> explicit RC."""
4475+
4476+
class InheritedRCProto1(RCProto1, Protocol):
4477+
"""Bare, but runtime-checkability is "inherited"."""
4478+
4479+
@runtime_checkable
4480+
class RCProto2(InheritedRCProto1, Protocol):
4481+
"""Explicit RC -> inherited RC -> explicit RC."""
4482+
4483+
class InheritedRCProto2(RCProto3, Protocol):
4484+
"""Bare -> explicit RC -> inherited RC."""
4485+
4486+
class InheritedRCProto3(RCProto2, Protocol):
4487+
"""Explicit RC -> inherited RC -> explicit RC -> inherited RC."""
4488+
4489+
class Concrete1(BareProto):
4490+
pass
4491+
4492+
class Concrete2(InheritedRCProto3):
4493+
pass
4494+
4495+
class Concrete3(InheritedRCProto3):
4496+
pass
4497+
4498+
depr_message_re = (
4499+
r"<class .+\.InheritedRCProto\d'> isn't explicitly decorated "
4500+
r"with @runtime_checkable but it is used in issubclass\(\) or "
4501+
r"isinstance\(\). Instance and class checks can only be used with "
4502+
r"@runtime_checkable protocols. This may stop working in Python 3.20."
4503+
)
4504+
4505+
for inherited_runtime_proto in InheritedRCProto1, InheritedRCProto2, InheritedRCProto3:
4506+
with self.assertWarnsRegex(DeprecationWarning, depr_message_re):
4507+
isinstance(object(), inherited_runtime_proto)
4508+
4509+
# Don't warn for explicitly checkable protocols and concrete implementations.
4510+
with warnings.catch_warnings():
4511+
warnings.simplefilter("error", DeprecationWarning)
4512+
4513+
for explicit_runtime_proto in RCProto1, RCProto2, RCProto3, Concrete1, Concrete2, Concrete3:
4514+
isinstance(object(), explicit_runtime_proto)
4515+
4516+
# Don't warn for uncheckable protocols.
4517+
with warnings.catch_warnings():
4518+
warnings.simplefilter("error", DeprecationWarning)
4519+
4520+
with self.assertRaises(TypeError): # Self-test. Protocol below can't be runtime-checkable.
4521+
isinstance(object(), BareProto)
4522+
44614523
def test_super_call_init(self):
44624524
class P(Protocol):
44634525
x: int

0 commit comments

Comments
 (0)