python-datamodel 0.10.10__tar.gz → 0.10.11__tar.gz
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.
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/PKG-INFO +1 -1
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/abstract.py +37 -2
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/models.py +17 -8
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/version.py +1 -1
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/PKG-INFO +1 -1
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/CHANGELOG.md +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/CONTRIBUTING.md +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/LICENSE +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/MANIFEST.in +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/Makefile +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/README.md +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/SECURITY.md +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/adaptive/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/adaptive/models.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/aliases/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/base.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/converters.c +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/converters.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/converters.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/exceptions.c +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/exceptions.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/exceptions.pxd +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/exceptions.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/fields.cpp +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/fields.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/fields.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/functions.cpp +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/functions.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/functions.pxd +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/functions.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/jsonld/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/jsonld/models.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/libs/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/libs/mapping.c +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/libs/mapping.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/libs/mapping.pxd +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/libs/mapping.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/libs/mutables.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/parsers/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/parsers/encoders.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/parsers/json.cpp +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/parsers/json.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/parsers/json.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/profiler.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/py.typed +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/rs_core/Cargo.toml +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/rs_core/src/lib.rs +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/rs_parsers/Cargo.toml +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/rs_parsers/src/lib.rs +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/rs_validators/Cargo.toml +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/rs_validators/src/lib.rs +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/singleton.c +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/singleton.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/singleton.pxd +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/singleton.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/types.c +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/types.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/types.pxd +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/typedefs/types.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/types.c +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/types.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/types.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/validation.cpp +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/validation.html +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/datamodel/validation.pyx +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/pyproject.toml +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/SOURCES.txt +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/dependency_links.txt +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/not-zip-safe +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/requires.txt +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/top_level.txt +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/setup.cfg +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/setup.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/__init__.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_aliases.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_classdict.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_converter.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_dashboards.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_data.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_descriptors.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_dict.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_field.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_inherit.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_json.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_method.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_model.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_notify.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_primitives.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_qsdriver.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_qsmodel.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_qsobject.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_ticket.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_tickets.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_tuples.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_type_user.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_types.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_unions.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_valid_callables.py +0 -0
- {python_datamodel-0.10.10 → python_datamodel-0.10.11}/tests/test_validations.py +0 -0
|
@@ -153,6 +153,7 @@ class ModelMeta(type):
|
|
|
153
153
|
__fields__: List
|
|
154
154
|
__field_types__: List
|
|
155
155
|
__aliases__: Dict
|
|
156
|
+
__primary_keys__: List
|
|
156
157
|
# Class-level cache
|
|
157
158
|
_base_class_cache = {}
|
|
158
159
|
|
|
@@ -162,6 +163,8 @@ class ModelMeta(type):
|
|
|
162
163
|
_types_local = {}
|
|
163
164
|
_typing_args = {}
|
|
164
165
|
aliases = {}
|
|
166
|
+
primary_keys = [] # New list to collect primary key fields
|
|
167
|
+
|
|
165
168
|
for field, _type in annotations.items():
|
|
166
169
|
if isinstance(_type, InitVar) or _type == InitVar:
|
|
167
170
|
# Skip InitVar fields;
|
|
@@ -202,6 +205,10 @@ class ModelMeta(type):
|
|
|
202
205
|
df.name = field
|
|
203
206
|
df.type = _type
|
|
204
207
|
|
|
208
|
+
# Check for primary_key in field metadata
|
|
209
|
+
if df.metadata.get("primary_key", False):
|
|
210
|
+
primary_keys.append(field)
|
|
211
|
+
|
|
205
212
|
# Cache reflection info so we DON’T need to call
|
|
206
213
|
# get_origin/get_args repeatedly:
|
|
207
214
|
args = get_args(_type)
|
|
@@ -281,7 +288,7 @@ class ModelMeta(type):
|
|
|
281
288
|
# Assign the field object to the attrs so dataclass can pick it up
|
|
282
289
|
attrs[field] = df
|
|
283
290
|
cols[field] = df
|
|
284
|
-
return cols, _types_local, _typing_args, aliases
|
|
291
|
+
return cols, _types_local, _typing_args, aliases, primary_keys
|
|
285
292
|
|
|
286
293
|
def __new__(cls, name, bases, attrs, **kwargs): # noqa
|
|
287
294
|
annotations = attrs.get('__annotations__', {})
|
|
@@ -295,12 +302,14 @@ class ModelMeta(type):
|
|
|
295
302
|
_types = cached['types'].copy()
|
|
296
303
|
_typing_args = cached['_typing_args'].copy()
|
|
297
304
|
aliases = cached['aliases'].copy()
|
|
305
|
+
primary_keys = cached['primary_keys'].copy()
|
|
298
306
|
else:
|
|
299
307
|
# Compute field from Bases:
|
|
300
308
|
cols = OrderedDict()
|
|
301
309
|
_types = {}
|
|
302
310
|
_typing_args = {}
|
|
303
311
|
aliases = {}
|
|
312
|
+
primary_keys = []
|
|
304
313
|
|
|
305
314
|
# Step 1: Collect fields from parent classes
|
|
306
315
|
for base in bases:
|
|
@@ -311,9 +320,11 @@ class ModelMeta(type):
|
|
|
311
320
|
_typing_args |= base.__typing_args__
|
|
312
321
|
if hasattr(base, '__aliases__'):
|
|
313
322
|
aliases |= base.__aliases__
|
|
323
|
+
if hasattr(base, '__primary_keys__'):
|
|
324
|
+
primary_keys += base.__primary_keys__
|
|
314
325
|
|
|
315
326
|
# Now initialize subclass-specific fields
|
|
316
|
-
new_cols, new_types, new_typing_args, new_aliases = cls._initialize_fields(
|
|
327
|
+
new_cols, new_types, new_typing_args, new_aliases, nw_primary_keys = cls._initialize_fields( # noqa
|
|
317
328
|
attrs, annotations, strict
|
|
318
329
|
)
|
|
319
330
|
|
|
@@ -322,6 +333,7 @@ class ModelMeta(type):
|
|
|
322
333
|
_types.update(new_types)
|
|
323
334
|
_typing_args.update(new_typing_args)
|
|
324
335
|
aliases.update(new_aliases)
|
|
336
|
+
primary_keys.extend(nw_primary_keys)
|
|
325
337
|
|
|
326
338
|
# Store computed results in cache
|
|
327
339
|
cls._base_class_cache[base_key] = {
|
|
@@ -329,6 +341,7 @@ class ModelMeta(type):
|
|
|
329
341
|
'types': _types.copy(),
|
|
330
342
|
'_typing_args': _typing_args.copy(),
|
|
331
343
|
'aliases': aliases.copy(),
|
|
344
|
+
'primary_keys': primary_keys.copy(),
|
|
332
345
|
}
|
|
333
346
|
|
|
334
347
|
_columns = cols.keys()
|
|
@@ -393,11 +406,33 @@ class ModelMeta(type):
|
|
|
393
406
|
dc.__initialised__ = False
|
|
394
407
|
dc.__field_types__ = _types
|
|
395
408
|
dc.__aliases__ = aliases
|
|
409
|
+
# Set the primary_keys on the dataclass
|
|
410
|
+
dc.__primary_keys__ = primary_keys
|
|
396
411
|
dc.__typing_args__ = _typing_args
|
|
397
412
|
dc.modelName = dc.__name__
|
|
398
413
|
|
|
399
414
|
# Override __setattr__ method
|
|
400
415
|
setattr(dc, "__setattr__", _dc_method_setattr_)
|
|
416
|
+
|
|
417
|
+
# Method to get primary keys without further introspection
|
|
418
|
+
def get_primary_keys(cls):
|
|
419
|
+
return cls.__primary_keys__
|
|
420
|
+
|
|
421
|
+
# Add the method to the class
|
|
422
|
+
dc.get_primary_keys = classmethod(get_primary_keys)
|
|
423
|
+
|
|
424
|
+
def get_primary_key_fields(cls):
|
|
425
|
+
"""Return a dictionary of primary key fields with their types."""
|
|
426
|
+
return {name: cls.__columns__[name] for name in cls.__primary_keys__}
|
|
427
|
+
|
|
428
|
+
dc.get_primary_key_fields = classmethod(get_primary_key_fields)
|
|
429
|
+
|
|
430
|
+
def get_primary_key_values(self):
|
|
431
|
+
"""Get primary key values for this instance as a dictionary."""
|
|
432
|
+
return {key: getattr(self, key) for key in self.__primary_keys__}
|
|
433
|
+
|
|
434
|
+
dc.get_primary_key_values = get_primary_key_values
|
|
435
|
+
|
|
401
436
|
return dc
|
|
402
437
|
|
|
403
438
|
def __init__(cls, *args, **kwargs) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import contextlib
|
|
3
|
-
from typing import Any, Dict
|
|
3
|
+
from typing import Any, Dict, get_args
|
|
4
4
|
from enum import Enum, EnumMeta
|
|
5
5
|
# Dataclass
|
|
6
6
|
import inspect
|
|
@@ -250,13 +250,22 @@ class ModelMixin:
|
|
|
250
250
|
)
|
|
251
251
|
# if it's a list, might contain submodels or scalars
|
|
252
252
|
elif isinstance(value, list):
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
253
|
+
targs = field.args
|
|
254
|
+
if len(targs) == 2 and targs[1] is type(None):
|
|
255
|
+
# Checking if it's Optional[T]
|
|
256
|
+
submodel_class = get_args(targs[0])
|
|
257
|
+
elif field.origin is list and field.args:
|
|
258
|
+
submodel_class = field.args[0]
|
|
259
|
+
else:
|
|
260
|
+
submodel_class = None
|
|
261
|
+
if field.origin is list and submodel_class and (
|
|
262
|
+
issubclass(
|
|
263
|
+
submodel_class,
|
|
264
|
+
ModelMixin
|
|
265
|
+
) and not hasattr(submodel_class, name)
|
|
266
|
+
):
|
|
267
|
+
out[name] = json_encoder(value)
|
|
268
|
+
continue
|
|
260
269
|
items_out = []
|
|
261
270
|
for item in value:
|
|
262
271
|
if isinstance(item, ModelMixin):
|
|
@@ -6,7 +6,7 @@ __description__ = (
|
|
|
6
6
|
'simple library based on python +3.8 to use Dataclass-syntax'
|
|
7
7
|
'for interacting with Data'
|
|
8
8
|
)
|
|
9
|
-
__version__ = '0.10.
|
|
9
|
+
__version__ = '0.10.11'
|
|
10
10
|
__copyright__ = 'Copyright (c) 2020-2024 Jesus Lara'
|
|
11
11
|
__author__ = 'Jesus Lara'
|
|
12
12
|
__author_email__ = 'jesuslarag@gmail.com'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/requires.txt
RENAMED
|
File without changes
|
{python_datamodel-0.10.10 → python_datamodel-0.10.11}/python_datamodel.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|