I'd like to type-hint JSON objects with an unknown or changing structure (pulled in from external API). I'd like to avoid using Any or solutions like cast() as much as possible.
I believe the right hint is:
Json: TypeAlias = dict[str, "Json"] | list["Json"] | str | int | float | bool | None
I find this hint often doesn't work. The following code sample recreates the problem.
import requests
from typing_extensions import TypeAlias
Json: TypeAlias = dict[str, "Json"] | list["Json"] | str | int | float | bool | None
res: requests.models.Response = requests.get(
"https://randomuser.me/api/?results=5&nat=gb"
)
data: Json = res.json()
results: Json = data["results"]
On data["results:] I get the following complaints from mypy:
No overload variant of "getitem" of "list" matches argument type "str" [call-overload]
Possible overload variants: def getitem(self, SupportsIndex, /) -> Json def getitem(self, slice, /) -> list[Json]
Value of type "dict[str, Json] | list[Json] | str | int | float | bool | None" is not indexable [index]
What am I doing wrong? I've managed to find this GitHub issue which may well contain the solution, but if so, I'm not yet good enough with types to see it.
Thanks!
Any str is a valid instance of Json. So when you index a Json object, as in data["results"], mypy complains that that is not a valid operation on a string. You probably want data: dict[str, Json] = res.json(). Or even better, a TypedDict specifying the entire structure of the document.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With