Here's a kind of brute force solution: Just manually define some JSON types that cover generic JSON objects (as they would be represented in Python). You can't do recursive types in Python, but several nestings deep is usually enough for most use cases. After that we say best effort and allow Any
.
You can create a module and define these types:
from collections.abc import (
Mapping,
Sequence,
)
from typing import (
Any,
Union,
)
PrimitiveJSON = Union[str, int, float, bool, None]
# Not every instance of Mapping or Sequence can be fed to json.dump() but those
# two generic types are the most specific *immutable* super-types of `list`,
# `tuple` and `dict`:
AnyJSON4 = Union[Mapping[str, Any], Sequence[Any], PrimitiveJSON]
AnyJSON3 = Union[Mapping[str, AnyJSON4], Sequence[AnyJSON4], PrimitiveJSON]
AnyJSON2 = Union[Mapping[str, AnyJSON3], Sequence[AnyJSON3], PrimitiveJSON]
AnyJSON1 = Union[Mapping[str, AnyJSON2], Sequence[AnyJSON2], PrimitiveJSON]
AnyJSON = Union[Mapping[str, AnyJSON1], Sequence[AnyJSON1], PrimitiveJSON]
JSON = Mapping[str, AnyJSON]
JSONs = Sequence[JSON]
CompositeJSON = Union[JSON, Sequence[AnyJSON]]
# For mutable JSON we can be more specific and use dict and list:
AnyMutableJSON4 = Union[dict[str, Any], list[Any], PrimitiveJSON]
AnyMutableJSON3 = Union[dict[str, AnyMutableJSON4], list[AnyMutableJSON4], PrimitiveJSON]
AnyMutableJSON2 = Union[dict[str, AnyMutableJSON3], list[AnyMutableJSON3], PrimitiveJSON]
AnyMutableJSON1 = Union[dict[str, AnyMutableJSON2], list[AnyMutableJSON2], PrimitiveJSON]
AnyMutableJSON = Union[dict[str, AnyMutableJSON1], list[AnyMutableJSON1], PrimitiveJSON]
MutableJSON = dict[str, AnyMutableJSON]
MutableJSONs = list[MutableJSON]
MutableCompositeJSON = Union[MutableJSON, list[AnyJSON]]
Then you can just import the types you need from your module. Mostly you'll just use JSON
, JSONs
, MutableJSON
, and MutableJSONs
.
Note: this was taken from https://github.com/DataBiosphere/azul/blob/9fa0f78800dbbc7bf4822063ff31811b3bb3f55b/src/azul/types.py which uses the Apache 2.0 license.
It was likely inspired by this thread https://github.com/python/typing/issues/182.
This Stack Overflow answer contains some other useful suggestions depending on what you know about your data.