json-data-types
json-data-types provides type aliases, validators, and a flexible object-oriented validation framework for Python values that are directly serializable to JSON — scalars, dicts, and lists, in both strict (dict/list) and duck-typed (Mapping/Sequence) flavors.
Highlights
JsonData,JsonDict,JsonList— strict type aliases requiring realdictandlistobjects.JsonDataLike,JsonDictLike,JsonListLike— duck-typed aliases accepting anyMappingorSequence.JsonScalar— the union of the five JSON primitive types (int,float,str,bool,None).JsonScalarTypes— a runtimetuple[type, ...]constant suitable forisinstance()checks.- Validator functions —
validate_json_*andloads_json_*for each type alias, with deep or shallow validation and cyclic-reference detection. JsonObjectValidator— an extensible base class for building custom validators via subclassing.NotJsonDataError— aValueErrorsubclass raised on validation failure.- Zero dependencies — pure Python, no third-party packages required.
- Fully typed — PEP 561 compliant, inline annotations, works with mypy strict mode.
Installation
pip install json-data-types
Type Hierarchy
JsonScalar int | float | str | bool | None
JsonDataLike JsonScalar | JsonListLike | JsonDictLike
JsonListLike Sequence[JsonDataLike] # any Sequence (not str/bytes)
JsonDictLike Mapping[str, JsonDataLike] # any Mapping with str keys
JsonData JsonScalar | JsonList | JsonDict
JsonList list[JsonData] # real list only
JsonDict dict[str, JsonData] # real dict only
Use the *Like variants when accepting data that may come from custom Mapping or Sequence implementations (e.g., collections.OrderedDict, types.MappingProxyType, tuple). Use the strict variants (JsonData, JsonDict, JsonList) when you need plain Python dict and list objects — the most common case when working with json.loads() output.
Quick Start
from json_data_types import JsonData, JsonDict, validate_json_data
# Annotate function parameters and return types
def process(payload: JsonData) -> JsonDict:
assert isinstance(payload, dict)
return {"status": "ok", "echo": payload}
# Validate and typecast untrusted data at a boundary
raw: object = {"key": [1, True, None, "hello"]}
data: JsonData = validate_json_data(raw) # raises NotJsonDataError if invalid
Type Aliases
JsonScalar
JsonScalar: TypeAlias = int | float | str | bool | None
Any JSON primitive value. Maps to JSON's number (integers and floats), string, boolean, and null.
JsonScalarTypes
JsonScalarTypes: Final[tuple[type, ...]] = (int, float, str, bool, NoneType)
A runtime constant holding the same types as JsonScalar, usable with isinstance():
from json_data_types import JsonScalarTypes
isinstance(42, JsonScalarTypes) # True
isinstance([1, 2], JsonScalarTypes) # False
JsonData
JsonData: TypeAlias = JsonScalar | JsonList | JsonDict
Any fully JSON-serializable Python value built exclusively from dict, list, and the scalar types. This is the type you get back from json.loads().
JsonDict
JsonDict: TypeAlias = dict[str, JsonData]
A dict mapping str keys to JsonData values.
JsonList
JsonList: TypeAlias = list[JsonData]
A list of JsonData values.
JsonDataLike
JsonDataLike: TypeAlias = JsonScalar | JsonListLike | JsonDictLike
Like JsonData but accepts any Mapping or Sequence rather than only dict and list. Useful at API boundaries where callers may pass OrderedDict, MappingProxyType, named tuples, etc.
JsonDictLike
JsonDictLike: TypeAlias = Mapping[str, JsonDataLike]
Any Mapping with str keys and JsonDataLike values.
JsonListLike
JsonListLike: TypeAlias = Sequence[JsonDataLike]
Any Sequence of JsonDataLike values. str is excluded — it is treated as a scalar (JsonScalar), not as a sequence of characters.
NotJsonDataError
All validators raise NotJsonDataError on failure. It is a subclass of ValueError, so existing except ValueError clauses continue to work.
from json_data_types import NotJsonDataError, validate_json_data
try:
validate_json_data((1, 2, 3))
except NotJsonDataError as e:
print(e) # Invalid top-level JSON data: (1, 2, 3) ...
Validator Functions
validate_json_data(data, fast=False) -> JsonData
Validates that data is a pure-Python JSON-serializable value. Raises NotJsonDataError if any value is not of an allowed type, if any dict key is not a str, or if a cyclic reference is detected.
from json_data_types import validate_json_data
data = validate_json_data({"users": [{"id": 1, "score": 9.5, "active": True}]})
# data is typed as JsonData
With fast=True, only the top-level type is checked — no recursion, no cycle detection. Useful when you trust the structure but need a quick typecast.
data = validate_json_data(payload, fast=True) # shallow check only
validate_json_dict(data, fast=False) -> JsonDict
Validates that data is a dict with str keys and JsonData values.
cfg: JsonDict = validate_json_dict(raw_config)
validate_json_list(data, fast=False) -> JsonList
Validates that data is a list of JsonData values.
items: JsonList = validate_json_list(raw_items)
validate_json_data_like(data, fast=False) -> JsonDataLike
Like validate_json_data but accepts any Mapping or Sequence rather than only dict and list.
from collections import OrderedDict
from json_data_types import validate_json_data_like
od = OrderedDict([("a", 1), ("b", [2, 3])])
result = validate_json_data_like(od) # passes
validate_json_dict_like(data, fast=False) -> JsonDictLike
Validates that data is a Mapping with str keys and JsonDataLike values. Accepts any Mapping subtype at all nesting levels.
from types import MappingProxyType
from json_data_types import validate_json_dict_like
mp = MappingProxyType({"key": [1, 2, 3]})
result = validate_json_dict_like(mp) # passes
validate_json_list_like(data, fast=False) -> JsonListLike
Validates that data is a Sequence of JsonDataLike values. str is excluded. Accepts any Sequence subtype (including tuple) at all nesting levels.
from json_data_types import validate_json_list_like
result = validate_json_list_like((1, True, None, {"a": 1})) # passes
loads_json_* Functions
Each validator has a corresponding loads_json_* function that combines json.loads() with validation, returning the result cast to the appropriate type:
| Function | Returns |
|---|---|
loads_json_data(s, *, fast=False, **kwargs) |
JsonData |
loads_json_dict(s, *, fast=False, **kwargs) |
JsonDict |
loads_json_list(s, *, fast=False, **kwargs) |
JsonList |
loads_json_data_like(s, *, fast=False, **kwargs) |
JsonDataLike |
loads_json_dict_like(s, *, fast=False, **kwargs) |
JsonDictLike |
loads_json_list_like(s, *, fast=False, **kwargs) |
JsonListLike |
s may be str, bytes, or bytearray. Extra keyword arguments are forwarded to json.loads().
from json_data_types import loads_json_dict
config: JsonDict = loads_json_dict(response.content)
Object-Oriented Validator API
Each validator is an instance of a concrete subclass of JsonObjectValidator. The singleton instances used by the module-level functions are:
| Instance | Class |
|---|---|
(used by validate_json_data) |
JsonDataValidator |
(used by validate_json_dict) |
JsonDictValidator |
(used by validate_json_list) |
JsonListValidator |
(used by validate_json_data_like) |
JsonDataLikeValidator |
(used by validate_json_dict_like) |
JsonDictLikeValidator |
(used by validate_json_list_like) |
JsonListLikeValidator |
Validator instances are callable (__call__) and have a loads() method, both with the same signature as the module-level functions. You can create your own instances directly:
from json_data_types import JsonDataValidator, NotJsonDataError
v = JsonDataValidator()
data = v(raw) # same as validate_json_data(raw)
data = v.loads(text) # same as loads_json_data(text)
Subclassing JsonObjectValidator
JsonObjectValidator[_T] is a generic base class. Override class variables to customize which types are accepted at each level:
| Class variable | Default | Purpose |
|---|---|---|
_scalar_types |
JsonScalarTypes |
Types treated as scalars |
_dict_types |
(dict,) |
Types treated as JSON objects |
_list_types |
(list,) |
Types treated as JSON arrays |
_dict_key_types |
(str,) |
Allowed dict key types |
_toplevel_types |
None (same as allowed) |
Restrict the top-level type |
_excluded_types |
(bytes, bytearray) |
Always-excluded types |
_excluded_scalar_types |
() |
Excluded from scalar check |
_excluded_dict_types |
() |
Excluded from dict check |
_excluded_list_types |
(str, bytes, bytearray) |
Excluded from list check |
_excluded_toplevel_types |
() |
Excluded at top level only |
Example — a validator that only accepts dict at the top level but uses duck-typed Mapping/Sequence checks internally:
from collections.abc import Mapping, Sequence
from json_data_types import JsonObjectValidator, JsonDictLike
class StrictTopDuckDeepValidator(JsonObjectValidator[JsonDictLike]):
_toplevel_types = (dict,) # top level must be a real dict
_dict_types = (Mapping,) # nested dicts may be any Mapping
_list_types = (Sequence,) # nested lists may be any Sequence
v = StrictTopDuckDeepValidator()
Common Patterns
Validating API input
from json_data_types import JsonDict, loads_json_dict
def handle_request(body: bytes) -> JsonDict:
return loads_json_dict(body) # parses + validates in one call
Accepting flexible input
from json_data_types import JsonDataLike, validate_json_data_like
import json
def serialize(value: JsonDataLike) -> str:
validate_json_data_like(value) # raises NotJsonDataError if invalid
return json.dumps(value)
Detecting cyclic structures before serialization
from json_data_types import validate_json_data
bad: dict = {}
bad["self"] = bad # cyclic!
validate_json_data(bad)
# NotJsonDataError: Cyclic reference detected in JsonDataLike object
Using fast=True for trusted data
from json_data_types import JsonData, validate_json_data
# Already validated upstream; just need the typecast
data: JsonData = validate_json_data(trusted_payload, fast=True)
Checking scalar types at runtime
from json_data_types import JsonScalarTypes
def is_json_scalar(v: object) -> bool:
return isinstance(v, JsonScalarTypes)
Supported Python Versions
Python 3.10 through 3.14.
License
MIT. See LICENSE.
For development and release workflow documentation, see CONTRIBUTING.md.
Metadata
Release files for json-data-types 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| json_data_types-0.2.0.tar.gz | 15.7 kB | With provenance | Details for json_data_types-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| json_data_types-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for json_data_types-0.2.0-py3-none-any.whl |
Total release size: 26.1 kB
Release files / json_data_types-0.2.0.tar.gz
| Download URL | json_data_types-0.2.0.tar.gz |
|---|---|
| Size | 15.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
479ecfd81358ea704980b1faf579aef452afb09212dc9f636b068eaf4a426529
|
|
BLAKE2b-256 checksum How to use checksums |
045f95640f9ef57cc510918851b2fe1100365614a0b838f4945451e7e099a51e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 26, 2026.
Transparency logRelease files / json_data_types-0.2.0-py3-none-any.whl
| Download URL | json_data_types-0.2.0-py3-none-any.whl |
|---|---|
| Size | 10.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
65fb77313999287a3bea1a56988acf3c82b30e3bb81265979ad6428c63eb28ae
|
|
BLAKE2b-256 checksum How to use checksums |
57d8717e3d5db4cfaa689420bf50dee89a4e97b04b0215776556b07d9e961350
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 26, 2026.
Transparency logSecurity for json-data-types 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for json_data_types-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.