python-datamodel 0.10.1__cp313-cp313-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datamodel/__init__.py +13 -0
- datamodel/abstract.py +383 -0
- datamodel/adaptive/__init__.py +0 -0
- datamodel/adaptive/models.py +598 -0
- datamodel/aliases/__init__.py +26 -0
- datamodel/base.py +180 -0
- datamodel/converters.c +43471 -0
- datamodel/converters.cp313-win32.pyd +0 -0
- datamodel/converters.html +17387 -0
- datamodel/converters.pyx +1489 -0
- datamodel/exceptions.c +13455 -0
- datamodel/exceptions.cp313-win32.pyd +0 -0
- datamodel/exceptions.html +1261 -0
- datamodel/exceptions.pxd +13 -0
- datamodel/exceptions.pyx +50 -0
- datamodel/fields.cp313-win32.pyd +0 -0
- datamodel/fields.cpp +17401 -0
- datamodel/fields.html +3912 -0
- datamodel/fields.pyx +309 -0
- datamodel/functions.cp313-win32.pyd +0 -0
- datamodel/functions.cpp +9068 -0
- datamodel/functions.html +1766 -0
- datamodel/functions.pxd +9 -0
- datamodel/functions.pyx +82 -0
- datamodel/jsonld/__init__.py +45 -0
- datamodel/jsonld/models.py +500 -0
- datamodel/libs/__init__.py +1 -0
- datamodel/libs/mapping.c +15067 -0
- datamodel/libs/mapping.cp313-win32.pyd +0 -0
- datamodel/libs/mapping.html +2618 -0
- datamodel/libs/mapping.pxd +11 -0
- datamodel/libs/mapping.pyx +135 -0
- datamodel/libs/mutables.py +127 -0
- datamodel/models.py +814 -0
- datamodel/parsers/__init__.py +0 -0
- datamodel/parsers/encoders.py +15 -0
- datamodel/parsers/json.cp313-win32.pyd +0 -0
- datamodel/parsers/json.cpp +17004 -0
- datamodel/parsers/json.html +3365 -0
- datamodel/parsers/json.pyx +250 -0
- datamodel/profiler.py +21 -0
- datamodel/py.typed +0 -0
- datamodel/rs_core/Cargo.toml +17 -0
- datamodel/rs_core/src/lib.rs +294 -0
- datamodel/rs_parsers/Cargo.toml +22 -0
- datamodel/rs_parsers/src/lib.rs +571 -0
- datamodel/rs_parsers.cp313-win32.pyd +0 -0
- datamodel/rs_validators/Cargo.toml +17 -0
- datamodel/rs_validators/src/lib.rs +0 -0
- datamodel/typedefs/__init__.py +9 -0
- datamodel/typedefs/singleton.c +9169 -0
- datamodel/typedefs/singleton.cp313-win32.pyd +0 -0
- datamodel/typedefs/singleton.html +629 -0
- datamodel/typedefs/singleton.pxd +9 -0
- datamodel/typedefs/singleton.pyx +24 -0
- datamodel/typedefs/types.c +11716 -0
- datamodel/typedefs/types.cp313-win32.pyd +0 -0
- datamodel/typedefs/types.html +732 -0
- datamodel/typedefs/types.pxd +11 -0
- datamodel/typedefs/types.pyx +39 -0
- datamodel/types.c +7165 -0
- datamodel/types.cp313-win32.pyd +0 -0
- datamodel/types.html +716 -0
- datamodel/types.pyx +100 -0
- datamodel/validation.cp313-win32.pyd +0 -0
- datamodel/validation.cpp +17085 -0
- datamodel/validation.html +4769 -0
- datamodel/validation.pyx +315 -0
- datamodel/version.py +13 -0
- examples/nn/examples.py +311 -0
- examples/nn/stores.py +151 -0
- examples/tests/sp_types.py +294 -0
- examples/tests/speed_dates.py +26 -0
- python_datamodel-0.10.1.dist-info/LICENSE +29 -0
- python_datamodel-0.10.1.dist-info/METADATA +320 -0
- python_datamodel-0.10.1.dist-info/RECORD +78 -0
- python_datamodel-0.10.1.dist-info/WHEEL +5 -0
- python_datamodel-0.10.1.dist-info/top_level.txt +7 -0
datamodel/base.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
# Dataclass
|
|
4
|
+
from dataclasses import (
|
|
5
|
+
_FIELD,
|
|
6
|
+
)
|
|
7
|
+
from html import escape
|
|
8
|
+
from .converters import processing_fields, register_parser
|
|
9
|
+
from .fields import Field
|
|
10
|
+
from .exceptions import ValidationError
|
|
11
|
+
from .abstract import ModelMeta
|
|
12
|
+
from .models import ModelMixin
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
RendererFn = Callable[["BaseModel", bool], str]
|
|
16
|
+
|
|
17
|
+
HTML_RENDERERS: Dict[str, RendererFn] = {}
|
|
18
|
+
|
|
19
|
+
def register_renderer(schema_type: str):
|
|
20
|
+
"""
|
|
21
|
+
Decorator to register a custom renderer function for a given schema_type.
|
|
22
|
+
"""
|
|
23
|
+
def decorator(fn: RendererFn):
|
|
24
|
+
HTML_RENDERERS[schema_type] = fn
|
|
25
|
+
return fn
|
|
26
|
+
return decorator
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class BaseModel(ModelMixin, metaclass=ModelMeta):
|
|
30
|
+
"""
|
|
31
|
+
BaseModel.
|
|
32
|
+
Base Model for all DataModels.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __post_init__(self) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Post init method.
|
|
38
|
+
Fill fields with function-factory or calling validations
|
|
39
|
+
"""
|
|
40
|
+
# checking if an attribute is already a dataclass:
|
|
41
|
+
columns = list(self.__columns__.items())
|
|
42
|
+
|
|
43
|
+
if errors := processing_fields(self, columns):
|
|
44
|
+
if self.Meta.strict is True:
|
|
45
|
+
raise ValidationError(
|
|
46
|
+
f"""{self.modelName}: There are errors in Model. \
|
|
47
|
+
Hint: please check the "payload" attribute in the exception.""",
|
|
48
|
+
payload=errors
|
|
49
|
+
)
|
|
50
|
+
self.__errors__ = errors
|
|
51
|
+
object.__setattr__(self, "__valid__", False)
|
|
52
|
+
else:
|
|
53
|
+
object.__setattr__(self, "__valid__", True)
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def register_parser(
|
|
57
|
+
cls,
|
|
58
|
+
target_type: Any,
|
|
59
|
+
func: Callable,
|
|
60
|
+
field_name: str = None
|
|
61
|
+
):
|
|
62
|
+
key = (target_type, field_name) if field_name else target_type
|
|
63
|
+
register_parser(key, func)
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def add_field(cls, name: str, value: Any = None) -> None:
|
|
67
|
+
if cls.Meta.strict is True:
|
|
68
|
+
raise TypeError(
|
|
69
|
+
f'Cannot create a new field {name} on a Strict Model.'
|
|
70
|
+
)
|
|
71
|
+
if name != '__errors__':
|
|
72
|
+
f = Field(required=False, default=value)
|
|
73
|
+
f.name = name
|
|
74
|
+
f.type = type(value)
|
|
75
|
+
f._field_type = _FIELD
|
|
76
|
+
cls.__columns__[name] = f
|
|
77
|
+
cls.__dataclass_fields__[name] = f
|
|
78
|
+
|
|
79
|
+
def create_field(self, name: str, value: Any) -> None:
|
|
80
|
+
"""create_field.
|
|
81
|
+
create a new Field on Model (when strict is False).
|
|
82
|
+
Args:
|
|
83
|
+
name (str): name of the field
|
|
84
|
+
value (Any): value to be assigned.
|
|
85
|
+
Raises:
|
|
86
|
+
TypeError: when try to create a new field on an Strict Model.
|
|
87
|
+
"""
|
|
88
|
+
if self.Meta.strict is True:
|
|
89
|
+
raise TypeError(
|
|
90
|
+
f'Cannot create a new field {name} on a Strict Model.'
|
|
91
|
+
)
|
|
92
|
+
if name != '__errors__':
|
|
93
|
+
f = Field(required=False, default=value)
|
|
94
|
+
f.name = name
|
|
95
|
+
f.type = type(value)
|
|
96
|
+
f._field_type = _FIELD
|
|
97
|
+
self.__columns__[name] = f
|
|
98
|
+
self.__dataclass_fields__[name] = f
|
|
99
|
+
setattr(self, name, value)
|
|
100
|
+
|
|
101
|
+
def set(self, name: str, value: Any) -> None:
|
|
102
|
+
"""set.
|
|
103
|
+
Alias for Create Field.
|
|
104
|
+
Args:
|
|
105
|
+
name (str): name of the field
|
|
106
|
+
value (Any): value to be assigned.
|
|
107
|
+
"""
|
|
108
|
+
if name in self.__columns__:
|
|
109
|
+
setattr(self, name, value)
|
|
110
|
+
elif name != '__errors__' and self.Meta.strict is False:
|
|
111
|
+
self.create_field(name, value)
|
|
112
|
+
|
|
113
|
+
def get_errors(self):
|
|
114
|
+
return self.__errors__
|
|
115
|
+
|
|
116
|
+
def to_html(self, top_level: bool = True) -> str:
|
|
117
|
+
"""to_html.
|
|
118
|
+
Convert Model to HTML.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
top_level (bool, optional): If True, adds the @context to the schema.
|
|
122
|
+
"""
|
|
123
|
+
# 1) Determine the schema type from self.Meta or fallback to class name
|
|
124
|
+
schema_type = getattr(self.Meta, 'schema_type', self.__class__.__name__)
|
|
125
|
+
|
|
126
|
+
if schema_type in HTML_RENDERERS:
|
|
127
|
+
return HTML_RENDERERS[schema_type](self, top_level)
|
|
128
|
+
|
|
129
|
+
# 2) Container opening. For top-level objects, we specify:
|
|
130
|
+
# - vocab="https://schema.org/"
|
|
131
|
+
# - typeof="Recipe" (or other type)
|
|
132
|
+
# For nested objects, we might omit the 'vocab' attribute
|
|
133
|
+
# or rely on the parent's scope.
|
|
134
|
+
if top_level:
|
|
135
|
+
container_open = f'<div vocab="https://schema.org/" typeof="{escape(schema_type)}">'
|
|
136
|
+
else:
|
|
137
|
+
container_open = f'<div property="{escape(schema_type)}" typeof="{escape(schema_type)}">'
|
|
138
|
+
|
|
139
|
+
# We'll accumulate our HTML pieces here
|
|
140
|
+
pieces = [container_open]
|
|
141
|
+
|
|
142
|
+
# 3) Iterate over each field in this model
|
|
143
|
+
for field_name, value in self.__dict__.items():
|
|
144
|
+
# Skip internal or error fields
|
|
145
|
+
if field_name.startswith('_') or field_name == '__errors__':
|
|
146
|
+
continue
|
|
147
|
+
|
|
148
|
+
# Optionally skip if None
|
|
149
|
+
if value is None:
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
# 4) If value is a nested model, convert it to HTML as well
|
|
153
|
+
if isinstance(value, BaseModel):
|
|
154
|
+
nested_html = value.to_html(False)
|
|
155
|
+
snippet = f'<div property="{escape(field_name)}">\n{nested_html}\n</div>'
|
|
156
|
+
pieces.append(snippet)
|
|
157
|
+
|
|
158
|
+
elif isinstance(value, list):
|
|
159
|
+
# We might iterate and produce multiple lines
|
|
160
|
+
for item in value:
|
|
161
|
+
if isinstance(item, BaseModel):
|
|
162
|
+
nested_html = item.to_html(False)
|
|
163
|
+
snippet = f'<div property="{escape(field_name)}">\n{nested_html}\n</div>'
|
|
164
|
+
else:
|
|
165
|
+
# If it's a simple scalar, just output a <span>
|
|
166
|
+
# e.g.: <span property="recipeIngredient">3 bananas</span>
|
|
167
|
+
val_escaped = escape(str(item))
|
|
168
|
+
snippet = f'<span property="{escape(field_name)}">{val_escaped}</span>'
|
|
169
|
+
pieces.append(snippet)
|
|
170
|
+
else:
|
|
171
|
+
# For simple scalars (str, int, etc.):
|
|
172
|
+
# We might choose <span> or <meta> based on type.
|
|
173
|
+
# We'll do something simple: a <span>
|
|
174
|
+
val_escaped = escape(str(value))
|
|
175
|
+
snippet = f'<span property="{escape(field_name)}">{val_escaped}</span>'
|
|
176
|
+
pieces.append(snippet)
|
|
177
|
+
|
|
178
|
+
# 4) Close the container
|
|
179
|
+
pieces.append('</div>')
|
|
180
|
+
return "\n".join(pieces)
|