@@ -1136,40 +1136,36 @@ These can be used as types in annotations using ``[]``, each having a unique syn
1136
1136
1137
1137
.. data :: Annotated
1138
1138
1139
- A type, introduced in :pep: `593 ` (``Flexible function and variable
1140
- annotations ``), to decorate existing types with context-specific metadata
1141
- (possibly multiple pieces of it, as ``Annotated `` is variadic).
1142
- Specifically, a type ``T `` can be annotated with metadata ``x `` via the
1143
- typehint ``Annotated[T, x] ``. This metadata can be used for either static
1144
- analysis or at runtime: at runtime, it is stored in a :attr: `__metadata__ `
1145
- attribute. If a library (or tool) encounters a typehint
1146
- ``Annotated[T, x] `` and has no special logic for metadata ``x ``, it
1147
- should ignore it and simply treat the type as ``T ``. Unlike the
1148
- ``no_type_check `` functionality that currently exists in the ``typing ``
1149
- module which completely disables typechecking annotations on a function
1150
- or a class, the ``Annotated `` type allows for both static typechecking
1151
- of ``T `` (which can safely ignore ``x ``)
1152
- together with runtime access to ``x `` within a specific application.
1153
-
1154
- Ultimately, the responsibility of how to interpret the annotations (if
1155
- at all) is the responsibility of the tool or library encountering the
1156
- ``Annotated `` type. A tool or library encountering an ``Annotated `` type
1157
- can scan through the annotations to determine if they are of interest
1158
- (e.g., using ``isinstance() ``).
1159
-
1160
- When a tool or a library does not support annotations or encounters an
1161
- unknown annotation it should just ignore it and treat annotated type as
1162
- the underlying type.
1163
-
1164
- It's up to the tool consuming the annotations to decide whether the
1165
- client is allowed to have several annotations on one type and how to
1166
- merge those annotations.
1167
-
1168
- Since the ``Annotated `` type allows you to put several annotations of
1169
- the same (or different) type(s) on any node, the tools or libraries
1170
- consuming those annotations are in charge of dealing with potential
1171
- duplicates. For example, if you are doing value range analysis you might
1172
- allow this:
1139
+ Special typing form to add context-specific metadata to an annotation.
1140
+
1141
+ Add metadata ``x `` to a given type ``T `` by using the annotation
1142
+ ``Annotated[T, x] ``. Metadata added using ``Annotated `` can be used by
1143
+ static analysis tools or at runtime. At runtime, the metadata is stored
1144
+ in a :attr: `!__metadata__ ` attribute.
1145
+
1146
+ If a library or tool encounters an annotation ``Annotated[T, x] `` and has
1147
+ no special logic for the metadata, it should ignore the metadata and simply
1148
+ treat the annotation as ``T ``. As such, ``Annotated `` can be useful for code
1149
+ that wants to use annotations for purposes outside Python's static typing
1150
+ system.
1151
+
1152
+ Using ``Annotated[T, x] `` as an annotation still allows for static
1153
+ typechecking of ``T ``, as type checkers will simply ignore the metadata ``x ``.
1154
+ In this way, ``Annotated `` differs from the
1155
+ :func: `@no_type_check <no_type_check> ` decorator, which can also be used for
1156
+ adding annotations outside the scope of the typing system, but
1157
+ completely disables typechecking for a function or class.
1158
+
1159
+ The responsibility of how to interpret the metadata
1160
+ lies with the the tool or library encountering an
1161
+ ``Annotated `` annotation. A tool or library encountering an ``Annotated `` type
1162
+ can scan through the metadata elements to determine if they are of interest
1163
+ (e.g., using :func: `isinstance `).
1164
+
1165
+ .. describe :: Annotated[<type>, <metadata>]
1166
+
1167
+ Here is an example of how you might use ``Annotated `` to add metadata to
1168
+ type annotations if you were doing range analysis:
1173
1169
1174
1170
.. testcode ::
1175
1171
@@ -1181,14 +1177,11 @@ These can be used as types in annotations using ``[]``, each having a unique syn
1181
1177
T1 = Annotated[int, ValueRange(-10, 5)]
1182
1178
T2 = Annotated[T1, ValueRange(-20, 3)]
1183
1179
1184
- Passing ``include_extras=True `` to :func: `get_type_hints ` lets one
1185
- access the extra annotations at runtime.
1186
-
1187
- The details of the syntax:
1180
+ Details of the syntax:
1188
1181
1189
1182
* The first argument to ``Annotated `` must be a valid type
1190
1183
1191
- * Multiple type annotations are supported (``Annotated `` supports variadic
1184
+ * Multiple metadata elements can be supplied (``Annotated `` supports variadic
1192
1185
arguments)::
1193
1186
1194
1187
@dataclass
@@ -1197,24 +1190,28 @@ These can be used as types in annotations using ``[]``, each having a unique syn
1197
1190
1198
1191
Annotated[int, ValueRange(3, 10), ctype("char")]
1199
1192
1200
- * ``Annotated `` must be called with at least two arguments (
1193
+ It is up to the tool consuming the annotations to decide whether the
1194
+ client is allowed to add multiple metadata elements to one annotation and how to
1195
+ merge those annotations.
1196
+
1197
+ * ``Annotated `` must be subscripted with at least two arguments (
1201
1198
``Annotated[int] `` is not valid)
1202
1199
1203
- * The order of the annotations is preserved and matters for equality
1200
+ * The order of the metadata elements is preserved and matters for equality
1204
1201
checks::
1205
1202
1206
1203
assert Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[
1207
1204
int, ctype("char"), ValueRange(3, 10)
1208
1205
]
1209
1206
1210
- * Nested ``Annotated `` types are flattened, with metadata ordered
1211
- starting with the innermost annotation::
1207
+ * Nested ``Annotated `` types are flattened. The order of the metadata elements
1208
+ starts with the innermost annotation::
1212
1209
1213
1210
assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
1214
1211
int, ValueRange(3, 10), ctype("char")
1215
1212
]
1216
1213
1217
- * Duplicated annotations are not removed::
1214
+ * Duplicated metadata elements are not removed::
1218
1215
1219
1216
assert Annotated[int, ValueRange(3, 10)] != Annotated[
1220
1217
int, ValueRange(3, 10), ValueRange(3, 10)
@@ -1233,21 +1230,46 @@ These can be used as types in annotations using ``[]``, each having a unique syn
1233
1230
1234
1231
assert Vec[int] == Annotated[list[tuple[int, int]], MaxLen(10)]
1235
1232
1236
- .. attribute :: __metadata__
1233
+ * `` Annotated `` cannot be used with an unpacked :class: ` TypeVarTuple `::
1237
1234
1238
- At runtime, the metadata associated with an ``Annotated `` type can be
1239
- retrieved via the ``__metadata__ `` attribute.
1235
+ type Variadic[*Ts] = Annotated[*Ts, Ann1] # NOT valid
1240
1236
1241
- For example :
1237
+ This would be equivalent to: :
1242
1238
1243
- .. doctest ::
1239
+ Annotated[T1, T2, T3, ..., Ann1]
1240
+
1241
+ where ``T1``, ``T2``, etc. are :class:`TypeVars <TypeVar>`. This would be
1242
+ invalid: only one type should be passed to Annotated.
1243
+
1244
+ * By default, :func: `get_type_hints ` strips the metadata from annotations.
1245
+ Pass ``include_extras=True `` to have the metadata preserved:
1246
+
1247
+ .. doctest ::
1248
+
1249
+ >>> from typing import Annotated, get_type_hints
1250
+ >>> def func (x : Annotated[int , " metadata" ]) -> None : pass
1251
+ ...
1252
+ >>> get_type_hints(func)
1253
+ {'x': <class 'int'>, 'return': <class 'NoneType'>}
1254
+ >>> get_type_hints(func, include_extras = True )
1255
+ {'x': typing.Annotated[int, 'metadata'], 'return': <class 'NoneType'>}
1256
+
1257
+ * At runtime, the metadata associated with an ``Annotated `` type can be
1258
+ retrieved via the :attr: `!__metadata__ ` attribute:
1259
+
1260
+ .. doctest ::
1261
+
1262
+ >>> from typing import Annotated
1263
+ >>> X = Annotated[int , " very" , " important" , " metadata" ]
1264
+ >>> X
1265
+ typing.Annotated[int, 'very', 'important', 'metadata']
1266
+ >>> X.__metadata__
1267
+ ('very', 'important', 'metadata')
1268
+
1269
+ .. seealso ::
1244
1270
1245
- >>> from typing import Annotated
1246
- >>> X = Annotated[int , " very" , " important" , " metadata" ]
1247
- >>> X
1248
- typing.Annotated[int, 'very', 'important', 'metadata']
1249
- >>> X.__metadata__
1250
- ('very', 'important', 'metadata')
1271
+ :pep: `593 ` - Flexible function and variable annotations
1272
+ The PEP introducing ``Annotated `` to the standard library.
1251
1273
1252
1274
.. versionadded :: 3.9
1253
1275
0 commit comments