Skip to content

Commit

Permalink
✨Introduce JSON Schemas (#44)
Browse files Browse the repository at this point in the history
* Add tox Env to Create JSON Schemas

* Use name of schemas instead of lambdas for recursive schemas

See fuhrysteve/marshmallow-jsonschema#164

* prettier json schemas
  • Loading branch information
hf-kklein authored Feb 25, 2022
1 parent d78e09d commit 9403f85
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 16 deletions.
182 changes: 182 additions & 0 deletions json_schemas/DeepAnwendungshandbuchSchema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
{
"$ref": "#/definitions/DeepAnwendungshandbuchSchema",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AhbMetaInformationSchema": {
"additionalProperties": false,
"properties": {
"pruefidentifikator": {
"title": "pruefidentifikator",
"type": "string"
}
},
"required": ["pruefidentifikator"],
"type": "object"
},
"DataElementFreeTextSchema": {
"additionalProperties": false,
"properties": {
"ahb_expression": {
"title": "ahb_expression",
"type": "string"
},
"data_element_id": {
"title": "data_element_id",
"type": "string"
},
"discriminator": {
"title": "discriminator",
"type": "string"
},
"entered_input": {
"title": "entered_input",
"type": ["string", "null"]
},
"value_type": {
"enum": ["TEXT", "DATETIME", "VALUE_POOL"],
"title": "value_type",
"type": "string"
}
},
"required": ["ahb_expression", "data_element_id", "discriminator"],
"type": "object"
},
"DataElementValuePoolSchema": {
"additionalProperties": false,
"properties": {
"data_element_id": {
"title": "data_element_id",
"type": "string"
},
"discriminator": {
"title": "discriminator",
"type": "string"
},
"value_pool": {
"items": {
"$ref": "#/definitions/ValuePoolEntrySchema",
"type": "object"
},
"title": "value_pool",
"type": "array"
},
"value_type": {
"enum": ["TEXT", "DATETIME", "VALUE_POOL"],
"title": "value_type",
"type": "string"
}
},
"required": ["data_element_id", "discriminator", "value_pool"],
"type": "object"
},
"DeepAnwendungshandbuchSchema": {
"additionalProperties": false,
"properties": {
"lines": {
"items": {
"$ref": "#/definitions/SegmentGroupSchema",
"type": "object"
},
"title": "lines",
"type": "array"
},
"meta": {
"$ref": "#/definitions/AhbMetaInformationSchema",
"type": "object"
}
},
"type": "object"
},
"SegmentGroupSchema": {
"additionalProperties": false,
"properties": {
"ahb_expression": {
"title": "ahb_expression",
"type": "string"
},
"discriminator": {
"title": "discriminator",
"type": "string"
},
"segment_groups": {
"items": {
"$ref": "#/definitions/SegmentGroupSchema",
"type": "object"
},
"title": "segment_groups",
"type": ["array", "null"]
},
"segments": {
"items": {
"$ref": "#/definitions/SegmentSchema",
"type": "object"
},
"title": "segments",
"type": ["array", "null"]
}
},
"required": ["ahb_expression", "discriminator"],
"type": "object"
},
"SegmentSchema": {
"additionalProperties": false,
"properties": {
"ahb_expression": {
"title": "ahb_expression",
"type": "string"
},
"data_elements": {
"items": {
"$ref": "#/definitions/_FreeTextOrValuePoolSchema",
"type": "object"
},
"title": "data_elements",
"type": "array"
},
"discriminator": {
"title": "discriminator",
"type": "string"
},
"section_name": {
"title": "section_name",
"type": "string"
}
},
"required": ["ahb_expression", "discriminator"],
"type": "object"
},
"ValuePoolEntrySchema": {
"additionalProperties": false,
"properties": {
"ahb_expression": {
"title": "ahb_expression",
"type": "string"
},
"meaning": {
"title": "meaning",
"type": "string"
},
"qualifier": {
"title": "qualifier",
"type": "string"
}
},
"required": ["ahb_expression", "meaning", "qualifier"],
"type": "object"
},
"_FreeTextOrValuePoolSchema": {
"additionalProperties": false,
"properties": {
"free_text": {
"$ref": "#/definitions/DataElementFreeTextSchema",
"type": "object"
},
"value_pool": {
"$ref": "#/definitions/DataElementValuePoolSchema",
"type": "object"
}
},
"type": "object"
}
}
}
17 changes: 17 additions & 0 deletions json_schemas/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## 🐁 JSON Schemas

