"""
Code generator for data models from schema.json descriptions
"""
import json
import shutil
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Union, Dict, Any, Type
from urllib import parse
from uuid import uuid4
from datamodel_code_generator import InputFileType, generate, ParseResult
from pydantic import create_model
from filip.models.ngsi_v2.context import ContextAttribute, ContextEntity
[docs]def create_data_model_file(*,
path: Union[Path, str],
url: str = None,
schema: Union[Path, str, ParseResult] = None,
schema_type: Union[str, InputFileType] =
InputFileType.JsonSchema,
class_name: str = None
) -> None:
"""
This will create a data model from data model definitions. The schemas
can either downloaded from a url or passed as str or dict. Allowed input
types are defined but the underlying toolbox.
Many data models suited for FIWARE are located here:
https://github.com/smart-data-models/data-models
Args:
path:
path where the generated code should saved
url:
url to download the definition from
schema_type (str):
`auto`, `openapi`, `jsonschema`, `json`, `yaml`, `dict`, `csv`
class_name:
classname for the model class
Returns:
None
Examples::
{
"type": "object",
"properties": {
"number": {
"type": "number"
},
"street_name": {
"type": "string"
},
"street_type": {
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
}
}
}
"""
if isinstance(path, str):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
if isinstance(schema_type, str):
schema_type = InputFileType(schema_type)
with TemporaryDirectory() as temp:
temp = Path(temp)
output = Path(temp).joinpath(f'{uuid4()}.py')
if url:
schema = parse.urlparse(url)
if not schema:
raise ValueError("Missing argument! Either 'url' or 'schema' "
"must be provided")
generate(
input_=schema,
input_file_type=schema_type,
output=output,
class_name=class_name)
# move temporary file to output directory
shutil.move(str(output), str(path))
[docs]def create_context_entity_model(name: str = None,
data: Dict = None,
validators: Dict[str, Any] = None,
path: Union[Path, str] = None) -> \
Type['ContextEntity']:
r"""
Creates a ContextEntity-Model from a dict:
Args:
name:
name of the model
data:
dictionary containing the data structure
validators (optional):
validators for the new model
path:
if present the model will written to *.py file if file ending
*.py is used and to json-schema if *.json is used.
Example:
>>> def username_alphanumeric(cls, value):
assert v.value.isalnum(), 'must be numeric'
return value
>>> model = create_context_entity_model(
name='MyModel',
data={
'id': 'MyId',
'type':'MyType',
'temp': 'MyProperty'}
{'validate_test': validator('temperature')(
username_alphanumeric)})
Returns:
ContextEntity
"""
properties = {key: (ContextAttribute, ...) for key in data.keys() if
key not in ContextEntity.model_fields}
model = create_model(
__model_name=name or 'GeneratedContextEntity',
__base__=ContextEntity,
__validators__=validators or {},
**properties
)
# if path exits a file will be generated that contains the model
if path:
if isinstance(path, str):
path=Path(path)
with TemporaryDirectory() as temp:
temp = Path(temp)
output = Path(temp).joinpath(f'{uuid4()}.json')
output.touch(exist_ok=True)
with output.open('w') as f:
json.dump(model.model_json_schema(), f, indent=2)
if path.suffix == '.json':
# move temporary file to output directory
shutil.move(str(output), str(path))
elif path.suffix == '.py':
create_data_model_file(path=path,
schema=output,
class_name=name)
return model