Skip to content

gh-130870 Fix _eval_type Handling for GenericAlias with Unflattened Arguments and Union Types - #130897

Closed
sharktide wants to merge 20 commits into
python:mainfrom
sharktide:patch-130870
Closed

gh-130870 Fix _eval_type Handling for GenericAlias with Unflattened Arguments and Union Types#130897
sharktide wants to merge 20 commits into
python:mainfrom
sharktide:patch-130870

Conversation

@sharktide

@sharktidesharktide commented Mar 5, 2025

Copy link
Copy Markdown
Contributor

Fixes the handling of GenericAlias types in _eval_type by correctly unflattening callable arguments when necessary. Also improves the resolution of Union types by evaluating their arguments properly.

Tests (View comments below):
#130897 (comment)

@bedevere-app

Copy link
Copy Markdown

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.

Comment threadMisc/NEWS.d/next/Library/2025-03-05-21-48-22.gh-issue-130870.uDz6AQ.rst Outdated
Comment threadLib/typing.py
@bedevere-app

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@sharktide

Copy link
Copy Markdown
ContributorAuthor

I have made the requested changes; please review again

@bedevere-app

Copy link
Copy Markdown

Thanks for making the requested changes!

@JelleZijlstra: please review the changes made to this pull request.

@sharktide

Copy link
Copy Markdown
ContributorAuthor

@JelleZijlstra

HI! Sorry to disturb you, but could you please re-review this pull request? TiA

@sharktide

Copy link
Copy Markdown
ContributorAuthor

@JelleZijlstra or @AlexWaygood Could you please check this PR again? It has been over a month I have been waiting.

@JelleZijlstra

Copy link
Copy Markdown
Member

The test cases don't use any public APIs so as far as I can see this PR doesn't change any behaviors that we care about.

@sharktide

sharktide commented Apr 12, 2025

Copy link
Copy Markdown
ContributorAuthor

The test cases don't use any public APIs so as far as I can see this PR doesn't change any behaviors that we care about.

@JelleZijlstra
While the changes might seem to address internal behaviors, They also contribute to more robust handling of GenericAlias and Union types within the _eval_type function (imo), ensuring that edge cases like callable argument unpacking and recursive type evaluation are properly managed. This improvement could indirectly enhance the reliability of features relying on these internal implementations.

It took me so long to write that :)

@sharktide

Copy link
Copy Markdown
ContributorAuthor

All of these tests still test only _eval_type, which is a private function and doesn't have any guaranteed behavior. Can you demonstrate that this fixes any operation that involves a public API?

@JelleZijlstra Please review again. I added new tests to demonstrate the behavior with a public api (get type hints). They passed.

Note: The fail of the Thread Sanatizer workflow is likely not due to this PR (asynicio test that failed)

@sharktide

Copy link
Copy Markdown
ContributorAuthor

@JelleZijlstra please review. I added the tests and everything works

the test fail is unrelated

@sharktide

Copy link
Copy Markdown
ContributorAuthor

@JelleZijlstra I think you forgot to review again. Please do get to it soon.

@JelleZijlstraJelleZijlstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The reason I've been slow to review this is that I feel I'll basically have to rewrite everything; it's still not clear to me what publicly visible behavior this is supposed to fix.

Start with writing a test case that fails today and that uses only public APIs (get_type_hints or get_args maybe, not _eval_type).

Comment threadLib/test/test_typing.py Outdated
class MyType:
pass

class TestGenericAliasHandling(BaseTestCase):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

All of these tests pass on master today without your changes in typing.py.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not the one I sent in the comments!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We shouldn't be adding tests that are unrelated to the change.

Comment threadLib/test/test_typing.py Outdated
Comment threadMisc/NEWS.d/next/Library/2025-03-05-21-48-22.gh-issue-130870.uDz6AQ.rst Outdated
@bedevere-app

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@sharktide

sharktide commented May 12, 2025

