PEP 749: Implementing PEP 649

Should we decide about deprecation now?

How about providing an option to enforce PEP 649 for all modules (even if from __future__ import annotations) and wait 2 or 3 years for feedbacks?


The cases folks are concerned about are the ones where PEP 649 doesn’t quite give the same behaviour as from __future__ import annotations does. My own preference would be:

  • from __future__ import annotations starts emitting PendingDeprecationWarning as soon as PEP 649 is implemented (i.e. 3.14). The mandatory release field in __future__.annotations is also set to None at this point (see below).
  • from __future__ import annotations starts emitting DeprecationWarning as soon as it stops having any effect and you get PEP 649 semantics even with this option specified

We would then never reach a point where from __future__ import annotations outright breaks - it would just emit DeprecationWarning indefinitely.

For the handling of __future__.annotations.getMandatoryRelease(), setting that to None for features that end up being dropped instead of becoming the default behaviour is explicitly documented: __future__ — Future statement definitions — Python 3.12.3 documentation

1 Like

That means, for example, that pytest displays PendingDeprecationWarning for hundreds of modules. The application programmer cannot easily resolve that warning until all dependent libraries stop from __future__ import annotations.

I don’t know how difficult to stop using from __future__ import annotations. That is why I want to wait for two or three years.
If there is no hard problem for transition, we can start emitting DeprecationWarning after Python 3.13 become EOL. I prefer it over displaying noisy PendingDeprecationWarning for all developers as soon as Python 3.14 is released.

Additionally, an option to enforce PEP 649 for all modules helps many developers a lot. They can easily run test or application with the option and see what is broken. Easy to try is important to collect information about how backward compatibility breackage affects to real world.
This is why I have added PEP 597 optional EncodingWarning. I enabled it at my .bashrc and see how many warning is shown. That option helped me to write PEP 686 – Make UTF-8 mode default a lot.

I think it’s important that we have a plan, so the future import doesn’t stay in limbo. However, PEP 749’s current plan leaves at least five years until we actually start emitting DeprecationWarning, so there is plenty of time to propose an alternative.

I like this idea. I think it would be useful for __future__ imports generally to be able to forcibly turn them on or off globally. For example, for from __future__ import generator_stop (the most recent future import), an option to turn the future import on globally would have made it easier to test for issues caused by the change.

Maybe we could do:

python -X future=foo  # turn on future 'foo' everywhere
python -X nofuture=foo  # turn off future 'foo' everywhere

The documentation for this feature should make it clear that it’s primarily for testing, since libraries you import may rely on the future statement.


I guess the unique nature of __future__ statements does make it genuinely hard to provide any advance programmatic notice (as PEP 749 argues), so consider the PendingDeprecationWarning suggestion withdrawn :slight_smile:

1 Like

Makes me wish (again) that PEP 690 had been accepted :frowning: In any case annotationlib seems like a reasonable approach, given that I agree annotations would be too confusing.


Why member of Format enum is named FORWARDREF and not FORWARD_REF? It is not compatible with class name (ForwardRef) which distincts Forward and Ref as 2 separate words

1 Like