I now have a working implementation of much of the C part of PEP 649 here: gh-119180: PEP 649 compiler changes by JelleZijlstra · Pull Request #119361 · python/cpython · GitHub. There are many issues still to work out and I haven’t run it on any third-party code yet.
However, CPython’s own test suite found a lot of interesting issues already. Here are some of my findings:
- Contrary to my earlier post, I don’t think we can apply PEP 649 semantics if
from __future__ import annotations
is active. This would break too much working code, in cases where a library inspects the annotations eagerly (e.g., in a decorator) and the user is relying on the future import to use forward references. Therefore, I kept thefrom __future__ import annotations
behavior in place and applied PEP 649 semantics only in cases where the future import is off. - Code that does
cls.__dict__.get("__annotations__")
to get to a class’s annotations dict will break. There is no longer going to be an annotations key in the class dict unless the user has already accessed thecls.__annotations__
descriptor. This affected several parts oftyping.py
. It is fixable by usingcls.__annotations__
directly. - Code that interacts directly with the
__annotations__
name in the local namespace stops working. I don’t know why people would do this, but there are test cases in CPython that rely on it (e.g., the ones removed in this commit: gh-119180: PEP 649 compiler changes by JelleZijlstra · Pull Request #119361 · python/cpython · GitHub).
Both of these cases are also called out in the PEP: PEP 649 – Deferred Evaluation Of Annotations Using Descriptors | peps.python.org. The PEP was accepted with the understanding that some unusual code patterns would break; we’ll have to see how problematic this is in practice.