This issue appears specifically for TypedDicts because the TypedDict constructor
code converts string annotations to ForwardRef objects, and those are not evaluated
properly by the get_type_hints() stack because of other shenanigans with type
parameters.
This issue does not affect normal generic classes because their annotations are not
pre-converted to ForwardRefs.
The fix attempts to restore the pre- #137227 behavior in the narrow scenario where
the issue manifests. It mostly makes changes only in the paths accessible from get_type_hints(),
ensuring that newer APIs (such as evaluate_forward_ref() and annotationlib) are not affected
by get_type_hints()'s past odd choices. This PR does not fix issue #138949, an older issue I
discovered while playing around with this one; we'll need a separate and perhaps more
invasive fix for that, but it should wait until after 3.14.0.
As explained in #133960, this removes most of the behavior differences with ForwardRef.evaluate.
The remaining difference is about recursive evaluation of forwardrefs; this is practically useful
in cases where an annotation refers to a type alias that itself is string-valued.
This also improves several edge cases that were previously not handled optimally. For example,
the function now takes advantage of the partial evaluation behavior of ForwardRef.evaluate() to
evaluate more ForwardRefs in the FORWARDREF format.
This also fixes#133959 as a side effect, because the buggy behavior in #133959 derives from
evaluate_forward_ref().
- Add @cpython_only decorator to lazy import tests
- Rename reference to SOURCE format
- Always two newlines between test case classes
- Merge two classes of ForwardRef tests
- Use get_annotations instead of annotationlib.get_annotations
- Format test_annotationlib with Black (not expecting that we'll keep this up
but it's close to Black-formatted right now)
This ensures that if we jump through some hoops to make sure something is imported
lazily, we don't regress on importing it.
I recently already accidentally made typing import warnings and annotationlib eagerly.
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
I started with just moving ForwardRefTests to test_annotationlib,
but found that it contained a number of tests for no_type_check, which
I moved to a new class in test_typing, as well as a number of tests that
are more appropriately classified as tests for get_type_hints().
One test, test_forward_equality_namespace(), was somewhat accidentally
depending on a global class A in test_typing. I added a class A in the
annotationlib tests instead.
Also add a useful comment in annotationlib.
It doesn't make sense to use a deprecation for evaluate_forward_ref,
as it is a new function in Python 3.14 and doesn't have compatibility
guarantees.
I considered making it throw an error if type_params it not passed and
there is no owner. However, I think this is too unfriendly for users. The
case where this param is really needed is fairly esoteric and I don't think
this case is worth the pain of forcing users to write "type_params=()".
Add the following methods:
* assertHasAttr() and assertNotHasAttr()
* assertIsSubclass() and assertNotIsSubclass()
* assertStartsWith() and assertNotStartsWith()
* assertEndsWith() and assertNotEndsWith()
Also improve error messages for assertIsInstance() and
assertNotIsInstance().