GeezerVison is showing github.com — gh-104935: typing: Fix interactions between `@runtime_checkable` and … · python/cpython@70cc4e5
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: Lib/test/test_typing.py +42Lines changed: 42 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -2472,6 +2472,48 @@ def f(): | 2472 | 2472 | self.assertNotIsSubclass(types.FunctionType, P) | 2473 | 2473 | self.assertNotIsInstance(f, P) | 2474 | 2474 |
| | 2475 | + def test_runtime_checkable_generic_non_protocol(self): | | 2476 | + # Make sure this doesn't raise AttributeError | | 2477 | + with self.assertRaisesRegex( | | 2478 | + TypeError, | | 2479 | + "@runtime_checkable can be only applied to protocol classes", | | 2480 | + ): | | 2481 | + @runtime_checkable | | 2482 | + class Foo[T]: ... | | 2483 | + | | 2484 | + def test_runtime_checkable_generic(self): | | 2485 | + @runtime_checkable | | 2486 | + class Foo[T](Protocol): | | 2487 | + def meth(self) -> T: ... | | 2488 | + | | 2489 | + class Impl: | | 2490 | + def meth(self) -> int: ... | | 2491 | + | | 2492 | + self.assertIsSubclass(Impl, Foo) | | 2493 | + | | 2494 | + class NotImpl: | | 2495 | + def method(self) -> int: ... | | 2496 | + | | 2497 | + self.assertNotIsSubclass(NotImpl, Foo) | | 2498 | + | | 2499 | + def test_pep695_generics_can_be_runtime_checkable(self): | | 2500 | + @runtime_checkable | | 2501 | + class HasX(Protocol): | | 2502 | + x: int | | 2503 | + | | 2504 | + class Bar[T]: | | 2505 | + x: T | | 2506 | + def __init__(self, x): | | 2507 | + self.x = x | | 2508 | + | | 2509 | + class Capybara[T]: | | 2510 | + y: str | | 2511 | + def __init__(self, y): | | 2512 | + self.y = y | | 2513 | + | | 2514 | + self.assertIsInstance(Bar(1), HasX) | | 2515 | + self.assertNotIsInstance(Capybara('a'), HasX) | | 2516 | + | 2475 | 2517 | def test_everything_implements_empty_protocol(self): | 2476 | 2518 | @runtime_checkable | 2477 | 2519 | class Empty(Protocol): | |
Collapse file Copy file name to clipboardExpand all lines: Lib/typing.py +3-3Lines changed: 3 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1899,7 +1899,7 @@ def _proto_hook(other): | 1899 | 1899 | annotations = getattr(base, '__annotations__', {}) | 1900 | 1900 | if (isinstance(annotations, collections.abc.Mapping) and | 1901 | 1901 | attr in annotations and | 1902 | | - issubclass(other, Generic) and other._is_protocol): | | 1902 | + issubclass(other, Generic) and getattr(other, '_is_protocol', False)): | 1903 | 1903 | break | 1904 | 1904 | else: | 1905 | 1905 | return NotImplemented | @@ -1917,7 +1917,7 @@ def _proto_hook(other): | 1917 | 1917 | if not (base in (object, Generic) or | 1918 | 1918 | base.__module__ in _PROTO_ALLOWLIST and | 1919 | 1919 | base.__name__ in _PROTO_ALLOWLIST[base.__module__] or | 1920 | | - issubclass(base, Generic) and base._is_protocol): | | 1920 | + issubclass(base, Generic) and getattr(base, '_is_protocol', False)): | 1921 | 1921 | raise TypeError('Protocols can only inherit from other' | 1922 | 1922 | ' protocols, got %r' % base) | 1923 | 1923 | if cls.__init__ is Protocol.__init__: | @@ -2064,7 +2064,7 @@ def close(self): ... | 2064 | 2064 | Warning: this will check only the presence of the required methods, | 2065 | 2065 | not their type signatures! | 2066 | 2066 | """ | 2067 | | - if not issubclass(cls, Generic) or not cls._is_protocol: | | 2067 | + if not issubclass(cls, Generic) or not getattr(cls, '_is_protocol', False): | 2068 | 2068 | raise TypeError('@runtime_checkable can be only applied to protocol classes,' | 2069 | 2069 | ' got %r' % cls) | 2070 | 2070 | cls._is_runtime_protocol = True | |
Collapse file Copy file name to clipboard +3Lines changed: 3 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +Fix bugs with the interaction between :func:`typing.runtime_checkable` and | | 2 | +:class:`typing.Generic` that were introduced by the :pep:`695` | | 3 | +implementation. Patch by Jelle Zijlstra. |
|