Mailing List Archive

TypedMapping structural type
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 -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/2P26R4VH2ZCNNNOQCBZWEM4RNF35OXOW/
Code of Conduct: http://python.org/psf/codeofconduct/