Reputation: 742
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!
Upvotes: 2
Views: 5320
Reputation: 58928
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.
Upvotes: 2