8000 PEP 705: TypedMapping by alicederyn · Pull Request #2997 · python/peps · GitHub
[go: up one dir, main page]

Skip to content

PEP 705: TypedMapping #2997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Mar 14, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Explore interaction with Protocols (#2)
  • Loading branch information
alicederyn authored Jan 12, 2023
commit d5ad9f4d93b5a64d4cb27f4bc03bba799240edcd
33 changes: 28 additions & 5 deletions pep-9999.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ The ``TypedMapping`` type is a protocol behaving almost identically to ``TypedDi

1. The runtime type of a TypedMapping object is not constrained to be a ``dict``
2. no mutator methods (``__setitem__``, ``__delitem__``, ``update``, etc.) will be generated
3. subclasses can narrow field types, in the same manner as other protocols
3. a class definition defines a ``TypedMapping`` protocol if and only if ``TypedMapping`` appears directly in its class bases
4. subclasses can narrow field types, in the same manner as other protocols

All current and future features of TypedDict are applicable to TypedMapping, including class-based and alternative syntax, totality, and ``Required`` and ``NotRequired`` from :pep:`655`.

Expand All @@ -120,11 +121,11 @@ As with :pep:`589`, this PEP provides a sketch of how a type checker is expected
Multiple inheritance and TypedDict
----------------------------------

A type that inherits from a TypedMapping subclass and from TypedDict (either directly or indirectly):
A type that inherits from a TypedMapping protocol and from TypedDict (either directly or indirectly):

4. is the structural intersection of its parents, or invalid if no such intersection exists
5. instances must be a dict subclass
6. adds mutator methods only for fields it explicitly (re)declares
5. is the structural intersection of its parents, or invalid if no such intersection exists
6. instances must be a dict subclass
7. adds mutator methods only for fields it explicitly (re)declares

For example::

Expand All @@ -141,6 +142,27 @@ For example::
movie["year"] = 1985 # Fine, mutator methods added in definition
movie["name"] = "Terminator" # Type check error, "name" mutator not declared

Inheriting, directly or indirectly, from both TypedDict and Protocol will continue to fail at runtime, and should continue to be rejected by type checkers.


Multiple inheritance and Protocol
---------------------------------

* A type that inherits from a TypedMapping protocol and from a Protocol protocol must satisfy the protocols defined by both, but is not itself a protocol unless it inherits directly from TypedMapping or Protocol.
* A type that inherits from a TypedMapping protocol and from Protocol itself is configured as a Protocol. Methods and properties may be defined; keys may not::

class A(Movie, Protocol):
# Declare a mutable property called 'year'
# This does not affect the dictionary key 'year'
year: str

* A type that inherits from a Protocol protocol and from TypedMapping itself is configured as a TypedMapping. Keys may be defined; methods and properties may not::

class B(A, TypedMapping):
# Declare a key 'year'
# This does not affect the property 'year'
year: int


Type Consistency Rules
----------------------
Expand Down Expand Up @@ -233,4 +255,5 @@ Several variations were considered and discarded:
* A ``readonly`` parameter to ``TypedDict``, behaving much like TypedMapping but with the additional constraint that instances must be dictionaries at runtime. This was discarded as less flexible due to the extra constraint; additionally, the new type nicely mirrors the existing ``Mapping``/``Dict`` types.
* Inheriting from a ``TypedMapping`` subclass and ``TypedDict`` resulting in mutator methods being added for all fields, not just those actively (re)declared in the class body. Discarded as less flexible, and not matching how inheritance works in other cases for TypedDict (e.g. total=False and total=True do not affect fields not specified in the class body).
* A generic type that removes mutator methods from its parameter, e.g. ``Readonly[MovieRecord]``. This would naturally want to be defined for a wider set of types than just ``TypedDict`` subclasses, and also raises questions about whether and how it applies to nested types. We decided to keep the scope of this PEP narrower.
* Declaring methods directly on a ``TypedMapping`` class. Methods are a kind of property, but declarations on a ``TypedMapping`` class are defining keys, so mixing the two is potentially confusing. Banning methods also makes it very easy to decide whether a ``TypedDict`` subclass can mix in a protocol or not (yes if it's just TypedMappings, no if there's a Protocol)

0