Fill a JSON instance with the missing defaults from its JSON Schema Draft 2020-12-valid schema
Project description
jsonschema-fill-default
Fill a JSON instance in Python with the missing defaults from its JSON Schema Draft 2020-12-valid schema.
from jsonschema_fill_default import fill_default
schema = {
"properties": {
"text": {"default": "Hello"},
"font": {"default": 12},
}
}
instance = {"text": "Goodbye"}
fill_default(instance, schema) # Mutates instance!
>>> instance
{
"text": "Goodbye",
"font": 12
}
[!CAUTION] Filled instances are not automatically validated.
See Load, validate, deference, fill for how you can validate instances and schemas.
Install
jsonschema-fill-default is available on PyPI. You can install using pip:
pip install jsonschema-fill-default
Features
-
Fills all missing defaults, including nested ones.
-
Uses the first applicable default if multiple defaults exist for a single property.
-
Works with the following keywords and any combination thereof (see examples for details):
"properties""allOf""anyOf""oneOf""dependentSchemas""if-then(-else)""prefixItems""items"
[!IMPORTANT]
- The instance must already be valid to its schema.
- The schema itself must be a valid Draft 2020-12 JSON Schema.
- The filled instance is not automatically validated.
Examples
Load, validate, dereference, fill
See unabridged script at examples/load_validate_dereference_fill.py.
import json
from jsonschema import validate, protocols
from jsonref import replace_refs
from jsonschema_fill_default import fill_default
schema_filename = "bicycle.schema.json"
instance = {
"style": "road",
"color": "purple",
"tire": {
"width": 28
}
}
with open(schema_filename, 'r') as file:
schema = json.load(file)
protocols.Validator.check_schema(schema) # Validate schema
validate(instance, schema) # Validate instance against schema
schema = replace_refs(schema) # De-reference schema "$refs"
fill_default(instance, schema) # Fill instance (mutates)
validate(instance, schema) # Validate filled instance
print(f"\nFilled:\n{json.dumps(instance, indent=4)}")
Nested defaults
from jsonschema_fill_default import fill_default
schema = {
"properties": {
"someString": {"default": "The default string"},
"someObject": {
"properties": {
"someNumber": {"default": 3.14},
"someBoolean": {"default": True}}}}}
instance = {
"someObject": {
"someNumber": -1
}
}
fill_default(instance, schema)
original
{
"someObject": {
"someNumber": -1
}
}
filled
{
"someString": "The default string",
"someObject": {
"someNumber": -1,
"someBoolean": True
}
}
Conditional properties with defaults with "dependentSchemas"
from jsonschema_fill_default import fill_default
schema = {
"properties": {"some_number": {"default": 100}},
"dependentSchemas": {
"some_bool": {
"properties": {
"some_string": {"default": "some_bool given"}}}}}
without_bool = {}
with_bool = {"some_bool": False}
fill_default(without_bool, schema)`
fill_default(with_bool, schema)
original {}
filled {"some_number": 100}
original
{
"some_bool": False
}
filled
{
"some_number": 100,
"some_bool": False,
"some_string": "some_bool given"
}
Conditional defaults with "if-then-else"
from jsonschema_fill_default import fill_default
schema = {
"if": {
"required": ["someInteger"]
},
"then": {
"if": {
"properties": {
"someInteger": {"multipleOf": 2}
}
},
"then": {"properties": {
"conditionalString": {"default": "Even integer"}
}},
"else": {"properties": {
"conditionalString": {"default": "Odd integer"}
}}
},
"else": {"properties": {
"conditionalString": {"default": "someInteger not given"}
}}
}
none = {}
odd = {"someInteger": 3}
even = {"someInteger": 4}
fill_default(none, schema)
fill_default(odd, schema)
fill_default(even, schema)
original {}
filled {"conditionalString": "someInteger not given"}
original {"someInteger": 3}
filled {"someInteger": 3, "conditionalString": "Odd integer"}
original {"someInteger": 4}
filled {"someInteger": 4, "conditionalString": "Even integer"}
Different properties and defaults with "oneOf"
from jsonschema_fill_default import fill_default
schema = {
"unevaluatedProperties": False,
"oneOf": [
{
"additionalProperties": False,
"properties": {
"food": {"enum": ["cake", "taco"]},
"price": {"default": 9.95}
},
"required": ["food"]
},
{
"additionalProperties": False,
"properties": {
"activity": {
"enum": ["walk", "talk", "eat"]
},
"duration": {
"default": 30
}
},
"required": ["activity"]
}
],
}
A = {"food": "cake"}
B = {"activity": "eat"}
fill_default(A, schema)
fill_default(B, schema)
original {"food": "cake"}
filled {"food": "cake", "price": 9.95}
original {"activity": "eat"}
filled {"activity": "eat", "duration": 30}
Fill array defaults with "prefixItems" and "items"
from jsonschema_fill_default import fill_default
schema = {
"type": "array",
"prefixItems": [
{"type": "number"},
{"type": "string"},
{"enum": ["Street", "Avenue", "Drive"], "default": "Drive"}
],
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "default": 11}
},
"required": ["name"]
}
}
a = [4, "Privet"]
fill_default(a, schema)
# Missing prefixItems are only filled if there are only default-resolving prefixItem schemas remaining.
original [4]
filled [4]
original [4, "Privet"]
filled [4, "Privet", "Drive"]
# Existing prefixItems and items are filled
original [4, "Privet", "Drive",
{"name": "Harry"},
{"name": "Dudley"}]
filled [4, "Privet", "Drive",
{"name": "Harry", "age": 11},
{"name": "Dudley", "age": 11}]
original [1428, "Elm", "Street"]
filled [1428, "Elm", "Street"]
Developers
Development environment with conda and poetry
I use conda to create a virtual environment with Python, pip, and poetry.
I then add the dependencies using poetry install, which automatically adds them to that conda environment.
Here's how:
1. Clone the repo
2. Create and activate a virtual environment using conda
For example, create and activate a virtual environment env in the root of the project repo using requirements.dev.txt as reference:
cd /root/of/this/repo
conda env create --prefix ./env python=3.9
conda activate ./env
pip install poetry==1.8.5
I don't use an environment.yml to solve and install the conda environment because it's typically slower than just running the above "manual" install.
3. Install poetry dependencies
poetry install
4. Use
Once set up, you can use the development environment in the future by simply activating the conda environment.
If you used the example above, that would be:
cd /root/of/this/repo
conda activate ./env
How to release
- Checkout branch
- Update version X.Y.Z.YYYYMMDD in
pyproject.toml- Bump X.Y.Z according to semantic versioning 2.0.0
- Set YYYYMMDD according to current UTC date
- Update
poetry.lockwithpoetry update - Push changes
- Merge with main
- Create release with title and tag
vX.Y.Z.YYYYMMDD(prependvin both) - PyPI is automatically published
Paradigms
Use the top-level __init__.py to declare a 'public' API for the module
From this post by reostra:
For example, having
stuff/ __init__.py bigstuff.py Stuffinator() Stuffinatrix() privateStuff.pywhere init.py contains
from .bigstuff import Stuffinator, Stuffinatrixand thereby users can import those with
from stuff import Stuffinator, Stuffinatrixwhich essentially says that stuff.Stuffinator and stuff.Stuffinatrix are the only parts of the module intended for public use.
While there's nothing stopping people from doing an 'import stuff.bigstuff.Stuffometer' or 'import stuff.privateStuff.HiddenStuff', they'll at least know they're peeking behind the curtain at that point.
Rather than being implicit, I find it's rather explicit.
Credits
jsonschema-fill-default is by Lars Maxfield
Recursive filling of "properties" based on Tom-tbt's answer to Set default values according to JSON schema automatically on Stack Overflow.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jsonschema_fill_default-0.1.3.20250131.tar.gz.
File metadata
- Download URL: jsonschema_fill_default-0.1.3.20250131.tar.gz
- Upload date:
- Size: 6.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46bbdd2ca2160cf1077473fa449740359a70326cec1989d53fc81455ce2996a4
|
|
| MD5 |
921238d6a1c1b7ade2bfa2afcc2c6f9f
|
|
| BLAKE2b-256 |
b4f43cdbb608615365b2282faeead2b1c2957c54d0898b24f2c04bad72004d35
|
Provenance
The following attestation bundles were made for jsonschema_fill_default-0.1.3.20250131.tar.gz:
Publisher:
publish.yml on larsmaxfield/jsonschema-fill-default
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jsonschema_fill_default-0.1.3.20250131.tar.gz -
Subject digest:
46bbdd2ca2160cf1077473fa449740359a70326cec1989d53fc81455ce2996a4 - Sigstore transparency entry: 167498816
- Sigstore integration time:
-
Permalink:
larsmaxfield/jsonschema-fill-default@a4262f08abc163c00cfcd471beafca5018534c65 -
Branch / Tag:
refs/tags/v0.1.3.20250131 - Owner: https://github.com/larsmaxfield
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4262f08abc163c00cfcd471beafca5018534c65 -
Trigger Event:
push
-
Statement type:
File details
Details for the file jsonschema_fill_default-0.1.3.20250131-py3-none-any.whl.
File metadata
- Download URL: jsonschema_fill_default-0.1.3.20250131-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c390eb701a3e22e2d5020aa12307281d1bee6de0a55c5551e9b7a68b0cf702b
|
|
| MD5 |
9d96ae7b6a49cd1275ed157ae4c0ecd7
|
|
| BLAKE2b-256 |
31f134ee740cd043e547b23ddf4e727590a6fb0af38f89987c24a18f88b2a9dd
|
Provenance
The following attestation bundles were made for jsonschema_fill_default-0.1.3.20250131-py3-none-any.whl:
Publisher:
publish.yml on larsmaxfield/jsonschema-fill-default
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
jsonschema_fill_default-0.1.3.20250131-py3-none-any.whl -
Subject digest:
7c390eb701a3e22e2d5020aa12307281d1bee6de0a55c5551e9b7a68b0cf702b - Sigstore transparency entry: 167498818
- Sigstore integration time:
-
Permalink:
larsmaxfield/jsonschema-fill-default@a4262f08abc163c00cfcd471beafca5018534c65 -
Branch / Tag:
refs/tags/v0.1.3.20250131 - Owner: https://github.com/larsmaxfield
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4262f08abc163c00cfcd471beafca5018534c65 -
Trigger Event:
push
-
Statement type: