Skip to content

gh-111353: GenericAlias support and TypeVarLike resolution for typing.get_type_hints #111515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

NCPlayz
Copy link

@NCPlayz NCPlayz commented Oct 30, 2023

get_type_hints can now resolve TypeVarLikes correctly for all generic classes, including TypedDicts.
There were a lot of edge cases that I tested and subsequently wrote unit tests for.
I've also split some pre-existing code in the typing library into their own utility functions (_copy_with to work for copying any generic type with new params and _make_substitution from _GenericAlias._make_substitution).

I've tried my hardest to document each step but please let me know if there are any steps that don't make sense or could be written another way.

@bedevere-app
Copy link

bedevere-app bot commented Oct 30, 2023

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@NCPlayz NCPlayz force-pushed the get_type_hints-generic-alias-support branch from 86f1624 to d122b0f Compare October 30, 2023 18:56
@Fidget-Spinner
Copy link
Member

Wow thank you for this large improvement! I'm sorry I'm not able to review this as it's been some time since I touched that specific code (I wrote some of it but I no longer remember its intricacies). I'll defer to the rest.

Thanks again. Your efforts are much appreciated!

@Fidget-Spinner Fidget-Spinner removed their request for review October 30, 2023 20:41
@zhPavel
Copy link

zhPavel commented Oct 30, 2023

I think there is a lack of tests and implementation for handling TypeVarTuple. I have added a comment to the original issue, which includes an implementation for this feature.

@NCPlayz
Copy link
Author

NCPlayz commented Oct 31, 2023

Thanks @zhPavel! I've implemented some preliminary support for TypeVarTuple, which seemed to work with the test cases I added. Though, I haven't really used TypeVarTuple too much so there may be some bits that are buggy, please let me know if you find anything!

@NCPlayz NCPlayz changed the title gh-111353: GenericAlias support and TypeVar resolution for typing.get_type_hints gh-111353: GenericAlias support and TypeVarLike resolution for typing.get_type_hints Oct 31, 2023
@ermakov-oleg
Copy link

Thank you so much for your work on this. It's truly an essential addition that's been missing from the standard library.

While testing this PR, I stumbled upon a scenario where get_type_hints throws an error when used with TypedDict + Generic + Annotated:

def test_get_type_hints_annotated_generic_typeddict(self):
    class Foo(TypedDict, Generic[T]):
        a: T
        b: Annotated[str, 'annotation']

    self.assertEqual(get_type_hints(Foo[bool]), {'a': bool, 'b': str})

The error I encountered is as follows:

Traceback (most recent call last):
  File "/Users/.../cpython/Lib/test/test_typing.py", line 6482, in test_get_type_hints_annotated_generic_typeddict
    self.assertEqual(get_type_hints(Foo[bool]), {'a': bool, 'b': str})
                     ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../cpython/Lib/typing.py", line 2220, in get_type_hints
    to_sub = _substitute_type_hints(param_tracking[obj], hints)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../cpython/Lib/typing.py", line 2414, in _substitute_type_hints
    sub = _copy_with(value, new_args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../cpython/Lib/typing.py", line 387, in _copy_with
    return t.copy_with(new_args)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../cpython/Lib/typing.py", line 1969, in copy_with
    assert len(params) == 1
           ^^^^^^^^^^^^^^^^
AssertionError

@ermakov-oleg
Copy link

And one more example with an error:

def test_get_type_hints_unbound_typevar(self):
    class Foo(Generic[T]):
        x: list[T]
        y: KT

    self.assertEqual(gth(Foo), {'x': list[T], 'y': KT})  # ok
    self.assertEqual(gth(Foo[int]), {'x': list[int], 'y': KT})    # error

Error:

Traceback (most recent call last):
  File "/Users/.../cpython/Lib/test/test_typing.py", line 6571, in test_get_type_hints_extended_generic_rules_subclassing_with_generic
    self.assertEqual(gth(Foo[int]), {'x': list[int], 'y': KT})    # error
                     ^^^^^^^^^^^^^
  File "/Users/.../cpython/Lib/typing.py", line 2220, in get_type_hints
    to_sub = _substitute_type_hints(param_tracking[obj], hints)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../cpython/Lib/typing.py", line 2416, in _substitute_type_hints
    sub = mapping[value]
          ~~~~~~~^^^^^^^
KeyError: ~KT

@gvanrossum gvanrossum removed their request for review May 20, 2024 20:47
Copy link
Member

@JelleZijlstra JelleZijlstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, but I think this doesn't need to go into CPython.

I'd prefer to limit CPython's introspection support to the minimum required for third-party packages to access typing metadata in a safe, portable way. This limits the surface area we have to maintain and enables third-party tools to provide support across many Python versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants