Thanks so much for this, I think it makes a lot of sense. You've saved me by explaining why PEP 563 semantics are problematic for pydantic far more articulately than I could have done.

I can entirely see why PEP 563 made sense at the time, myself (and others in the "runtime use of annotations" community) should have engaged with the PEP before it was accepted, we might have been able to smooth out these wrinkles then.

One other route occurs to me:

Switch from `from __future__ import annotations` to a per module feature flag (say, something like `from __switches__ import postponed_annotations`).

I don't know if there's a precedent for this?, but I think it has a lot of advantages:

* those who want type annotations as strings get their way (just a switch of statement at the beginning of files)
* those who want runtime access to type annotations (pydantic etc.) get their way
* if you have one module in a big code base that uses pydantic or similar, you only need to pay the price of runtime type annotations in that file
* `from __future__ import annotations` can continue to prompt PEP 563 semantics (for now or indefinitely), independently it can also continue to work for PEP 585 and PEP 604 as I believe it does now
* there's room for PEP 649 or similar in the future to improve forward refs and performance when the switch is not set, without the rush to get it into 3.10
* we could even allow the default to be changed with an env variable or command line flag like -O / PYTHONOPTIMIZE - but maybe this too complicated

I understand that adding another switch to python is not ideal, but given that we are where we are, it seems like a pragmatic solution.

For me I'd be happy if there was anyway whatsoever to keep the current (or PEP 649) behaviour in 3.10.

Samuel

--

Samuel Colvin