Skip to content

Commit c3dc681

Browse files
authored
Make sure that ReadOnly is removed when using get_type_hints(include_extra=False) (#349)
1 parent 2d74216 commit c3dc681

File tree

4 files changed

+26
-3
lines changed

4 files changed

+26
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Release 4.11.0 (WIP)
2+
3+
- When `include_extra=False`, `get_type_hints()` now strips `ReadOnly` from the annotation.
4+
15
# Release 4.10.0 (February 24, 2024)
26

37
This feature release adds support for PEP 728 (TypedDict with extra

doc/index.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,11 @@ Functions
760760

761761
Interaction with :data:`Required` and :data:`NotRequired`.
762762

763+
.. versionchanged:: 4.11.0
764+
765+
When ``include_extra=False``, ``get_type_hints()`` now strips
766+
:data:`ReadOnly` from the annotation.
767+
763768
.. function:: is_protocol(tp)
764769

765770
Determine if a type is a :class:`Protocol`. This works with protocols

src/test_typing_extensions.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4199,6 +4199,20 @@ class AllTheThings(TypedDict):
41994199
self.assertEqual(AllTheThings.__readonly_keys__, frozenset({'a', 'b', 'c'}))
42004200
self.assertEqual(AllTheThings.__mutable_keys__, frozenset({'d'}))
42014201

4202+
self.assertEqual(
4203+
get_type_hints(AllTheThings, include_extras=False),
4204+
{'a': int, 'b': int, 'c': int, 'd': int},
4205+
)
4206+
self.assertEqual(
4207+
get_type_hints(AllTheThings, include_extras=True),
4208+
{
4209+
'a': Annotated[Required[ReadOnly[int]], 'why not'],
4210+
'b': Required[Annotated[ReadOnly[int], 'why not']],
4211+
'c': ReadOnly[NotRequired[Annotated[int, 'why not']]],
4212+
'd': NotRequired[Annotated[int, 'why not']],
4213+
},
4214+
)
4215+
42024216
def test_extra_keys_non_readonly(self):
42034217
class Base(TypedDict, closed=True):
42044218
__extra_items__: str

src/typing_extensions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,15 +1122,15 @@ def greet(name: str) -> None:
11221122
return val
11231123

11241124

1125-
if hasattr(typing, "Required"): # 3.11+
1125+
if hasattr(typing, "ReadOnly"): # 3.13+
11261126
get_type_hints = typing.get_type_hints
1127-
else: # <=3.10
1127+
else: # <=3.13
11281128
# replaces _strip_annotations()
11291129
def _strip_extras(t):
11301130
"""Strips Annotated, Required and NotRequired from a given type."""
11311131
if isinstance(t, _AnnotatedAlias):
11321132
return _strip_extras(t.__origin__)
1133-
if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired):
1133+
if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly):
11341134
return _strip_extras(t.__args__[0])
11351135
if isinstance(t, typing._GenericAlias):
11361136
stripped_args = tuple(_strip_extras(a) for a in t.__args__)

0 commit comments

Comments
 (0)