I would like to propose adding a new TypedMapping structural type, which (like
Mapping vs dict) functions as a read-only equivalent of TypedDict.
(This is a cross-post from typing-sig@, where our original proposal got
refined.)
# Specification
```python
class Request(TypedMapping, total=False):
some_field: string | None
request: Request = { "some_field": "foo" }
request2: Request = {} # fine because total=False
request["some_field"] = None # error
del request["some_field"] # error
```
TypedMapping is a structural type that mirrors TypedDict except for:
1) instances need not be subclasses of dict;
2) no mutate methods will be generated
3) subclasses can narrow field types (consequence of 2)
Rules for 3 mirror Protocols.
## Multiple inheritance and TypedDict
A type that inherits from a TypedMapping subclass 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 mutate methods only for fields it explicitly (re)declares
```python
class A(TypedMapping):
field1: int
field2: str
class B(A, TypedDict):
field1: int
b: B = { "field1": 5, "field2": "value" }
b["field1"] = 6 # Fine, mutate methods added in definition of B
b["field2"] = "value2" # Error, field2 mutator not declared
```
# Use case
We are making increasing use of TypedDict to type hint code that uses
dictionaries to hold requests to and responses from services (both client and
server side). However, we run into problems whenever any constraint is
loosened, e.g. passing data from a response where a field is guaranteed to a
request where it is optional:
```python
class Response(TypedDict):
some_field: string
class Request(TypedDict, total=False):
some_field: string | None
class Server1:
def fetch_data() -> Response: ...
class Server2:
def accept_data(request: Request): ...
def my_code(server1: Server1, server2: Server2):
data: Response = server1.fetch_data()
server2.accept_data(data) # error: Response and Request are incompatible
```python
This last line is not type-safe, as there are mutation operations on Request
that aren't valid on Response. If we could remove those mutation operations
from the Request type, then it would be a valid subtype of Response. This
problem seems quite common, e.g. https://github.com/python/mypy/pull/12142.
Pablo Galindo has agreed to sponsor a PEP.
_______________________________________________
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/2P26R4VH2ZCNNNOQCBZWEM4RNF35OXOW/
Code of Conduct: http://python.org/psf/codeofconduct/