# JSON Schema Validation within Jinja2 Templates
[![Tests](https://img.shields.io/github/actions/workflow/status/copier-org/jinja2-jsonschema/tests.yml?branch=main&label=Tests&labelColor=333&logo=github&style=flat-square)](https://github.com/copier-org/jinja2-jsonschema/actions?query=branch%3Amain)
[![Python versions](https://img.shields.io/pypi/pyversions/jinja2-jsonschema?label=Python&logo=python&logoColor=%23959DA5&style=flat-square)](https://pypi.org/project/jinja2-jsonschema)
[![PyPI](https://img.shields.io/pypi/v/jinja2-jsonschema?label=PyPI&logo=pypi&logoColor=%23959DA5&style=flat-square)](https://pypi.org/project/jinja2-jsonschema)
[![Formatter & Linter: Ruff](https://img.shields.io/badge/-Ruff-261230.svg?labelColor=grey&logo=ruff&logoColor=D7FF64&style=flat-square)](https://github.com/charliermarsh/ruff)
[![Type-checker: mypy](https://img.shields.io/badge/mypy-strict-2A6DB2.svg?style=flat-square)](http://mypy-lang.org)
A [Jinja2 extension][jinja-extensions] providing a [Jinja2 filter][jinja-filter] and a [Jinja2 test][jinja-test] for validating data against a JSON/YAML schema within [Jinja2][jinja] templates.
## Installation
* With [`pip`](https://pip.pypa.io):
```shell
pip install jinja2-jsonschema
# ... or with YAML support
pip install jinja2-jsonschema[yaml]
```
* With [`poetry`][poetry]:
```shell
poetry add jinja2-jsonschema
# ... or with YAML support
poetry add jinja2-jsonschema -E yaml
```
* With [`pdm`][pdm]:
```shell
pdm add jinja2-jsonschema
# ... or with YAML support
pdm add jinja2-jsonschema[yaml]
```
* With [`pipx`][pipx] (injected into the `pipx`-managed virtual env of a package):
```shell
pipx inject PACKAGE jinja2-jsonschema
# ... or with YAML support
pipx inject PACKAGE jinja2-jsonschema[yaml]
```
## Usage
The extension provides:
* A Jinja2 filter which receives a schema file path or schema object as input and returns a [`jsonschema.ValidationError`][python-jsonschema-validationerror] object when validation fails and an empty string (`""`) otherwise.
* A Jinja2 test which receives a schema file path or schema object as input and returns `False` when validation fails and `True` otherwise.
The [JSON Schema dialect][jsonschema-dialect] is inferred from the `$schema` field in the JSON Schema document and, when omitted, defaults to the [latest dialect supported by the installed `jsonschema` library][python-jsonschema-features]. Both local and remote schemas are supported including [schema references][jsonschema-ref] and [JSON Pointers][jsonschema-jsonpointer].
Local schema files are loaded via a [Jinja2 loader](https://jinja.palletsprojects.com/en/latest/api/#loaders) in which case configuring the Jinja2 environment with a loader is mandatory.
Some example usage of the JSON Schema validation filter and test is this:
```python
from jinja2 import Environment
from jinja2 import FileSystemLoader
env = Environment(
# Register a loader (only necessary when using local schema files).
loader=FileSystemLoader("/path/to/templates"),
# Register the extension.
extensions=["jinja2_jsonschema.JsonSchemaExtension"],
)
# Example using an inline schema object.
template = env.from_string("{{ age | jsonschema({'type': 'integer', 'minimum': 0}) }}")
template.render(age=30) # OK
template.render(age=-1) # ERROR
template = env.from_string("{{ age is jsonschema({'type': 'integer', 'minimum': 0}) }}")
template.render(age=30) # --> `True`
template.render(age=-1) # --> `False`
# Example using a local schema file.
template = env.from_string("{{ age | jsonschema('age.json') }}")
template.render(age=30) # OK
template.render(age=-1) # ERROR
template = env.from_string("{{ age is jsonschema('age.json') }}")
template.render(age=30) # --> `True`
template.render(age=-1) # --> `False`
# Example using a remote schema file.
template = env.from_string("{{ age | jsonschema('https://example.com/age.json') }}")
template.render(age=30) # OK
template.render(age=-1) # ERROR
template = env.from_string("{{ age is jsonschema('https://example.com/age.json') }}")
template.render(age=30) # --> `True`
template.render(age=-1) # --> `False`
```
## Usage with Copier
The extension integrates nicely with [Copier][copier], e.g. for validating complex JSON/YAML answers in the Copier questionnaire. For this, add the extension as a [Jinja2 extension in `copier.yml`][copier-jinja-extensions] and use the Jinja2 filter in the `validator` field of a Copier [question][copier-questions]. For instance:
```yaml
_jinja_extensions:
- jinja2_jsonschema.JsonSchemaExtension
complex_question:
type: json # or `yaml`
validator: "{{ complex_question | jsonschema('schemas/complex.json') }}"
```
In this example, a local schema file `schemas/complex.json` is used whose path is relative to the template root. To prevent copying schema files to the generated project, they should be either [excluded][copier-exclude]
```diff
+_exclude:
+ - schemas/
_jinja_extensions:
- jinja2_jsonschema.JsonSchemaExtension
```
or the project template should be located in a [subdirectory][copier-subdirectory] such as `template/`:
```diff
+_subdirectory_: template
_jinja_extensions:
- jinja2_jsonschema.JsonSchemaExtension
```
Finally, template consumers need to install the extension along with Copier. For instance with `pipx`:
```shell
pipx install copier
pipx inject copier jinja2-jsonschema
```
## Contributions
Contributions are always welcome via filing [issues](https://github.com/copier-org/jinja2-jsonschema/issues) or submitting [pull requests](https://github.com/copier-org/jinja2-jsonschema/pulls). Please check the [contribution guide][contribution-guide] for more details.
[contribution-guide]: https://github.com/copier-org/jinja2-jsonschema/blob/main/CONTRIBUTING.md
[copier]: https://github.com/copier-org/copier
[copier-exclude]: https://copier.readthedocs.io/en/stable/configuring/#exclude
[copier-jinja-extensions]: https://copier.readthedocs.io/en/stable/configuring/#jinja_extensions
[copier-questions]: https://copier.readthedocs.io/en/stable/configuring/#questions
[copier-subdirectory]: https://copier.readthedocs.io/en/stable/configuring/#subdirectory
[jinja]: https://jinja.palletsprojects.com
[jinja-extensions]: https://jinja.palletsprojects.com/en/latest/extensions/
[jinja-filter]: https://jinja.palletsprojects.com/en/latest/templates/#filters
[jinja-test]: https://jinja.palletsprojects.com/en/latest/templates/#tests
[jsonschema]: https://json-schema.org
[jsonschema-dialect]: https://json-schema.org/understanding-json-schema/reference/schema.html#schema
[jsonschema-ref]: https://json-schema.org/understanding-json-schema/structuring.html#ref
[jsonschema-jsonpointer]: https://json-schema.org/understanding-json-schema/structuring.html#json-pointer
[pdm]: https://pdm.fming.dev
[pip]: https://pip.pypa.io
[pipx]: https://pypa.github.io/pipx
[poetry]: https://python-poetry.org
[python-jsonschema-features]: https://python-jsonschema.readthedocs.io/en/stable/#features
[python-jsonschema-validationerror]: https://python-jsonschema.readthedocs.io/en/stable/api/jsonschema/exceptions/#jsonschema.exceptions.ValidationError
Raw data
{
"_id": null,
"home_page": null,
"name": "jinja2-jsonschema",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "extension, jinja, jinja2, json, jsonschema, yaml",
"author": null,
"author_email": "Sigurd Spieckermann <sigurd.spieckermann@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/53/8d/0018457d0955998a292082e1e3a00899246bef5c3dc22386f8dbc125a1b6/jinja2_jsonschema-0.3.0.tar.gz",
"platform": null,
"description": "# JSON Schema Validation within Jinja2 Templates\n\n[![Tests](https://img.shields.io/github/actions/workflow/status/copier-org/jinja2-jsonschema/tests.yml?branch=main&label=Tests&labelColor=333&logo=github&style=flat-square)](https://github.com/copier-org/jinja2-jsonschema/actions?query=branch%3Amain)\n[![Python versions](https://img.shields.io/pypi/pyversions/jinja2-jsonschema?label=Python&logo=python&logoColor=%23959DA5&style=flat-square)](https://pypi.org/project/jinja2-jsonschema)\n[![PyPI](https://img.shields.io/pypi/v/jinja2-jsonschema?label=PyPI&logo=pypi&logoColor=%23959DA5&style=flat-square)](https://pypi.org/project/jinja2-jsonschema)\n[![Formatter & Linter: Ruff](https://img.shields.io/badge/-Ruff-261230.svg?labelColor=grey&logo=ruff&logoColor=D7FF64&style=flat-square)](https://github.com/charliermarsh/ruff)\n[![Type-checker: mypy](https://img.shields.io/badge/mypy-strict-2A6DB2.svg?style=flat-square)](http://mypy-lang.org)\n\nA [Jinja2 extension][jinja-extensions] providing a [Jinja2 filter][jinja-filter] and a [Jinja2 test][jinja-test] for validating data against a JSON/YAML schema within [Jinja2][jinja] templates.\n\n## Installation\n\n* With [`pip`](https://pip.pypa.io):\n\n ```shell\n pip install jinja2-jsonschema\n\n # ... or with YAML support\n pip install jinja2-jsonschema[yaml]\n ```\n\n* With [`poetry`][poetry]:\n\n ```shell\n poetry add jinja2-jsonschema\n\n # ... or with YAML support\n poetry add jinja2-jsonschema -E yaml\n ```\n\n* With [`pdm`][pdm]:\n\n ```shell\n pdm add jinja2-jsonschema\n\n # ... or with YAML support\n pdm add jinja2-jsonschema[yaml]\n ```\n\n* With [`pipx`][pipx] (injected into the `pipx`-managed virtual env of a package):\n\n ```shell\n pipx inject PACKAGE jinja2-jsonschema\n\n # ... or with YAML support\n pipx inject PACKAGE jinja2-jsonschema[yaml]\n ```\n\n## Usage\n\nThe extension provides:\n\n* A Jinja2 filter which receives a schema file path or schema object as input and returns a [`jsonschema.ValidationError`][python-jsonschema-validationerror] object when validation fails and an empty string (`\"\"`) otherwise.\n* A Jinja2 test which receives a schema file path or schema object as input and returns `False` when validation fails and `True` otherwise.\n\nThe [JSON Schema dialect][jsonschema-dialect] is inferred from the `$schema` field in the JSON Schema document and, when omitted, defaults to the [latest dialect supported by the installed `jsonschema` library][python-jsonschema-features]. Both local and remote schemas are supported including [schema references][jsonschema-ref] and [JSON Pointers][jsonschema-jsonpointer].\n\nLocal schema files are loaded via a [Jinja2 loader](https://jinja.palletsprojects.com/en/latest/api/#loaders) in which case configuring the Jinja2 environment with a loader is mandatory.\n\nSome example usage of the JSON Schema validation filter and test is this:\n\n```python\nfrom jinja2 import Environment\nfrom jinja2 import FileSystemLoader\n\n\nenv = Environment(\n # Register a loader (only necessary when using local schema files).\n loader=FileSystemLoader(\"/path/to/templates\"),\n # Register the extension.\n extensions=[\"jinja2_jsonschema.JsonSchemaExtension\"],\n)\n\n# Example using an inline schema object.\ntemplate = env.from_string(\"{{ age | jsonschema({'type': 'integer', 'minimum': 0}) }}\")\ntemplate.render(age=30) # OK\ntemplate.render(age=-1) # ERROR\ntemplate = env.from_string(\"{{ age is jsonschema({'type': 'integer', 'minimum': 0}) }}\")\ntemplate.render(age=30) # --> `True`\ntemplate.render(age=-1) # --> `False`\n\n# Example using a local schema file.\ntemplate = env.from_string(\"{{ age | jsonschema('age.json') }}\")\ntemplate.render(age=30) # OK\ntemplate.render(age=-1) # ERROR\ntemplate = env.from_string(\"{{ age is jsonschema('age.json') }}\")\ntemplate.render(age=30) # --> `True`\ntemplate.render(age=-1) # --> `False`\n\n# Example using a remote schema file.\ntemplate = env.from_string(\"{{ age | jsonschema('https://example.com/age.json') }}\")\ntemplate.render(age=30) # OK\ntemplate.render(age=-1) # ERROR\ntemplate = env.from_string(\"{{ age is jsonschema('https://example.com/age.json') }}\")\ntemplate.render(age=30) # --> `True`\ntemplate.render(age=-1) # --> `False`\n```\n\n## Usage with Copier\n\nThe extension integrates nicely with [Copier][copier], e.g. for validating complex JSON/YAML answers in the Copier questionnaire. For this, add the extension as a [Jinja2 extension in `copier.yml`][copier-jinja-extensions] and use the Jinja2 filter in the `validator` field of a Copier [question][copier-questions]. For instance:\n\n```yaml\n_jinja_extensions:\n - jinja2_jsonschema.JsonSchemaExtension\n\ncomplex_question:\n type: json # or `yaml`\n validator: \"{{ complex_question | jsonschema('schemas/complex.json') }}\"\n```\n\nIn this example, a local schema file `schemas/complex.json` is used whose path is relative to the template root. To prevent copying schema files to the generated project, they should be either [excluded][copier-exclude]\n\n```diff\n+_exclude:\n+ - schemas/\n _jinja_extensions:\n - jinja2_jsonschema.JsonSchemaExtension\n```\n\nor the project template should be located in a [subdirectory][copier-subdirectory] such as `template/`:\n\n```diff\n+_subdirectory_: template\n _jinja_extensions:\n - jinja2_jsonschema.JsonSchemaExtension\n```\n\nFinally, template consumers need to install the extension along with Copier. For instance with `pipx`:\n\n```shell\npipx install copier\npipx inject copier jinja2-jsonschema\n```\n\n## Contributions\n\nContributions are always welcome via filing [issues](https://github.com/copier-org/jinja2-jsonschema/issues) or submitting [pull requests](https://github.com/copier-org/jinja2-jsonschema/pulls). Please check the [contribution guide][contribution-guide] for more details.\n\n[contribution-guide]: https://github.com/copier-org/jinja2-jsonschema/blob/main/CONTRIBUTING.md\n[copier]: https://github.com/copier-org/copier\n[copier-exclude]: https://copier.readthedocs.io/en/stable/configuring/#exclude\n[copier-jinja-extensions]: https://copier.readthedocs.io/en/stable/configuring/#jinja_extensions\n[copier-questions]: https://copier.readthedocs.io/en/stable/configuring/#questions\n[copier-subdirectory]: https://copier.readthedocs.io/en/stable/configuring/#subdirectory\n[jinja]: https://jinja.palletsprojects.com\n[jinja-extensions]: https://jinja.palletsprojects.com/en/latest/extensions/\n[jinja-filter]: https://jinja.palletsprojects.com/en/latest/templates/#filters\n[jinja-test]: https://jinja.palletsprojects.com/en/latest/templates/#tests\n[jsonschema]: https://json-schema.org\n[jsonschema-dialect]: https://json-schema.org/understanding-json-schema/reference/schema.html#schema\n[jsonschema-ref]: https://json-schema.org/understanding-json-schema/structuring.html#ref\n[jsonschema-jsonpointer]: https://json-schema.org/understanding-json-schema/structuring.html#json-pointer\n[pdm]: https://pdm.fming.dev\n[pip]: https://pip.pypa.io\n[pipx]: https://pypa.github.io/pipx\n[poetry]: https://python-poetry.org\n[python-jsonschema-features]: https://python-jsonschema.readthedocs.io/en/stable/#features\n[python-jsonschema-validationerror]: https://python-jsonschema.readthedocs.io/en/stable/api/jsonschema/exceptions/#jsonschema.exceptions.ValidationError\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "JSON/YAML schema validation within Jinja2 templates",
"version": "0.3.0",
"project_urls": {
"Homepage": "https://github.com/copier-org/jinja2-jsonschema",
"Repository": "https://github.com/copier-org/jinja2-jsonschema"
},
"split_keywords": [
"extension",
" jinja",
" jinja2",
" json",
" jsonschema",
" yaml"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "912b38cb53f20d83edb0fd68faedfd311ecdae405e8c887484dcaf29a4c3010f",
"md5": "30d6aa1b6afd834ec62d312d06418325",
"sha256": "03800cfb19fd8b8a5b812099621f252beb83c4db20ab9ca59e659b291719fc6a"
},
"downloads": -1,
"filename": "jinja2_jsonschema-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "30d6aa1b6afd834ec62d312d06418325",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 6722,
"upload_time": "2024-10-16T15:38:48",
"upload_time_iso_8601": "2024-10-16T15:38:48.015964Z",
"url": "https://files.pythonhosted.org/packages/91/2b/38cb53f20d83edb0fd68faedfd311ecdae405e8c887484dcaf29a4c3010f/jinja2_jsonschema-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "538d0018457d0955998a292082e1e3a00899246bef5c3dc22386f8dbc125a1b6",
"md5": "d8731fd107960667344b94a93f48e5aa",
"sha256": "7f278ce937b7fdfef897545f1d3b3772c789c66386dd926052d7f091a5530a87"
},
"downloads": -1,
"filename": "jinja2_jsonschema-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "d8731fd107960667344b94a93f48e5aa",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 6740,
"upload_time": "2024-10-16T15:38:48",
"upload_time_iso_8601": "2024-10-16T15:38:48.923509Z",
"url": "https://files.pythonhosted.org/packages/53/8d/0018457d0955998a292082e1e3a00899246bef5c3dc22386f8dbc125a1b6/jinja2_jsonschema-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-16 15:38:48",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "copier-org",
"github_project": "jinja2-jsonschema",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "jinja2-jsonschema"
}