{"id":24069434,"url":"https://github.com/larsmaxfield/jsonschema-fill-default","last_synced_at":"2025-07-20T04:36:00.857Z","repository":{"id":271708092,"uuid":"911603073","full_name":"larsmaxfield/jsonschema-fill-default","owner":"larsmaxfield","description":"Fill a JSON instance in Python with the missing defaults from its JSON Schema Draft 2020-12-valid schema","archived":false,"fork":false,"pushed_at":"2025-07-10T20:47:05.000Z","size":109,"stargazers_count":3,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-11T02:46:29.560Z","etag":null,"topics":["default","fill-default","jsonschema","jsonschema-default"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/jsonschema-fill-default/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/larsmaxfield.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-03T12:05:28.000Z","updated_at":"2025-07-10T20:46:13.000Z","dependencies_parsed_at":"2025-01-09T12:39:37.673Z","dependency_job_id":"e454a308-b009-476f-8e87-d7eaeb500b00","html_url":"https://github.com/larsmaxfield/jsonschema-fill-default","commit_stats":null,"previous_names":["larsmaxfield/jsonschema-fill-default"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/larsmaxfield/jsonschema-fill-default","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsmaxfield%2Fjsonschema-fill-default","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsmaxfield%2Fjsonschema-fill-default/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsmaxfield%2Fjsonschema-fill-default/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsmaxfield%2Fjsonschema-fill-default/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/larsmaxfield","download_url":"https://codeload.github.com/larsmaxfield/jsonschema-fill-default/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsmaxfield%2Fjsonschema-fill-default/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266067419,"owners_count":23871342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["default","fill-default","jsonschema","jsonschema-default"],"created_at":"2025-01-09T14:57:19.633Z","updated_at":"2025-07-20T04:36:00.846Z","avatar_url":"https://github.com/larsmaxfield.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jsonschema-fill-default\n\nFill a JSON instance in Python with the missing defaults from its [JSON Schema](https://json-schema.org/) [Draft 2020-12](https://json-schema.org/draft/2020-12)-valid schema.\n\n```python\nfrom jsonschema_fill_default import fill_default\n\nschema = {\n    \"properties\": {\n        \"text\": {\"default\": \"Hello\"},\n        \"font\": {\"default\": 12},\n    }\n}\n\ninstance = {\"text\": \"Goodbye\"}\n\nfill_default(instance, schema)  # Mutates instance!\n```\n```python\n\u003e\u003e\u003e instance\n    {\n        \"text\": \"Goodbye\",\n        \"font\": 12\n    }\n```\n\n\u003e [!CAUTION]\n\u003e Filled instances are not automatically validated.\n\u003e\n\u003e See [Load, validate, deference, fill](#load-validate-dereference-fill) for how you can validate instances and schemas.\n\n\n## Install\n\n`jsonschema-fill-default` is available on [`PyPI`](https://pypi.org/project/jsonschema-fill-default/). You can install using [`pip`](https://pip.pypa.io/en/stable/):\n\n```command\npip install jsonschema-fill-default\n```\n\n## Features\n\n- Fills all missing defaults, including nested ones.\n\n- Optionally [do *not* create missing parents](#do-not-create-missing-parents-with-nested-defaults) when filling.\n\n- Uses the first applicable default if multiple defaults exist for a single property.\n\n- Works with the following keywords and any combination thereof (see [examples](#examples) for details):\n  - `\"properties\"`\n  - `\"allOf\"`\n  - `\"anyOf\"`\n  - `\"oneOf\"`\n  - `\"dependentSchemas\"`\n  - `\"if-then(-else)\"`\n  - `\"prefixItems\"`\n  - `\"items\"`\n\n\u003e [!IMPORTANT]\n\u003e - The instance must already be valid to its schema.\n\u003e - The schema itself must be a valid [Draft 2020-12](https://json-schema.org/draft/2020-12) [JSON Schema](https://json-schema.org/).\n\u003e - The filled instance is **not automatically validated**.\n\n\n## Examples\n\n\n### Load, validate, dereference, fill\n\nSee unabridged script at [examples/load_validate_dereference_fill.py](https://github.com/larsmaxfield/jsonschema-fill-default/blob/main/examples/load_validate_dereference_fill.py).\n\n```python\nimport json\n\nfrom jsonschema import validate, protocols\nfrom jsonref import replace_refs\nfrom jsonschema_fill_default import fill_default\n\n\nschema_filename = \"bicycle.schema.json\"\ninstance = {\n    \"style\": \"road\",\n    \"color\": \"purple\",\n    \"tire\": {\n        \"width\": 28\n    }\n}\n\nwith open(schema_filename, 'r') as file:\n    schema = json.load(file)\n\nprotocols.Validator.check_schema(schema)  # Validate schema\nvalidate(instance, schema)  # Validate instance against schema\n\nschema = replace_refs(schema) # De-reference schema \"$refs\"\n\nfill_default(instance, schema)  # Fill instance (mutates)\n\nvalidate(instance, schema)  # Validate filled instance\n\nprint(f\"\\nFilled:\\n{json.dumps(instance, indent=4)}\")\n```\n\n### Nested defaults\n\n```python\nfrom jsonschema_fill_default import fill_default\n\nschema = {\n    \"properties\": {\n        \"someString\": {\"default\": \"The default string\"},\n        \"someObject\": {\n            \"properties\": {\n                \"someNumber\": {\"default\": 3.14},\n                \"someBoolean\": {\"default\": True}}}}}\n\ninstance = {\n    \"someObject\": {\n        \"someNumber\": -1\n    }\n}\n\nfill_default(instance, schema)\n```\n```python\noriginal\n    {\n        \"someObject\": {\n            \"someNumber\": -1\n        }\n    }\n\nfilled\n    {\n        \"someString\": \"The default string\",\n        \"someObject\": {\n            \"someNumber\": -1,\n            \"someBoolean\": True\n        }\n    }\n```\n\n\n### Do not create missing parents with nested defaults\n\n```python\nfrom jsonschema_fill_default import fill_default, FillConfig\n\nschema = {\n    \"properties\": {\n        \"pool\": {\n            \"properties\": {\n                \"max_connections\": {\"type\": \"int\", \"default\": 8},\n                \"min_connections\": {\"type\": \"int\", \"default\": 0}\n            }\n        }\n    }\n}\n\nconfig = FillConfig(create_missing_parents=False)\n\nmissing = {}\nfill_default(missing, schema, config)\nassert missing == {}, missing\n\nempty = {\"pool\": {}}\nfill_default(empty, schema, config)\nassert empty == {\"pool\": {\"max_connections\": 8, \"min_connections\": 0}}, empty\n```\n\n\n### Conditional properties with defaults with `\"dependentSchemas\"`\n\n```python\nfrom jsonschema_fill_default import fill_default\n\nschema = {\n    \"properties\": {\"some_number\": {\"default\": 100}},\n    \"dependentSchemas\": {\n        \"some_bool\": {\n            \"properties\": {\n              \"some_string\": {\"default\": \"some_bool given\"}}}}}\n\nwithout_bool = {}\nwith_bool = {\"some_bool\": False}\n\nfill_default(without_bool, schema)`\nfill_default(with_bool, schema)\n```\n```python\noriginal  {}\nfilled    {\"some_number\": 100}\n\noriginal\n    {\n        \"some_bool\": False\n    }\nfilled\n    {\n        \"some_number\": 100,\n        \"some_bool\": False,\n        \"some_string\": \"some_bool given\"\n    }\n```\n\n\n### Conditional defaults with `\"if-then-else\"`\n\n```python\nfrom jsonschema_fill_default import fill_default\n\nschema = {\n    \"if\": {\n        \"required\": [\"someInteger\"]\n    },\n    \"then\": {\n        \"if\": {\n            \"properties\": {\n                \"someInteger\": {\"multipleOf\": 2}\n            }\n        },\n        \"then\": {\"properties\": {\n            \"conditionalString\": {\"default\": \"Even integer\"}\n        }},\n        \"else\": {\"properties\": {\n            \"conditionalString\": {\"default\": \"Odd integer\"}\n        }}\n    },\n    \"else\": {\"properties\": {\n        \"conditionalString\": {\"default\": \"someInteger not given\"}\n    }}\n}\n\nnone = {}\nodd = {\"someInteger\": 3}\neven = {\"someInteger\": 4}\n\nfill_default(none, schema)\nfill_default(odd, schema)\nfill_default(even, schema)\n```\n```python\noriginal  {}\nfilled    {\"conditionalString\": \"someInteger not given\"}\n\noriginal  {\"someInteger\": 3}\nfilled    {\"someInteger\": 3, \"conditionalString\": \"Odd integer\"}\n\noriginal  {\"someInteger\": 4}\nfilled    {\"someInteger\": 4, \"conditionalString\": \"Even integer\"}\n```\n\n### Different properties and defaults with `\"oneOf\"`\n\n```python\nfrom jsonschema_fill_default import fill_default\n\nschema = {\n    \"unevaluatedProperties\": False,\n    \"oneOf\": [\n        {\n            \"additionalProperties\": False,\n            \"properties\": {\n                \"food\": {\"enum\": [\"cake\", \"taco\"]},\n                \"price\": {\"default\": 9.95}\n            },\n            \"required\": [\"food\"]\n        },\n        {\n            \"additionalProperties\": False,\n            \"properties\": {\n                \"activity\": {\n                    \"enum\": [\"walk\", \"talk\", \"eat\"]\n                },\n                \"duration\": {\n                    \"default\": 30\n                }\n            },\n            \"required\": [\"activity\"]\n        }\n    ],\n}\n\nA = {\"food\": \"cake\"}\nB = {\"activity\": \"eat\"}\n\nfill_default(A, schema)\nfill_default(B, schema)\n```\n```python\noriginal  {\"food\": \"cake\"}\nfilled    {\"food\": \"cake\", \"price\": 9.95}\n\n\noriginal  {\"activity\": \"eat\"}\nfilled    {\"activity\": \"eat\", \"duration\": 30}\n```\n\n### Fill array defaults with `\"prefixItems\"` and `\"items\"`\n\n```python\nfrom jsonschema_fill_default import fill_default\n\nschema = {\n    \"type\": \"array\",\n    \"prefixItems\": [\n        {\"type\": \"number\"},\n        {\"type\": \"string\"},\n        {\"enum\": [\"Street\", \"Avenue\", \"Drive\"], \"default\": \"Drive\"}\n    ],\n    \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"name\": {\"type\": \"string\"},\n            \"age\": {\"type\": \"integer\", \"default\": 11}\n        },\n        \"required\": [\"name\"]\n    }\n}\n\na = [4, \"Privet\"]\nfill_default(a, schema)\n```\n```python\n# Missing prefixItems are only filled if there are only default-resolving prefixItem schemas remaining.\n\noriginal  [4]\nfilled    [4]\n\noriginal  [4, \"Privet\"]\nfilled    [4, \"Privet\", \"Drive\"]\n\n\n# Existing prefixItems and items are filled\n\noriginal  [4, \"Privet\", \"Drive\",\n           {\"name\": \"Harry\"},\n           {\"name\": \"Dudley\"}]\nfilled    [4, \"Privet\", \"Drive\",\n           {\"name\": \"Harry\", \"age\": 11},\n           {\"name\": \"Dudley\", \"age\": 11}]\n\n\noriginal  [1428, \"Elm\", \"Street\"]\nfilled    [1428, \"Elm\", \"Street\"]\n```\n\n## Developers\n\n### Development environment with `conda` and `poetry`\n\nI use `conda` to create a virtual environment with Python, `pip`, and `poetry`.\n\nI then add the dependencies using `poetry install`, which automatically adds them to that `conda` environment.\n\nHere's how:\n\n#### 1. Clone the repo\n\n#### 2. Create and activate a virtual environment using `conda`\n\nFor example, create and activate a virtual environment `env` in the root of the project repo using `requirements.dev.txt` as reference:\n\n```\ncd /root/of/this/repo\nconda env create --prefix ./env python=3.9\nconda activate ./env\npip install poetry==1.8.5\n```\n\nI 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.\n\n#### 3. Install `poetry` dependencies\n\n```\npoetry install\n```\n\n#### 4. Use\n\nOnce set up, you can use the development environment in the future by simply activating the `conda` environment.\n\nIf you used the example above, that would be:\n\n```\ncd /root/of/this/repo\nconda activate ./env\n```\n\n### How to release\n\n1. Checkout branch \n2. Update version X.Y.Z.YYYYMMDD in `pyproject.toml`\n    - Bump X.Y.Z according to semantic versioning 2.0.0\n    - Set YYYYMMDD according to current UTC date\n4. Update `poetry.lock` with `poetry update`\n5. Push changes\n6. Merge with main\n7. Create release with title and tag `vX.Y.Z.YYYYMMDD` (prepend `v` in both)\n8. PyPI is automatically published\n\n\n### Paradigms\n\n#### Use the top-level `__init__.py` to declare a 'public' API for the module\n\n_From [this post](https://www.reddit.com/r/Python/comments/1bbbwk/comment/c95cjs5/) by reostra:_\n\n\u003e For example, having\n\u003e \n\u003e ```\n\u003e stuff/\n\u003e   __init__.py\n\u003e   bigstuff.py\n\u003e     Stuffinator()\n\u003e     Stuffinatrix()\n\u003e   privateStuff.py\n\u003e ```\n\u003e \n\u003e where **init**.py contains\n\u003e \n\u003e ```\n\u003e from .bigstuff import Stuffinator, Stuffinatrix\n\u003e ```\n\u003e \n\u003e and thereby users can import those with\n\u003e \n\u003e ```\n\u003e from stuff import Stuffinator, Stuffinatrix\n\u003e ```\n\u003e \n\u003e which essentially says that stuff.Stuffinator and stuff.Stuffinatrix are the only parts of the module intended for public use.\n\u003e \n\u003e 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.\n\u003e \n\u003e Rather than being implicit, I find it's rather explicit.\n\u003e \n\n\n## Credits\n\njsonschema-fill-default is by Lars Maxfield\n\nRecursive filling of `\"properties\"` based on [Tom-tbt](https://stackoverflow.com/users/10712860/tom-tbt)'s answer to [Set default values according to JSON schema automatically](https://stackoverflow.com/questions/72044825/set-default-values-according-to-json-schema-automatically) on Stack Overflow.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flarsmaxfield%2Fjsonschema-fill-default","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flarsmaxfield%2Fjsonschema-fill-default","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flarsmaxfield%2Fjsonschema-fill-default/lists"}