Fix Python 3.14 compatibility for typing.Union annotations#2093
Fix Python 3.14 compatibility for typing.Union annotations#2093frenzymadness wants to merge 3 commits intodavidhalter:masterfrom
Conversation
In Python 3.14, typing.Union changed its repr from 'typing.Union[X, Y]' to 'X | Y' (PEP 604), breaking annotation inference. Changes: - Use getattr() instead of safe_getattr() for __module__ retrieval (getattr_static fails on Union types in Python 3.14) - Add fallback to typing.get_origin() when regex fails to match - Normalize Union display back to 'Union[X, Y]' format for consistency - Update test expectations for invalid annotation edge case in 3.14 Fixes: davidhalter#2064
|
The problem in the docs job is caused by |
|
Would you accept fixes for 3.15 here as well? |
- Fix getattr_static for Python 3.15 __dict__ GetSetDescriptorType
- Accept abs() parameter name change ('x' → 'number')
- Add Python 3.15 os module constants to test expectations
Fixes instance attribute introspection and stdlib changes in Python 3.15.
davidhalter
left a comment
There was a problem hiding this comment.
Thanks! Sorry for the review delay. I think the changes are mostly fine, but I want to review something manually.
| if safe_getattr(self._obj, '__module__', default='') == 'typing': | ||
| # Use getattr instead of safe_getattr for __module__ as getattr_static | ||
| # fails on typing types in Python 3.14+ | ||
| module = getattr(self._obj, '__module__', '') |
There was a problem hiding this comment.
Hmm I need to look at this one in detail. I want to understand why safe_getattr doesn't work. We might need some fixes. Also safe_getattr solves a few other problems of code executions that I would want to avoid, but since it's only accessing __module__ it might be mostly fine (except for __getattr__ cases).
DO you know why __module__ is not working anymore?
There was a problem hiding this comment.
I already kinda lost the context here, but AFAIR: in Python 3.14, the typing module's internal implementation changed. The __module__ attribute on Union types is no longer accessible through the static inspection mechanism that getattr_static() uses.
There was a problem hiding this comment.
Hmm that's fine. I guess I'll take a stab at it then. This function seems cursed anyway. Why are we matching with regex? Nobody seems to know anymore. This probably comes from a time where some of the typing API wasn't available or very different.
|
I don't mind fixing things for 3.15 in here. |
|
I've pushed the commit I had prepared for 3.15. |
davidhalter
left a comment
There was a problem hiding this comment.
I guess probably just revert the test change that makes it worse for 3.14 and then I can try to fix that one. I don't think it will take too much time.
| {'return': 'typing.Union["str", 1]'}, | ||
| ['str'] if (3, 11) <= sys.version_info < (3, 14) else [], | ||
| '', | ||
| ), |
There was a problem hiding this comment.
>>> import typing
>>> x = typing.Union["str", 1]
>>> x.__args__
(ForwardRef('str'), 1)
Also a small nit: I generally prefer to keep the formatting as is. Especially here where all the other cases have this style. I don't think I would have said anything if I didn't look at this in more detail (Might also be an auto formatter, that did this, but still)
There was a problem hiding this comment.
There is a job in the CI here running flake8 and that failed with:
test/test_api/test_interpreter.py:667:101: E501 line too long (102 > 100 characters)
I can revert the commit if you are okay with merging PRs with failed tests like this.
There was a problem hiding this comment.
No worries, I'll just build upon this PR
| if safe_getattr(self._obj, '__module__', default='') == 'typing': | ||
| # Use getattr instead of safe_getattr for __module__ as getattr_static | ||
| # fails on typing types in Python 3.14+ | ||
| module = getattr(self._obj, '__module__', '') |
There was a problem hiding this comment.
Hmm that's fine. I guess I'll take a stab at it then. This function seems cursed anyway. Why are we matching with regex? Nobody seems to know anymore. This probably comes from a time where some of the typing API wasn't available or very different.
In Python 3.14, typing.Union changed its repr from 'typing.Union[X, Y]' to 'X | Y' (PEP 604), breaking annotation inference.
Changes:
Fixes: #2064
It works for me on Python 3.12, 3.13, and 3.14.