Specify keys for mypy in python dictionary
Ran into this problem too when trying to put some typing around AWS API Gateway/Lambda integration.
As pointed out by @Michael0x2a in the comments, TypedDict would seem to be the way to go, especially because it does not require any conversions yourself before passing into a function (a requirement for API responses, like you mentioned).
from mypy_extensions import TypedDict
DictWithOnlyX = TypedDict('DictWithOnlyX', {"x": str})
# error: Extra key 'y' for TypedDict "DictWithOnlyX@58"
dx1: DictWithOnlyX = { "y": 123 }
# error: Incompatible types (expression has type "int",
# TypedDict item "x" has type "str")
dx2: DictWithOnlyX = { "x": 123 }
# GOOD!
dx3: DictWithOnlyX = { "x": "123" }
Should also note that, if dependencies are segregated between production and dev/test, then this makes mypy
a production dependency.
There are a few ways and assuming that your data structure must only have the same attributes, but they don't use dicts.
Instead of passing in a dict
, you can use a namedtuple. Using a namedtuple, you can treat it as an object, but no new fields can be added either.
from collections import namedtuple
A = namedtuple("A", ["x", "y", "z"])
def get_x(d: A) -> int:
d.x
Another way is to create a class and use the __slot__
attribute. This also makes it so no new attributes can be accidentally inserted.
class A:
__slot__ = ["x", "y", "z"]
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
Using the above methods, you must define the fields at the very beginning.