python-datamodel 0.10.1__cp311-cp311-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.cp311-win32.pyd +0 -0
- datamodel/converters.html +17387 -0
- datamodel/converters.pyx +1489 -0
- datamodel/exceptions.c +13455 -0
- datamodel/exceptions.cp311-win32.pyd +0 -0
- datamodel/exceptions.html +1261 -0
- datamodel/exceptions.pxd +13 -0
- datamodel/exceptions.pyx +50 -0
- datamodel/fields.cp311-win32.pyd +0 -0
- datamodel/fields.cpp +17401 -0
- datamodel/fields.html +3912 -0
- datamodel/fields.pyx +309 -0
- datamodel/functions.cp311-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.cp311-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.cp311-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.cp311-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.cp311-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.cp311-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.cp311-win32.pyd +0 -0
- datamodel/types.html +716 -0
- datamodel/types.pyx +100 -0
- datamodel/validation.cp311-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/__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,383 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Optional, Any, List, Dict, get_args, get_origin, ClassVar
|
|
4
|
+
from types import GenericAlias
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
import types
|
|
8
|
+
from inspect import isclass
|
|
9
|
+
from dataclasses import dataclass, InitVar
|
|
10
|
+
from .parsers.json import JSONContent
|
|
11
|
+
from .converters import encoders, parse_basic
|
|
12
|
+
from .validation import validators
|
|
13
|
+
from .fields import Field
|
|
14
|
+
from .functions import (
|
|
15
|
+
is_dataclass,
|
|
16
|
+
is_primitive
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
class Meta:
|
|
20
|
+
"""
|
|
21
|
+
Metadata information about Model.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
name: str = "" name of the model
|
|
25
|
+
description: str = "" description of the model
|
|
26
|
+
schema: str = "" schema of the model (optional)
|
|
27
|
+
frozen: bool = False if the model (dataclass) is read-only (frozen state)
|
|
28
|
+
strict: bool = True if the model (dataclass) should raise an error on invalid data.
|
|
29
|
+
remove_null: bool = True if the model should remove null values from the data.
|
|
30
|
+
validate_assignment: bool = True if the model should validate during assignment.
|
|
31
|
+
"""
|
|
32
|
+
name: str = ""
|
|
33
|
+
description: str = ""
|
|
34
|
+
schema: str = ""
|
|
35
|
+
frozen: bool = False
|
|
36
|
+
strict: bool = True
|
|
37
|
+
driver: str = None
|
|
38
|
+
credentials: dict = Optional[dict]
|
|
39
|
+
dsn: Optional[str] = None
|
|
40
|
+
datasource: Optional[str] = None
|
|
41
|
+
connection: Optional[Callable] = None
|
|
42
|
+
remove_nulls: bool = False
|
|
43
|
+
endpoint: str
|
|
44
|
+
extra: str = 'forbid' # could be 'allow', 'ignore', or 'forbid'
|
|
45
|
+
validate_assignment: bool = False
|
|
46
|
+
as_objects: bool = False
|
|
47
|
+
no_nesting: bool = False
|
|
48
|
+
alias_function: Optional[Callable] = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def set_connection(cls, conn: Callable):
|
|
52
|
+
cls.connection = conn
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _dc_method_setattr_(self, name: str, value: Any) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Simplified __setattr__ for dataclass-like objects.
|
|
58
|
+
|
|
59
|
+
This version separates the known-field assignment (with optional validation)
|
|
60
|
+
from the “extra field” assignment and uses a helper to perform conversion/validation.
|
|
61
|
+
"""
|
|
62
|
+
# Ensure that the __values__ dict is present.
|
|
63
|
+
if not hasattr(self, '__values__'):
|
|
64
|
+
object.__setattr__(self, '__values__', {})
|
|
65
|
+
|
|
66
|
+
# Check whether we are assigning to a known field.
|
|
67
|
+
if name in self.__fields__:
|
|
68
|
+
# Save the initial value (only once).
|
|
69
|
+
self.__values__.setdefault(name, value)
|
|
70
|
+
|
|
71
|
+
# If assignment validation is active, convert the value.
|
|
72
|
+
if self.Meta.validate_assignment:
|
|
73
|
+
value = _validate_field_assignment(self, name, value)
|
|
74
|
+
object.__setattr__(self, name, value)
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
# If the class is frozen, do not allow new attributes.
|
|
78
|
+
if self.Meta.frozen:
|
|
79
|
+
raise TypeError(
|
|
80
|
+
f"Cannot add new attribute {name!r} on {self.modelName} "
|
|
81
|
+
"(the class is frozen)"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# For extra attributes, store them as usual.
|
|
85
|
+
# (Note: here we “neutralize” any callable value to None if needed.)
|
|
86
|
+
object.__setattr__(self, name, None if callable(value) else value)
|
|
87
|
+
if name == '__values__':
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
# If the field isn’t known yet:
|
|
91
|
+
if name not in self.__fields__:
|
|
92
|
+
# In strict mode, we don’t allow unknown fields.
|
|
93
|
+
if self.Meta.strict:
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
# Otherwise, check the "extra" policy.
|
|
97
|
+
extra_policy = self.Meta.extra
|
|
98
|
+
if extra_policy == 'forbid':
|
|
99
|
+
raise TypeError(f"Field {name!r} is not allowed on {self.modelName}")
|
|
100
|
+
elif extra_policy == 'ignore':
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
# Dynamically create a new Field for the unknown attribute.
|
|
104
|
+
try:
|
|
105
|
+
new_field = Field(required=False, default=value)
|
|
106
|
+
new_field.name = name
|
|
107
|
+
new_field.type = type(value)
|
|
108
|
+
# (Optionally, you might attach a parser here if validation is on.)
|
|
109
|
+
self.__columns__[name] = new_field
|
|
110
|
+
self.__fields__.append(name)
|
|
111
|
+
object.__setattr__(self, name, value)
|
|
112
|
+
except Exception as err:
|
|
113
|
+
logging.exception(err, stack_info=True)
|
|
114
|
+
raise
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _validate_field_assignment(self, name: str, value: Any) -> Any:
|
|
118
|
+
"""
|
|
119
|
+
Helper that applies field conversion/validation based on cached field info.
|
|
120
|
+
|
|
121
|
+
If you cache the parser (or the type-category) on the Field during model creation,
|
|
122
|
+
this helper could simply call that parser.
|
|
123
|
+
"""
|
|
124
|
+
field_obj = self.__columns__[name]
|
|
125
|
+
# _type = field_obj.type
|
|
126
|
+
# _encoder = field_obj.metadata.get('encoder')
|
|
127
|
+
# Retrieve the field category (pre‐computed at class creation)
|
|
128
|
+
# field_category = self.__field_types__.get(name, 'complex')
|
|
129
|
+
try:
|
|
130
|
+
return field_obj.parser(value) if field_obj.parser else value
|
|
131
|
+
except Exception as e:
|
|
132
|
+
raise TypeError(
|
|
133
|
+
f"Cannot assign {value!r} to field {name!r}: {e}"
|
|
134
|
+
) from e
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class ModelMeta(type):
|
|
138
|
+
"""ModelMeta.
|
|
139
|
+
|
|
140
|
+
Metaclass for DataModels, convert any Model into a dataclass-compatible object.
|
|
141
|
+
"""
|
|
142
|
+
__columns__: Dict
|
|
143
|
+
__fields__: List
|
|
144
|
+
__field_types__: List
|
|
145
|
+
__aliases__: Dict
|
|
146
|
+
|
|
147
|
+
def __new__(cls, name, bases, attrs, **kwargs): # noqa
|
|
148
|
+
cols = OrderedDict()
|
|
149
|
+
strict = False
|
|
150
|
+
cls.__field_types__ = {}
|
|
151
|
+
cls.__typing_args__ = {}
|
|
152
|
+
cls.__aliases__ = {}
|
|
153
|
+
_types = {}
|
|
154
|
+
_typing_args = {}
|
|
155
|
+
aliases = {}
|
|
156
|
+
|
|
157
|
+
if "__annotations__" in attrs:
|
|
158
|
+
annotations = attrs.get('__annotations__', {})
|
|
159
|
+
with contextlib.suppress(TypeError, AttributeError, KeyError):
|
|
160
|
+
strict = attrs['Meta'].strict
|
|
161
|
+
|
|
162
|
+
@staticmethod
|
|
163
|
+
def _initialize_fields(attrs, annotations, strict):
|
|
164
|
+
cols = OrderedDict()
|
|
165
|
+
_types_local = {}
|
|
166
|
+
_typing_args = {}
|
|
167
|
+
aliases = {}
|
|
168
|
+
for field, _type in annotations.items():
|
|
169
|
+
if isinstance(_type, InitVar) or _type == InitVar:
|
|
170
|
+
# Skip InitVar fields;
|
|
171
|
+
# they should not be part of the dataclass instance
|
|
172
|
+
continue
|
|
173
|
+
origin = get_origin(_type)
|
|
174
|
+
if origin is ClassVar:
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
# Check if the field's default value is a descriptor
|
|
178
|
+
default_value = attrs.get(field, None)
|
|
179
|
+
is_descriptor = any(
|
|
180
|
+
hasattr(default_value, method)
|
|
181
|
+
for method in ("__get__", "__set__", "__delete__")
|
|
182
|
+
)
|
|
183
|
+
# Handle the descriptor field
|
|
184
|
+
if is_descriptor:
|
|
185
|
+
default_value._type_category = 'descriptor'
|
|
186
|
+
cols[field] = default_value
|
|
187
|
+
_types_local[field] = 'descriptor'
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
if isinstance(_type, Field):
|
|
191
|
+
_type = _type.type
|
|
192
|
+
df = attrs.get(
|
|
193
|
+
field,
|
|
194
|
+
Field(type=_type, required=False, default=None)
|
|
195
|
+
)
|
|
196
|
+
if df is not None and isinstance(df, Field):
|
|
197
|
+
alias = df.metadata.get("alias", None)
|
|
198
|
+
if alias:
|
|
199
|
+
aliases[alias] = field
|
|
200
|
+
if not isinstance(df, Field):
|
|
201
|
+
df = Field(required=False, type=_type, default=df)
|
|
202
|
+
df.name = field
|
|
203
|
+
df.type = _type
|
|
204
|
+
|
|
205
|
+
# Cache reflection info so we DON’T need to call
|
|
206
|
+
# get_origin/get_args repeatedly:
|
|
207
|
+
args = get_args(_type)
|
|
208
|
+
_default = df.default
|
|
209
|
+
_is_dc = is_dataclass(_type)
|
|
210
|
+
_is_prim = is_primitive(_type)
|
|
211
|
+
_is_alias = isinstance(_type, GenericAlias)
|
|
212
|
+
_is_typing = hasattr(_type, '__module__') and _type.__module__ == 'typing' # noqa
|
|
213
|
+
|
|
214
|
+
# Store the type info in the field object:
|
|
215
|
+
df.is_dc = _is_dc
|
|
216
|
+
df.is_primitive = _is_prim
|
|
217
|
+
df.is_typing = _is_typing
|
|
218
|
+
df.origin = origin
|
|
219
|
+
df.args = args
|
|
220
|
+
df.type_args = getattr(_type, '__args__', None)
|
|
221
|
+
|
|
222
|
+
df._typeinfo_ = {
|
|
223
|
+
"default_callable": callable(_default)
|
|
224
|
+
}
|
|
225
|
+
# Current Field have an Encoder Function.
|
|
226
|
+
custom_encoder = df.metadata.get("encoder")
|
|
227
|
+
try:
|
|
228
|
+
df.parser = encoders[_type]
|
|
229
|
+
except (TypeError, KeyError):
|
|
230
|
+
df.parser = None
|
|
231
|
+
if custom_encoder:
|
|
232
|
+
df.parser = lambda value, _type=_type, encoder=custom_encoder: parse_basic(_type, value, encoder) # noqa
|
|
233
|
+
# Caching Validator:
|
|
234
|
+
try:
|
|
235
|
+
df.validator = validators[_type]
|
|
236
|
+
except (KeyError, TypeError):
|
|
237
|
+
df.validator = None
|
|
238
|
+
|
|
239
|
+
# check type of field:
|
|
240
|
+
if _is_prim:
|
|
241
|
+
_type_category = 'primitive'
|
|
242
|
+
elif origin == type:
|
|
243
|
+
_type_category = 'type'
|
|
244
|
+
elif _is_dc:
|
|
245
|
+
_type_category = 'dataclass'
|
|
246
|
+
elif _is_typing or _is_alias: # noqa
|
|
247
|
+
if df.origin is not None and (df.origin is list and df.args):
|
|
248
|
+
df._inner_type = args[0]
|
|
249
|
+
df._inner_origin = get_origin(df._inner_type)
|
|
250
|
+
df._typing_args = get_args(df._inner_type)
|
|
251
|
+
df._inner_is_dc = is_dataclass(df._inner_type)
|
|
252
|
+
try:
|
|
253
|
+
df._encoder_fn = encoders[df._inner_type]
|
|
254
|
+
except (TypeError, KeyError):
|
|
255
|
+
df._encoder_fn = None
|
|
256
|
+
if origin is list:
|
|
257
|
+
inner_type = args[0]
|
|
258
|
+
try:
|
|
259
|
+
df._encoder_fn = encoders[inner_type]
|
|
260
|
+
except (TypeError, KeyError):
|
|
261
|
+
df._encoder_fn = None
|
|
262
|
+
_type_category = 'typing'
|
|
263
|
+
elif isclass(_type):
|
|
264
|
+
_type_category = 'class'
|
|
265
|
+
# elif _is_alias:
|
|
266
|
+
# _type_category = 'typing'
|
|
267
|
+
else:
|
|
268
|
+
# TODO: making parser for complex types
|
|
269
|
+
_type_category = 'complex'
|
|
270
|
+
_types_local[field] = _type_category
|
|
271
|
+
df._type_category = _type_category
|
|
272
|
+
|
|
273
|
+
# Store them in a dict keyed by field name:
|
|
274
|
+
_typing_args[field] = (origin, args)
|
|
275
|
+
# Assign the field object to the attrs so dataclass can pick it up
|
|
276
|
+
attrs[field] = df
|
|
277
|
+
cols[field] = df
|
|
278
|
+
return cols, _types_local, _typing_args, aliases
|
|
279
|
+
|
|
280
|
+
# Initialize the fields
|
|
281
|
+
cols, _types, _typing_args, aliases = _initialize_fields(
|
|
282
|
+
attrs, annotations, strict
|
|
283
|
+
)
|
|
284
|
+
else:
|
|
285
|
+
# if no __annotations__, cols is empty:
|
|
286
|
+
cols = OrderedDict()
|
|
287
|
+
|
|
288
|
+
_columns = cols.keys()
|
|
289
|
+
cls.__slots__ = tuple(_columns)
|
|
290
|
+
|
|
291
|
+
# Pop Meta before creating the class so we can assign it after
|
|
292
|
+
attr_meta = attrs.pop("Meta", None)
|
|
293
|
+
# Create the class
|
|
294
|
+
new_cls = super().__new__(cls, name, bases, attrs, **kwargs)
|
|
295
|
+
|
|
296
|
+
# Attach Meta class
|
|
297
|
+
new_cls.Meta = attr_meta or getattr(new_cls, "Meta", Meta)
|
|
298
|
+
new_cls.__dataclass_fields__ = cols
|
|
299
|
+
new_cls.__typing_args__ = _typing_args
|
|
300
|
+
if not new_cls.Meta:
|
|
301
|
+
new_cls.Meta = Meta
|
|
302
|
+
new_cls.Meta.set_connection = types.MethodType(
|
|
303
|
+
set_connection, new_cls.Meta
|
|
304
|
+
)
|
|
305
|
+
try:
|
|
306
|
+
frozen = new_cls.Meta.frozen
|
|
307
|
+
except AttributeError:
|
|
308
|
+
new_cls.Meta.frozen = False
|
|
309
|
+
frozen = False
|
|
310
|
+
|
|
311
|
+
# mix values from Meta to an existing Meta Class
|
|
312
|
+
new_cls.Meta.__annotations__ = Meta.__annotations__
|
|
313
|
+
for key, _ in Meta.__annotations__.items():
|
|
314
|
+
if not hasattr(new_cls.Meta, key):
|
|
315
|
+
try:
|
|
316
|
+
setattr(new_cls.Meta, key, None)
|
|
317
|
+
except AttributeError as e:
|
|
318
|
+
logging.warning(
|
|
319
|
+
f'Missing Meta Key: {key}, {e}'
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# If there's a __model_init__ method, call it
|
|
323
|
+
try:
|
|
324
|
+
new_cls.__model_init__(
|
|
325
|
+
new_cls,
|
|
326
|
+
name,
|
|
327
|
+
attrs
|
|
328
|
+
)
|
|
329
|
+
except AttributeError:
|
|
330
|
+
pass
|
|
331
|
+
|
|
332
|
+
# Now that fields are in attrs, decorate the class as a dataclass
|
|
333
|
+
dc = dataclass(
|
|
334
|
+
unsafe_hash=strict,
|
|
335
|
+
repr=False,
|
|
336
|
+
init=True,
|
|
337
|
+
order=False,
|
|
338
|
+
eq=True,
|
|
339
|
+
frozen=frozen
|
|
340
|
+
)(new_cls)
|
|
341
|
+
# Set additional attributes:
|
|
342
|
+
dc.__columns__ = cols
|
|
343
|
+
dc.__fields__ = list(_columns)
|
|
344
|
+
dc.__values__ = {}
|
|
345
|
+
dc.__encoder__ = JSONContent
|
|
346
|
+
dc.__valid__ = False
|
|
347
|
+
dc.__errors__ = None
|
|
348
|
+
dc.__frozen__ = strict
|
|
349
|
+
dc.__initialised__ = False
|
|
350
|
+
dc.__field_types__ = _types
|
|
351
|
+
dc.__aliases__ = aliases
|
|
352
|
+
dc.__typing_args__ = _typing_args
|
|
353
|
+
dc.modelName = dc.__name__
|
|
354
|
+
|
|
355
|
+
# Override __setattr__ method
|
|
356
|
+
setattr(dc, "__setattr__", _dc_method_setattr_)
|
|
357
|
+
return dc
|
|
358
|
+
|
|
359
|
+
def __init__(cls, *args, **kwargs) -> None:
|
|
360
|
+
# Initialized Data Model = True
|
|
361
|
+
cls.__initialised__ = True
|
|
362
|
+
cls.__errors__ = None
|
|
363
|
+
super().__init__(*args, **kwargs)
|
|
364
|
+
|
|
365
|
+
def __call__(cls, *args, **kwargs):
|
|
366
|
+
# rename any kwargs that match an alias ONLY if there are aliases defined.
|
|
367
|
+
alias_func = getattr(cls.Meta, "alias_function", None)
|
|
368
|
+
if callable(alias_func):
|
|
369
|
+
new_kwargs = {}
|
|
370
|
+
for k, v in kwargs.items():
|
|
371
|
+
new_k = alias_func(k)
|
|
372
|
+
new_kwargs[new_k] = v
|
|
373
|
+
kwargs = new_kwargs
|
|
374
|
+
if cls.__aliases__:
|
|
375
|
+
new_kwargs = {}
|
|
376
|
+
for k, v in kwargs.items():
|
|
377
|
+
if k in cls.__aliases__:
|
|
378
|
+
real_field = cls.__aliases__[k]
|
|
379
|
+
new_kwargs[real_field] = v
|
|
380
|
+
else:
|
|
381
|
+
new_kwargs[k] = v
|
|
382
|
+
kwargs = new_kwargs
|
|
383
|
+
return super().__call__(*args, **kwargs)
|
|
File without changes
|