From __future__ import annotations_compat as a migration bridge

I may have missed an earlier discussion on this—I tried to read it all, but it’s a lot.

The current behavior with from future import __annotations__, IIUC, causes migration headaches; I think this has been discussed sufficiently. What is a library that wants to support all non-EOL Python versions to do? I think the only option is to retain that, and thus get the stringifying behavior. This also means there’s a flag day at EOL of Python 3.13, especially to get rid of the warnings. One migratory path is to make sure no code uses from __future__ import annotations.

There was a 2024 discussion of this in PEP649 means that PEP563 will see *more* usage, not less, and will break runtime typecheckers . Backporting PEP 749 is not going to happen.

In the original PEP 649, there was also the proposal to make this into a future import when released, from __future__ import co_annotations, but the decision was made to make it on-by-default.

PEP 749 recognizes the migration problem by pointing out that this is impossible:

# impossible
if sys.version_info < (3, 14):
    from __future__ import annotations

I think there is one primitive, however, that would possibly make migrations easier: On Python versions that still get feature releases, introduce a

from __future__ import annotations_compat

with these semantics:

  • On Python <3.14: It functions exactly as from __future__ import annotations
  • On Python >=3.14, it will function as a no-op

Thus, it will explicitly provide different annotation semantics on older Python versions and on 3.14+, with an implied user promise that either behavior is ok.

I think if this is something that could be achieved for even one Python release <3.14, that might ease some migration headaches?

Interesting idea, but the tricky part is that from future imports are compile-time directives, not runtime conditionals, so adding annotations_compat still needs to land in each old version’s grammar. Backporting it to already-released 3.13 or earlier isn’t possible, which is exactly the flag-day problem you’re describing. The value would only kick in on future 3.13.x releases, and even then it’s a narrow window. Worth raising, but I suspect that’s the sticking point.

Yeah, that’s the wall I keep running into too. Since from __future__ imports are parsed at compile time, not evaluated at runtime, the directive has to already exist in that version’s grammar to do anything. So you can’t retrofit annotations_compat onto 3.13.0 or earlier that are already out the door, which is the exact flag-day problem. Best case it only helps on future point releases, and that’s a narrow slice. Still worth floating on the ideas board, but I bet that’s where it stalls.

I don’t think this is likely as it essentially requires adding the feature to older pythons that are mostly only getting security patches at this point. (3.13 falls into this category when 3.15 is released).

As things stand the solution is to stick with from __future__ import annotations if you need it. If you don’t actually have any forward references that require it you may be better off to remove it.