PEP 9999: Shorthand syntax for Annotated type metadata#4995
PEP 9999: Shorthand syntax for Annotated type metadata#4995till-varoquaux wants to merge 1 commit into
Conversation
|
@ilevkivskyi The draft is up and ready for your official sponsorship sign-off whenever you have a moment! |
Documentation build overview
701 files changed ·
|
| id: int = Field(gt=0) | ||
| name: str = Field(min_length=3) | ||
|
|
||
| The transition to ``Annotated`` cleanly separated type from metadata but |
There was a problem hiding this comment.
| The transition to ``Annotated`` cleanly separated type from metadata but | |
| The transition to ``Annotated`` cleanly separated types from metadata but |
| >>> int @ Field(gt=0) | ||
| int @ Field(gt=0) | ||
|
|
||
| ``__copy__`` and ``__deepcopy__`` are not supported on ``AnnotatedType`` |
There was a problem hiding this comment.
copy.copy works for Annotated right now, so this would break compatibility. I don't really see a reason for changing this.
| ``AnnotatedType`` objects support pickling via ``copyreg``, reconstructing | ||
| through ``AnnotatedType[origin, *metadata]``. | ||
|
|
||
| ``None`` on the left-hand side is accepted and uses ``NoneType`` as the |
There was a problem hiding this comment.
Can we just keep it None? typing internals turning None into NoneType is a bit of a nuisance.
| - ``types.GenericAlias`` (e.g., ``list[int]``) | ||
| - ``typing.TypeVar``, ``typing.ParamSpec``, ``typing.TypeVarTuple`` | ||
| - ``typing.TypeAliasType`` | ||
| - ``types.AnnotatedType`` (for chaining) |
There was a problem hiding this comment.
You also need it for sentinels and for a bunch of things in typing.py. It may be easier to say that everything that currently supports | for making a union should also support @.
| cannot be resolved, only that name is wrapped in ``ForwardRef``; the | ||
| surrounding operators are still evaluated. The example above produces:: | ||
|
|
||
| AnnotatedType(ForwardRef('NotYetDefined'), Field(gt=0)) |
There was a problem hiding this comment.
This explanation doesn't make sense because @ only returns an Annotated instance if the objects turn out to be of the appropriate type. Maybe the LHS is a numpy array instead!
A cleaner way to frame it is that this format assumes typing semantics. So perhaps it can always return Annotated for @, union for |, and GenericAlias for subscripting.
| The private ``typing._AnnotatedAlias`` class is retained as a deprecated | ||
| compatibility shim. Code using ``isinstance(x, typing._AnnotatedAlias)`` | ||
| will continue to work but emit a ``DeprecationWarning``. The shim is | ||
| scheduled for removal in Python 3.23. |
There was a problem hiding this comment.
Given that it's private, I think we can remove it earlier. 3.23 is, what, 2034?
| Pyright, and Ruff are compact. Since ``@`` is already a valid expression | ||
| operator, these tools do not require parser changes. They handle the new syntax | ||
| during semantic analysis. Ruff has already prototyped a ``pyupgrade`` rule | ||
| (``UP051``) for automated conversion. This enables large codebases to |
There was a problem hiding this comment.
I'd avoid mentioning the rule number in case Ruff ends up shipping another pyupgrade Rule before yours that takes the number. (I assume Ruff will only actually add the rule if and when the PEP is accepted.)
This PR introduces a draft PEP proposing a shorthand syntax for
typing.Annotatedusing the@operator (e.g.,x: int @ "metadata"instead oftyping.Annotated[int, "metadata"]).This proposal aims to improve the developer ergonomics of metadata-heavy typing frameworks like Pydantic, FastAPI, and SQLModel, aligning Python's type annotations with the conciseness of JVM languages (Java, Kotlin).
All prototype implementations (CPython, Mypy, Pyright, Ruff) are complete and linked in the Reference Implementation section.