Dealing with forward refs at runtime

On a loosely related note: I have found it difficult to deal with forward refs at runtime when using either a metaclass or a descriptor’s __set_name__ method to figure out the bound type on the RHS from the annotation on the LHS (kind of like mapped_column works in SQLAlchemy 2.0), since get_type_hints only works if every forward ref can be resolved, it’s always either everything or nothing, which is kind of an awkward limitation.

Depending on the use-case we might only care about a subset of the annotations on a class, so if get_type_hints fails because of an unrelated annotation that’s pretty frustrating. It’s also pretty heavy handed, since you’re doing a bunch of extra work to resolve forward refs that never needed to be resolved at runtime. I found myself using some of the undocumented helper functions and duplicating some of the logic of get_type_hints in order to only look at the type hints I care about, which is a fragile solution at best.

So improved utility functions to deal with a single annotation or a small subset of the annotations on an object would be quite valuable as well.

3 Likes

Which Python version? This area keeps changing (and PEP 649 will change it again – hopefully that will actually go into 3.13, per the PEP header).

3.10, although I don’t think anything changed in 3.11 or 3.12 that would’ve addressed my concerns. But PEP 649 looks like it will address at least the biggest frustration by allowing partial evaluation of forward references as far as it is possible.

It would still be nice to either be able to filter annotations in typing.get_type_hints by attribute name or to apply the transformations that function does internally to a single annotation value, provided a matching context, so you don’t introduce quite as much overhead if you only want to inspect a single annotation on a class with dozens of annotations.

PEP 649 has been dragging its feet so long that I don’t recall what it does about errors; your experience points in the direction of wanting to be able to access some annotations even if other annotations of the same object have an error. I agree with that desire.

Yes, absolutely. The second of three modes for get_type_hints in PEP649 appears to wrap anything that couldn’t be resolved to a type at the time of the call into a ForwardRef, so that should take care of that.

But bonus points for reducing introspection overhead when all you care about is a single or a handful of specific type hints, rather than all of them. This could also be useful for resolving the return values of typing.get_args, since that can contain forward references as well.