Copy link
Copy Markdown
ContributorAuthor

@JelleZijlstra You want a failing test? I'll give you a failing test:

classTestCallableAlias(BaseTestCase):
deftest_callable_alias_preserves_subclass(self):
C=ABCallable[[str, ForwardRef('int')], int]
classA:
c: C# Explicitly pass global namespace to ensure correct resolutionhints=get_type_hints(A, globalns=globals())
# Ensure evaluated type retains the correct subclass (_CallableGenericAlias)self.assertEqual(hints['c'].__class__, C.__class__)
# Ensure evaluated type retains correct originself.assertEqual(hints['c'].__origin__, C.__origin__)
# Instead of comparing raw ForwardRef, check if the resolution is correctexpected_args=tuple(intifisinstance(arg, ForwardRef) elseargforarginC.__args__)
self.assertEqual(hints['c'].__args__, expected_args)

Out without the fix: (Note that this was when I had f string assertionError messages. I removed them)

FAIL: test_callable_alias_preserves_subclass (__main__.TestCallableAlias.test_callable_alias_preserves_subclass)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\rihaan.meher\Documents\GitHub\cpython\zzz.py", line 30, in test_callable_alias_preserves_subclass
self.assertEqual(hints['c'].__class__, C.__class__, f"Expected {C.__class__}, got {hints['c'].__class__}")
AssertionError: <class 'types.GenericAlias'>!= <class 'collections.abc._CallableGenericAlias'>: Expected <class 'collections.abc._CallableGenericAlias'>, got <class 'types.GenericAlias'>

With my PR, this passes.

I added it to test_typing.py

Essentially what this PR does:

  • Preserving Type Information: If Callable is incorrectly converted to GenericAlias, it loses its subclass-specific behavior, which could affect type introspection and runtime checks.

  • Ensuring Correct Type Resolution: ForwardRef('int') should be properly resolved to int, maintaining expected behavior when evaluating type hints.

  • Preventing Silent Type Corruption: If Callable is mishandled, it could lead to unexpected behavior in libraries and applications relying on precise type annotations.

@sharktide

Copy link
Copy Markdown
ContributorAuthor

Test fails are unrelated: 504 gateway timeout in http/urllib tests

@sharktide

Copy link
Copy Markdown
ContributorAuthor

The reason I've been slow to review this is that I feel I'll basically have to rewrite everything; it's still not clear to me what publicly visible behavior this is supposed to fix.

Start with writing a test case that fails today and that uses only public APIs (get_type_hints or get_args maybe, not _eval_type).

Look at the comment I just posted

@sharktide

Copy link
Copy Markdown
ContributorAuthor

No reviewer action in at least 1mo —> @JelleZijlstra please review

@ZeroIntensityZeroIntensity left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree with Jelle: I don't think this PR is solving an actual problem. This will end up exposing implemenation details, like _CallableGenericAlias. In practice, why do users care about something like _CallableGenericAlias over the (public) GenericAlias?

Comment threadLib/test/test_typing.py Outdated
class MyType:
pass

class TestGenericAliasHandling(BaseTestCase):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We shouldn't be adding tests that are unrelated to the change.

@sharktide

Copy link
Copy Markdown
ContributorAuthor

I agree with Jelle: I don't think this PR is solving an actual problem. This will end up exposing implemenation details, like _CallableGenericAlias. In practice, why do users care about something like _CallableGenericAlias over the (public) GenericAlias?

Explained in issue

@sharktide

Copy link
Copy Markdown
ContributorAuthor

I have made the requested changes; please review again

@bedevere-app

Copy link
Copy Markdown

Thanks for making the requested changes!

@JelleZijlstra: please review the changes made to this pull request.

@JelleZijlstra

Copy link
Copy Markdown
Member

Superseded by #131583.

Sign up for freeto 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.

3 participants

@sharktide@JelleZijlstra@ZeroIntensity