python-datamodel 0.6.28__cp313-cp313-win_amd64.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 +189 -0
- datamodel/base.py +639 -0
- datamodel/converters.c +25347 -0
- datamodel/converters.cp313-win_amd64.pyd +0 -0
- datamodel/exceptions.c +13079 -0
- datamodel/exceptions.cp313-win_amd64.pyd +0 -0
- datamodel/fields.cp313-win_amd64.pyd +0 -0
- datamodel/fields.cpp +16655 -0
- datamodel/libs/__init__.py +0 -0
- datamodel/libs/mapping.c +14796 -0
- datamodel/libs/mapping.cp313-win_amd64.pyd +0 -0
- datamodel/libs/mutables.py +116 -0
- datamodel/models.py +111 -0
- datamodel/parsers/__init__.py +0 -0
- datamodel/parsers/encoders.py +15 -0
- datamodel/parsers/json.cp313-win_amd64.pyd +0 -0
- datamodel/parsers/json.cpp +12976 -0
- datamodel/profiler.py +21 -0
- datamodel/types.c +7137 -0
- datamodel/types.cp313-win_amd64.pyd +0 -0
- datamodel/validation.cp313-win_amd64.pyd +0 -0
- datamodel/validation.cpp +13275 -0
- datamodel/version.py +10 -0
- python_datamodel-0.6.28.dist-info/LICENSE +29 -0
- python_datamodel-0.6.28.dist-info/METADATA +316 -0
- python_datamodel-0.6.28.dist-info/RECORD +29 -0
- python_datamodel-0.6.28.dist-info/WHEEL +5 -0
- python_datamodel-0.6.28.dist-info/top_level.txt +1 -0
datamodel/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""DataModels.
|
|
3
|
+
|
|
4
|
+
DataModel is a reimplementation of dataclasses with true inheritance and composition.
|
|
5
|
+
"""
|
|
6
|
+
from datamodel.fields import Field, Column, fields
|
|
7
|
+
from .models import Model
|
|
8
|
+
from .base import BaseModel
|
|
9
|
+
from .version import (
|
|
10
|
+
__title__, __description__, __version__, __author__, __author_email__
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = ('fields', 'Field', 'Column', 'Model', 'BaseModel', )
|
datamodel/abstract.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional, Union, Any
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from collections import OrderedDict
|
|
5
|
+
import types
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from .parsers.json import JSONContent
|
|
8
|
+
from .fields import Field
|
|
9
|
+
|
|
10
|
+
class Meta:
|
|
11
|
+
"""
|
|
12
|
+
Metadata information about Model.
|
|
13
|
+
"""
|
|
14
|
+
name: str = ""
|
|
15
|
+
description: str = ""
|
|
16
|
+
schema: str = ""
|
|
17
|
+
app_label: str = ""
|
|
18
|
+
frozen: bool = False
|
|
19
|
+
strict: bool = True
|
|
20
|
+
driver: str = None
|
|
21
|
+
credentials: dict = Optional[dict]
|
|
22
|
+
dsn: Optional[str] = None
|
|
23
|
+
datasource: Optional[str] = None
|
|
24
|
+
connection: Optional[Callable] = None
|
|
25
|
+
remove_nulls: bool = False
|
|
26
|
+
endpoint: str = ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def set_connection(cls, conn: Callable):
|
|
30
|
+
cls.connection = conn
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _dc_method_setattr_(
|
|
34
|
+
self,
|
|
35
|
+
name: str,
|
|
36
|
+
value: Any,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""
|
|
39
|
+
_dc_method_setattr_.
|
|
40
|
+
Method for overwrite the "setattr" on Dataclasses.
|
|
41
|
+
"""
|
|
42
|
+
# Initialize __values__ if it doesn't exist
|
|
43
|
+
if not hasattr(self, '__values__'):
|
|
44
|
+
object.__setattr__(self, '__values__', {})
|
|
45
|
+
|
|
46
|
+
# Check if the attribute is a field
|
|
47
|
+
if name in self.__fields__:
|
|
48
|
+
# Only store the initial value:
|
|
49
|
+
if name not in self.__values__:
|
|
50
|
+
# Store the initial value in __values__
|
|
51
|
+
self.__values__[name] = value
|
|
52
|
+
|
|
53
|
+
if self.Meta.frozen is True and name not in self.__fields__:
|
|
54
|
+
raise TypeError(
|
|
55
|
+
f"Cannot add New attribute {name} on {self.modelName}, "
|
|
56
|
+
"This DataClass is frozen (read-only class)"
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
value = None if callable(value) else value
|
|
60
|
+
object.__setattr__(self, name, value)
|
|
61
|
+
if name == '__values__':
|
|
62
|
+
return
|
|
63
|
+
if name not in self.__fields__:
|
|
64
|
+
if self.Meta.strict is True:
|
|
65
|
+
return False
|
|
66
|
+
try:
|
|
67
|
+
# create a new Field on Model.
|
|
68
|
+
f = Field(required=False, default=value)
|
|
69
|
+
f.name = name
|
|
70
|
+
f.type = type(value)
|
|
71
|
+
self.__columns__[name] = f
|
|
72
|
+
self.__fields__.append(name)
|
|
73
|
+
setattr(self, name, value)
|
|
74
|
+
except Exception as err:
|
|
75
|
+
logging.exception(err, stack_info=True)
|
|
76
|
+
raise
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def create_dataclass(
|
|
80
|
+
new_cls: Union[object, Any],
|
|
81
|
+
strict: bool = False,
|
|
82
|
+
frozen: bool = False
|
|
83
|
+
) -> Callable:
|
|
84
|
+
"""
|
|
85
|
+
create_dataclass.
|
|
86
|
+
Create a Dataclass from a simple Class.
|
|
87
|
+
"""
|
|
88
|
+
dc = dataclass(
|
|
89
|
+
unsafe_hash=strict,
|
|
90
|
+
repr=False,
|
|
91
|
+
init=True,
|
|
92
|
+
order=False,
|
|
93
|
+
eq=True,
|
|
94
|
+
frozen=frozen
|
|
95
|
+
)(new_cls)
|
|
96
|
+
dc.__values__: dict = {}
|
|
97
|
+
# adding a properly internal json encoder:
|
|
98
|
+
dc.__encoder__: Any = JSONContent
|
|
99
|
+
dc.__valid__: bool = False
|
|
100
|
+
dc.__errors__: Union[list, None] = None
|
|
101
|
+
dc.__frozen__: bool = strict
|
|
102
|
+
dc.__initialised__: bool = False
|
|
103
|
+
setattr(dc, "__setattr__", _dc_method_setattr_)
|
|
104
|
+
dc.modelName = dc.__name__
|
|
105
|
+
return dc
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ModelMeta(type):
|
|
109
|
+
|
|
110
|
+
def __new__(cls, name, bases, attrs, **kwargs):
|
|
111
|
+
cols = OrderedDict()
|
|
112
|
+
strict = False
|
|
113
|
+
if "__annotations__" in attrs:
|
|
114
|
+
annotations = attrs.get('__annotations__', {})
|
|
115
|
+
try:
|
|
116
|
+
strict = attrs['Meta'].strict
|
|
117
|
+
except (TypeError, AttributeError, KeyError):
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def _initialize_fields(attrs, annotations, strict):
|
|
122
|
+
cols = OrderedDict()
|
|
123
|
+
for field, _type in annotations.items():
|
|
124
|
+
if isinstance(_type, Field):
|
|
125
|
+
_type = _type.type
|
|
126
|
+
df = attrs.get(
|
|
127
|
+
field,
|
|
128
|
+
Field(type=_type, required=False, default=None)
|
|
129
|
+
)
|
|
130
|
+
if not isinstance(df, Field):
|
|
131
|
+
df = Field(required=False, type=_type, default=df)
|
|
132
|
+
df.name = field
|
|
133
|
+
df.type = _type
|
|
134
|
+
cols[field] = df
|
|
135
|
+
attrs[field] = df
|
|
136
|
+
return cols
|
|
137
|
+
|
|
138
|
+
cols = _initialize_fields(attrs, annotations, strict)
|
|
139
|
+
_columns = cols.keys()
|
|
140
|
+
cls.__slots__ = tuple(_columns)
|
|
141
|
+
attr_meta = attrs.pop("Meta", None)
|
|
142
|
+
new_cls = super().__new__(cls, name, bases, attrs, **kwargs)
|
|
143
|
+
new_cls.Meta = attr_meta or getattr(new_cls, "Meta", Meta)
|
|
144
|
+
new_cls.__dataclass_fields__ = cols
|
|
145
|
+
if not new_cls.Meta:
|
|
146
|
+
new_cls.Meta = Meta
|
|
147
|
+
new_cls.Meta.set_connection = types.MethodType(
|
|
148
|
+
set_connection, new_cls.Meta
|
|
149
|
+
)
|
|
150
|
+
try:
|
|
151
|
+
frozen = new_cls.Meta.frozen
|
|
152
|
+
except AttributeError:
|
|
153
|
+
new_cls.Meta.frozen = False
|
|
154
|
+
frozen = False
|
|
155
|
+
# mix values from Meta to an existing Meta Class
|
|
156
|
+
new_cls.Meta.__annotations__ = Meta.__annotations__
|
|
157
|
+
for key, _ in Meta.__annotations__.items():
|
|
158
|
+
if not hasattr(new_cls.Meta, key):
|
|
159
|
+
try:
|
|
160
|
+
setattr(new_cls.Meta, key, None)
|
|
161
|
+
except AttributeError as e:
|
|
162
|
+
logging.warning(
|
|
163
|
+
f'Missing Meta Key: {key}, {e}'
|
|
164
|
+
)
|
|
165
|
+
# adding a "class init method"
|
|
166
|
+
try:
|
|
167
|
+
new_cls.__model_init__(
|
|
168
|
+
new_cls,
|
|
169
|
+
name,
|
|
170
|
+
attrs
|
|
171
|
+
)
|
|
172
|
+
except AttributeError:
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
# Create the dataclass once
|
|
176
|
+
dc = create_dataclass(
|
|
177
|
+
new_cls,
|
|
178
|
+
strict=new_cls.Meta.strict,
|
|
179
|
+
frozen=frozen
|
|
180
|
+
)
|
|
181
|
+
dc.__columns__ = cols
|
|
182
|
+
dc.__fields__ = list(_columns)
|
|
183
|
+
return dc
|
|
184
|
+
|
|
185
|
+
def __init__(cls, *args, **kwargs) -> None:
|
|
186
|
+
# Initialized Data Model = True
|
|
187
|
+
cls.__initialised__ = True
|
|
188
|
+
cls.__errors__ = None
|
|
189
|
+
super().__init__(*args, **kwargs)
|