Coverage for filip/utils/model_generation.py: 38%
42 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-02-13 10:20 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-02-13 10:20 +0000
1"""
2Code generator for data models from schema.json descriptions
3"""
5import json
6import shutil
7from pathlib import Path
8from tempfile import TemporaryDirectory
9from typing import Union, Dict, Any, Type
10from urllib import parse
11from uuid import uuid4
12from datamodel_code_generator import InputFileType, generate, ParseResult
13from pydantic import create_model
15from filip.models.ngsi_v2.context import ContextAttribute, ContextEntity
18def create_data_model_file(
19 *,
20 path: Union[Path, str],
21 url: str = None,
22 schema: Union[Path, str, ParseResult] = None,
23 schema_type: Union[str, InputFileType] = InputFileType.JsonSchema,
24 class_name: str = None,
25) -> None:
26 """
27 This will create a data model from data model definitions. The schemas
28 can either downloaded from a url or passed as str or dict. Allowed input
29 types are defined but the underlying toolbox.
31 Many data models suited for FIWARE are located here:
32 https://github.com/smart-data-models/data-models
34 Args:
35 path:
36 path where the generated code should saved
37 url:
38 url to download the definition from
39 schema_type (str):
40 `auto`, `openapi`, `jsonschema`, `json`, `yaml`, `dict`, `csv`
41 class_name:
42 classname for the model class
44 Returns:
45 None
47 Examples::
49 {
50 "type": "object",
51 "properties": {
52 "number": {
53 "type": "number"
54 },
55 "street_name": {
56 "type": "string"
57 },
58 "street_type": {
59 "type": "string",
60 "enum": ["Street", "Avenue", "Boulevard"]
61 }
62 }
63 }
64 """
65 if isinstance(path, str):
66 path = Path(path)
67 path.parent.mkdir(parents=True, exist_ok=True)
69 if isinstance(schema_type, str):
70 schema_type = InputFileType(schema_type)
72 with TemporaryDirectory() as temp:
73 temp = Path(temp)
74 output = Path(temp).joinpath(f"{uuid4()}.py")
76 if url:
77 schema = parse.urlparse(url)
78 if not schema:
79 raise ValueError(
80 "Missing argument! Either 'url' or 'schema' " "must be provided"
81 )
83 generate(
84 input_=schema,
85 input_file_type=schema_type,
86 output=output,
87 class_name=class_name,
88 )
90 # move temporary file to output directory
91 shutil.move(str(output), str(path))
94def create_context_entity_model(
95 name: str = None,
96 data: Dict = None,
97 validators: Dict[str, Any] = None,
98 path: Union[Path, str] = None,
99) -> Type["ContextEntity"]:
100 r"""
101 Creates a ContextEntity-Model from a dict:
103 Args:
104 name:
105 name of the model
106 data:
107 dictionary containing the data structure
108 validators (optional):
109 validators for the new model
110 path:
111 if present the model will written to *.py file if file ending
112 *.py is used and to json-schema if *.json is used.
114 Example:
116 >>> def username_alphanumeric(cls, value):
117 assert v.value.isalnum(), 'must be numeric'
118 return value
120 >>> model = create_context_entity_model(
121 name='MyModel',
122 data={
123 'id': 'MyId',
124 'type':'MyType',
125 'temp': 'MyProperty'}
126 {'validate_test': validator('temperature')(
127 username_alphanumeric)})
129 Returns:
130 ContextEntity
132 """
133 properties = {
134 key: (ContextAttribute, ...)
135 for key in data.keys()
136 if key not in ContextEntity.model_fields
137 }
138 model = create_model(
139 __model_name=name or "GeneratedContextEntity",
140 __base__=ContextEntity,
141 __validators__=validators or {},
142 **properties,
143 )
145 # if path exits a file will be generated that contains the model
146 if path:
147 if isinstance(path, str):
148 path = Path(path)
150 with TemporaryDirectory() as temp:
151 temp = Path(temp)
152 output = Path(temp).joinpath(f"{uuid4()}.json")
153 output.touch(exist_ok=True)
154 with output.open("w") as f:
155 json.dump(model.model_json_schema(), f, indent=2)
156 if path.suffix == ".json":
157 # move temporary file to output directory
158 shutil.move(str(output), str(path))
159 elif path.suffix == ".py":
160 create_data_model_file(path=path, schema=output, class_name=name)
161 return model