Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type hinting a JSON object in Python

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

Problem

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]

Question

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!

like image 639
FlightPlan Avatar asked Aug 12 '26 07:08

FlightPlan


1 Answers

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.

like image 94
l0b0 Avatar answered Aug 13 '26 21:08

l0b0