@@ -673,7 +673,12 @@ Object creation
673673 specified by ``Member `` arguments
674674
675675* ``NewProtocolWithBases[Bases: tuple[type], *Ms: Member] `` - A variant that
676- allows specifying bases too. TODO: Is this something we actually want?
676+ allows specifying bases too. The idea is that a type would satisfy
677+ this protocol if it extends all of the given bases and has the
678+ specified members. (TODO: Is this something we actually
679+ want? It would would be a potentially powerful feature for dealing
680+ with things like Pydantic models, but protocol-with-bases would be
681+ something of a new concept.)
677682
678683* ``NewTypedDict[*Ps: Member] `` - Creates a new ``TypedDict `` with
679684 items specified by the ``Member `` arguments. TODO: Do we want a way
@@ -886,13 +891,14 @@ Runtime evaluation support
886891--------------------------
887892
888893An important goal is supporting runtime evaluation of these computed
889- types. We do not propose to add an official evaluator to the standard
894+ types. We ** do not ** propose to add an official evaluator to the standard
890895library, but intend to release a third-party evaluator library.
891896
892897While most of the extensions to the type system are "inert" type
893- operator applications, the syntax also includes list iteration and
894- conditionals, which will be automatically evaluated when the
895- ``__annotate__ `` method of a class, alias, or function is called.
898+ operator applications, the syntax also includes list iteration,
899+ conditionals, and attribute access, which will be automatically
900+ evaluated when the ``__annotate__ `` method of a class, alias, or
901+ function is called.
896902
897903In order to allow an evaluator library to trigger type evaluation in
898904those cases, we add a new hook to ``typing ``:
@@ -1149,6 +1155,10 @@ I am proposing a fully new extended callable syntax because:
11491155 closely mimic the ``mypy_extensions `` version though, if something new
11501156 is a non starter)
11511157
1158+ TODO: Currently I made the qualifiers be short strings, for code brevity
1159+ when using them, but an alternate approach would be to mirror
1160+ ``inspect.Signature `` more directly, and have an enum with names like
1161+ ``ParamKind.POSITIONAL_OR_KEYWORD ``.
11521162
11531163.. _generic-callable-rationale :
11541164
@@ -1226,6 +1236,9 @@ like mapped types are unmentioned in current documentation
12261236Reference Implementation
12271237========================
12281238
1239+ There is a demo of a runtime evaluator [#runtime ]_, which is
1240+ also where this PEP draft currently lives.
1241+
12291242There is an in-progress proof-of-concept implementation in mypy [#ref-impl ]_.
12301243
12311244It can type check the ORM and FastAPI-style model derivation
@@ -1234,8 +1247,6 @@ examples.
12341247It is missing support for callables, ``UpdateClass ``, annotation
12351248processing, and various smaller things.
12361249
1237- There is a demo of a runtime evaluator as well [#runtime ]_.
1238-
12391250Alternate syntax ideas
12401251======================
12411252
@@ -1374,15 +1385,48 @@ Rejected Ideas
13741385Renounce all cares of runtime evaluation
13751386----------------------------------------
13761387
1377- This would have a lot of simplifying features.
1388+ This would give us more flexibility to experiment with syntactic
1389+ forms, and would allow us to dispense with some ugliness such as
1390+ requiring ``typing.Iter `` in unpacked comprehension types and having a
1391+ limited set of ``<type-bool> `` expressions that can appear in
1392+ conditional types.
13781393
1379- TODO: Expand
1394+ For better or worse, though, runtime use of type annotations is
1395+ widespread, and one of our motivating examples (automatically deriving
1396+ FastAPI CRUD models) depends on it.
13801397
13811398Support TypeScript style pattern matching in subtype checking
13821399-------------------------------------------------------------
13831400
1384- This would almost certainly only be possible if we also decide not to
1385- care about runtime evaluation, as above.
1401+ In TypeScript, conditional types are formed like::
1402+
1403+ SomeType extends OtherType ? TrueType : FalseType
1404+
1405+ What's more, the right hand side of the check allows binding type
1406+ variables based on pattern matching, using the ``infer `` keyword, like
1407+ this example that extracts the element type of an array::
1408+
1409+ type ArrayArg<T> = T extends [infer El] ? El : never;
1410+
1411+ This is a very elegant mechanism, especially in the way that it
1412+ eliminates the need for ``typing.GetArg `` and its subtle ``Base ``
1413+ parameter.
1414+
1415+ Unfortunately it seems very difficult to shoehorn into Python's
1416+ existing syntax in any sort of satisfactory way, especially because of
1417+ the subtle binding structure.
1418+
1419+ Perhaps the most plausible variant would be something like::
1420+
1421+ type ArrayArg[T] = El if IsAssignable[T, list[Infer[El]]] else Never
1422+
1423+ Then, if we wanted to evaluate it at runtime, we'd need to do
1424+ something gnarly involving a custom ``globals `` environment that
1425+ catches the unbound ``Infer `` arguments.
1426+
1427+ Additionally, without major syntactic changes (using type operators
1428+ instead of ternary), we wouldn't be able to match TypeScript's
1429+ behavior of lifting the conditional over unions.
13861430
13871431
13881432Replace ``IsAssignable `` with something weaker than "assignable to" checking
@@ -1410,6 +1454,34 @@ that is similar to but not the same as subtyping, and that would need
14101454to either have a long and weird name like ``IsAssignableSimilar `` or a
14111455misleading short one like ``IsAssignable ``.
14121456
1457+
1458+ Don't use dot notation to access ``Member `` components
1459+ ------------------------------------------------------
1460+
1461+ Earlier versions of this PEP draft omitted the ability to write
1462+ ``m.name `` and similar on ``Member `` and ``Param `` components, and
1463+ instead relied on helper operators such as ``typing.GetName `` (that
1464+ could be implemented under the hood using ``typing.GetArg `` or
1465+ ``typing.GetMemberType ``).
1466+
1467+ The potential advantage here is reducing the number of new constructs
1468+ being added to the type language, and avoiding needing to either
1469+ introduce a new general mechanism for associated types or having a
1470+ special-case for ``Member ``.
1471+
1472+ ``PropsOnly `` (from :ref: `the query builder example <qb-impl >`) would
1473+ look like::
1474+
1475+ type PropsOnly[T] = typing.NewProtocol[
1476+ *[
1477+ typing.Member[typing.GetName[p], PointerArg[typing.GetType[p]]]
1478+ for p in typing.Iter[typing.Attrs[T]]
1479+ if typing.IsAssignable[typing.GetType[p], Property]
1480+ ]
1481+ ]
1482+
1483+ Everyone hated how this looked a lot.
1484+
14131485.. _less_syntax :
14141486
14151487
@@ -1430,8 +1502,9 @@ Boolean operations would likewise become operators (``Not``, ``And``,
14301502etc).
14311503
14321504The advantage of this is that constructing a type annotation never
1433- needs to do non-trivial computation, and thus we don't need
1434- :ref: `runtime hooks <rt-support >` to support evaluating them.
1505+ needs to do non-trivial computation (assuming we also get rid of dot
1506+ notation), and thus we don't need :ref: `runtime hooks <rt-support >` to
1507+ support evaluating them.
14351508
14361509It would also mean that it would be much easier to extract the raw
14371510type annotation. (The lambda form would still be somewhat fiddly.
@@ -1448,35 +1521,6 @@ worse. Supporting filtering while mapping would make it even more bad
14481521
14491522We can explore other options too if needed.
14501523
1451-
1452- Don't use dot notation to access ``Member `` components
1453- ------------------------------------------------------
1454-
1455- Earlier versions of this PEP draft omitted the ability to write
1456- ``m.name `` and similar on ``Member `` and ``Param `` components, and
1457- instead relied on helper operators such as ``typing.GetName `` (that
1458- could be implemented under the hood using ``typing.GetArg `` or
1459- ``typing.GetMemberType ``).
1460-
1461- The potential advantage here is reducing the number of new constructs
1462- being added to the type language, and avoiding needing to either
1463- introduce a new general mechanism for associated types or having a
1464- special-case for ``Member ``.
1465-
1466- ``PropsOnly `` (from :ref: `the query builder example <qb-impl >`) would
1467- look like::
1468-
1469- type PropsOnly[T] = typing.NewProtocol[
1470- *[
1471- typing.Member[typing.GetName[p], PointerArg[typing.GetType[p]]]
1472- for p in typing.Iter[typing.Attrs[T]]
1473- if typing.IsAssignable[typing.GetType[p], Property]
1474- ]
1475- ]
1476-
1477- Everyone hated how this looked a lot.
1478-
1479-
14801524Perform type manipulations with normal Python functions
14811525-------------------------------------------------------
14821526
@@ -1559,7 +1603,7 @@ arguments invariantly.
15591603Acknowledgements
15601604================
15611605
1562- Jukka Lehtosalo
1606+ Jukka Lehtosalo, etc
15631607
15641608[Thank anyone who has helped with the PEP.]
15651609
0 commit comments