This directory contains [JSON Schema Draft v7](https://json-schema.org/specification-links.html#draft-7) compatible JSON
Schemas. You may use these schemas
to [autogenerate classes in the language of your choice](https://json-schema.org/implementations.html#code-generation).
This is thought to reduce manual efforts and allow for easy integration of AHBicht with other components (for example a
frontend).

### Autogenerate the Schemas using [`marshmallow-jsonschema`](https://github.com/fuhrysteve/marshmallow-jsonschema)

The files in this directory are autogenerated from the marshmallow classes that are also used for (de-)serialization.
There is a tox environment that executes [`generate_json_schemas.py`](generate_json_schemas.py) and overwrites
any `.json` files in this directory. Simply run:

```bash
tox -e json_schemas
```
28 changes: 28 additions & 0 deletions json_schemas/generate_json_schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
This script is run in the tox 'json_schemas' environment.
It creates json schema files as described in the README.md in the same directory.
"""

import json
import pathlib
from typing import List, Type

from marshmallow import Schema
from marshmallow_jsonschema import JSONSchema # type:ignore[import]

from maus.models.anwendungshandbuch import DeepAnwendungshandbuchSchema

schema_types: List[Type[Schema]] = [
DeepAnwendungshandbuchSchema
# add other schemas as you like
]
json_schema = JSONSchema()
for schema_type in schema_types:
this_directory = pathlib.Path(__file__).parent.absolute()
file_name = schema_type.__name__ + ".json" # pylint:disable=invalid-name
file_path = this_directory / file_name
schema_instance = schema_type()
json_schema_dict = json_schema.dump(schema_instance)

with open(file_path, "w", encoding="utf-8") as json_schema_file:
json.dump(json_schema_dict, json_schema_file, ensure_ascii=False, sort_keys=True, indent=4)
14 changes: 5 additions & 9 deletions src/maus/models/edifact_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,9 @@ class _FreeTextOrValuePoolSchema(Schema):
"""

# disable unnecessary lambda warning because of circular imports
free_text = fields.Nested(
lambda: DataElementFreeTextSchema(), allow_none=True, required=False # pylint: disable=unnecessary-lambda
) # fields.String(dump_default=False, required=False, allow_none=True)
value_pool = fields.Nested(
lambda: DataElementValuePoolSchema(), required=False, allow_none=True # pylint: disable=unnecessary-lambda
)
free_text = fields.Nested("DataElementFreeTextSchema", allow_none=True, required=False)
value_pool = fields.Nested("DataElementValuePoolSchema", required=False, allow_none=True)
# see https://github.com/fuhrysteve/marshmallow-jsonschema/issues/164

# pylint:disable= unused-argument, no-self-use
@post_load
Expand Down Expand Up @@ -360,9 +357,8 @@ class SegmentGroupSchema(SegmentLevelSchema):

segments = fields.List(fields.Nested(SegmentSchema), load_default=None, required=False)
segment_groups = fields.List(
fields.Nested(
lambda: SegmentGroupSchema(), # pylint: disable=unnecessary-lambda
),
fields.Nested("SegmentGroupSchema"),
# see https://github.com/fuhrysteve/marshmallow-jsonschema/issues/164
load_default=None,
required=False,
)
Expand Down
23 changes: 16 additions & 7 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[tox]
envlist =
tests
linting
coverage
type_check
tests
linting
coverage
type_check
skip_missing_interpreters = True
skipsdist = True

Expand All @@ -24,10 +24,10 @@ commands = python -m pytest --basetemp={envtmpdir} {posargs}
deps =
-rrequirements.txt
pylint
# add your fixtures like e.g. pytest_datafiles here
# add your fixtures like e.g. pytest_datafiles here
commands =
pylint src/maus
# add single files (ending with .py) or packages here
# add single files (ending with .py) or packages here

[testenv:type_check]
# the type_check environment checks the type hints using mypy
Expand All @@ -38,7 +38,7 @@ deps =
commands =
mypy --show-error-codes src/maus
mypy --show-error-codes unittests
# add single files (ending with .py) or packages here
# add single files (ending with .py) or packages here

[testenv:coverage]
# the coverage environment is called by the Github Action that runs the coverage measurement
Expand All @@ -60,6 +60,7 @@ deps =
{[testenv:type_check]deps}
{[testenv:docs]deps}
{[testenv:coverage]deps}
{[testenv:json_schemas]deps}
black
isort
pip-tools
Expand Down Expand Up @@ -91,3 +92,11 @@ commands =
sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html
sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html
python -m doctest README.rst

[testenv:json_schemas]
usedevelop = True
deps =
-rrequirements.txt
marshmallow_jsonschema
commands =
python json_schemas/generate_json_schemas.py

0 comments on commit 9403f85

Please sign in to comment.