Open JelleZijlstra opened 5 months ago
Thanks, I think I meant to say "in Python 3.14". Edited.
Hi everyone,
just wanted to share a (condensed) example where I had to use Forward references outside of type annotations, but in specific parameters of generics as below:
from typing import TypeVar, Generic
BaseClassType = TypeVar("BaseClassType")
class GenericClass(Generic[BaseClassType]):
def a_method(self) -> BaseClassType:
pass
class ConcreteClass(GenericClass["ConcreteFriendClass"]):
pass
GenericClassType = TypeVar("GenericClassType", bound=GenericClass)
class GenericFriendClass(Generic[GenericClassType]):
def a_method(self) -> GenericClassType:
pass
class ConcreteFriendClass(GenericFriendClass[ConcreteClass]):
pass
instance = ConcreteClass()
friend = ConcreteFriendClass()
res = instance.a_method()
Reason is, that ConcreteClass and ConcreteFriendClass are somehow coupled to each other from a business perspective. Not sure, the design is really great or could be improved, but what I want you guys to point you to is the statement of definition of Class ConcreteClass where the friend's class name is specified as forward reference. PyCharm is already able to correctly determine the type of variable res to be of ConcreteFriedClass - so it is at least ForwardReference-ish.
Question now, is this tbh quite corner case also in scope of the ticket, in that case I am glad to contribute above a test case. Just remove the Forward Reference in that line and it shall work. Or is it out of scope, maybe by a flaw of my own understanding or postponed to a later release etc.
EDIT: I just happened to realise that I can retrieve the type parameter at runtime in 3.12 and it turns out to be a Forward Reference
from typing import get_args, ForwardRef
from types import get_original_bases
assert ForwardRef("ConcreteFriendClass") == get_args(get_original_bases(ConcreteClass)[0])[0]
/EDIT
Happy to have a conversation on that.
Regards, Jens
@Jens-Dittrich your use case is already solved in Python 3.12, where PEP-695 provides a syntax for generic bounds that is lazily evaluated. If you have further questions, please post on https://discuss.python.org instead so we can keep this issue focused on implementing the Python 3.14 changes.
PEP-649 has been accepted and should be implemented in Python 3.14. Let's use this issue to track the implementation:
__annotate__
attributes #119209format
argument toinspect.get_annotations
#119891inspect.AnnotationsFormat
should be a "global enum". Is that desirable? TBD. https://github.com/python/cpython/pull/119361/files#r1614753031)from __future__ import annotations
; an introduction to annotationlib; an update to Larry's annotations HOWTOinspect
. (If it can't be removed, get rid of the awkward dance we do fortyping.Protocol
to importinspect.getattr_static
lazily.)pep649-typevar
branch in my fork)__dict__
__dict__
access (quora/pyanalyze#773)Things to revisit:
__annotate__
parameter__annotations__
invalidate__annotate__
?I am planning to work on the interpreter core first.
cc @larryhastings @carljm @samuelcolvin
Linked PRs