-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
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
gh-129463: gh-128593: Simplify ForwardRef #129465
base: main
Are you sure you want to change the base?
Conversation
if self.__cell__ is not None: | ||
try: | ||
value = self.__cell__.cell_contents | ||
except ValueError: | ||
pass | ||
else: | ||
self.__forward_evaluated__ = True | ||
self.__forward_value__ = value | ||
return value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this else
branch and just write: try: return self.__cell__.cell_contents
@@ -48,6 +48,7 @@ | |||
from test.test_inspect import inspect_fodder2 as mod2 | |||
from test.test_inspect import inspect_stringized_annotations | |||
from test.test_inspect import inspect_deferred_annotations | |||
from test.test_typing import EqualToForwardRef |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We try really hard to unwire different test cases, if possible - maybe it would be better to import this object from somewhere else?
Ho, ho... ho. @beartype maintainer @leycec has been summoned via #129463. As a born contrarian living in a cabin in the Canadian woods with too much time and too little sense, I have a lot of tiresome things to say about this and every other topic. Thankfully, nobody wants to hear it. I'll just pontificate about type hint smells instead. So Even Type Hints Smell Now, Huh?A type hint smell is the It's simple. Thus, it's maximally supported: from typing import TypeForm
def is_hints_smelly(hint_a: TypeForm, hint_b: TypeForm) -> bool:
'''
:data:`True` only if the passed type hints **smell** (i.e.,
are poorly designed in a manner suggesting catastrophic
failure by end users).
'''
return not (
(repr(hint_a) == repr(hint_b)) is
( hint_a == hint_b)
) There should thus exist a one-to-one correspondence between:
Two type hints that share the same string representation should thus either literally be the same type hint or compare equal to one another. Makes sense, right? In fact, this maxim makes so much sense that we can pretty much extend it to most object-oriented APIs. An API that violates this smell test isn't necessarily bad per say, but it is suggestive of badness. Nobody Cares About Your Suggestions, ThoughIn the case of type hints, this isn't quite a "suggestion." @beartype really wants this smell test to hold across all type hints. @beartype aggressively memoizes all internal calls on the basis of type hints and their string representations. Since all existing type hints satisfy the above smell test, they also memoize well out-of-the-box with respect to @beartype. The proof is in the tedious pudding. Pretend this matters: # Prove that the "list[int]" type hint isn't smelly.
>>> is_hints_smelly(list[int], list[int])
False # <-- good!
# Prove that the "Literal['smells', 'good']" type hint isn't smelly.
>>> is_hints_smelly(Literal['smells', 'good'], Literal['smells', 'good'])
False # <-- good!
# Prove that the "ForwardRef('muh_package.MuhType')" type hint isn't smelly.
>>> is_hints_smelly(ForwardRef('muh_package.MuhType'), ForwardRef('muh_package.MuhType'))
False # <-- good! So. We're agreed. Existing type hints don't smell. That's good... isn't it? 🤔 💭 💥 Would You Please Stop Talking AlreadyNo. I've warned you that I would pontificate! I intend to do just that. The proposed refactoring does simplify the existing implementation of The proposed refactoring also violates the above smell test. After merging this PR, So. You Admit You Are Willing to Do Something Then?No. I'm super-lazy! I just pontificate without writing code. Mostly. Actually, I lie. I casually inspected the Sure. CPython could diminish the real-world utility of forward references by gutting the I have a trivial proposal. It is trivial, because I just did it. If I can do it, literally anyone can do it. I live in a cabin in the woods, people. Let's just resolve the issue in the # This is what I'm a-sayin', folks.
def __hash__(self):
return hash(
(self.__forward_arg__, self.__forward_value__)
if self.__forward_evaluated__ else
(self.__forward_arg__, self.__forward_module__)
) Literally just two more lines of code. That's it. Of course... Python 3.14: It Is HellI acknowledge that Python 3.14 is coming. Indeed, Python 3.14 is almost here. Preserving the fragrant non-smelliness of Somebody? Anybody? Hellllllllllo? 😮💨 tl;dr: Let Us Fix a Thing Rather than Break a ThingThus spake @leycec. He don't know much, but he know a thing. This might be that thing. |
@leycec, keeping the caching mechanism through Also, I'm not sure trying to hash class A:
__hash__ = None
hash(Annotated[int, A()])
# TypeError
It seems to be that this was a bad assumption on your end, that is now causing an issue. I wouldn't rely on string representations for caching, even though it works for most type hints. |
I feel we should get rid of the value caching mechanism ( I'm more open to keeping |
Fixes #129463. Fixes #128593.
__hash__
and__eq__
#129463