sera-2 1.14.3__py3-none-any.whl → 1.14.5__py3-none-any.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.
- sera/make/__main__.py +1 -1
- sera/make/make_python_model.py +23 -28
- sera/make/make_typescript_model.py +18 -11
- sera/models/_class.py +9 -1
- sera/models/_datatype.py +5 -2
- sera/models/_parse.py +5 -1
- sera/models/_property.py +7 -1
- {sera_2-1.14.3.dist-info → sera_2-1.14.5.dist-info}/METADATA +1 -1
- {sera_2-1.14.3.dist-info → sera_2-1.14.5.dist-info}/RECORD +10 -10
- {sera_2-1.14.3.dist-info → sera_2-1.14.5.dist-info}/WHEEL +0 -0
sera/make/__main__.py
CHANGED
sera/make/make_python_model.py
CHANGED
@@ -370,25 +370,24 @@ def make_python_data_model(
|
|
370
370
|
continue
|
371
371
|
|
372
372
|
if isinstance(prop, DataProperty):
|
373
|
-
pytype = prop.get_data_model_datatype().get_python_type()
|
374
|
-
if prop.is_optional:
|
375
|
-
pytype = pytype.as_optional_type()
|
376
|
-
|
377
|
-
for dep in pytype.deps:
|
378
|
-
program.import_(dep, True)
|
379
|
-
|
380
|
-
pytype_type = pytype.type
|
373
|
+
pytype = prop.get_data_model_datatype().get_python_type().clone()
|
381
374
|
if len(prop.data.constraints) > 0:
|
382
375
|
# if the property has constraints, we need to figure out
|
383
376
|
program.import_("typing.Annotated", True)
|
384
377
|
if len(prop.data.constraints) == 1:
|
385
|
-
|
386
|
-
|
378
|
+
pytype.type = "Annotated[%s, %s]" % (
|
379
|
+
pytype.type,
|
387
380
|
prop.data.constraints[0].get_msgspec_constraint(),
|
388
381
|
)
|
389
382
|
else:
|
390
383
|
raise NotImplementedError(prop.data.constraints)
|
391
384
|
|
385
|
+
if prop.is_optional:
|
386
|
+
pytype = pytype.as_optional_type()
|
387
|
+
|
388
|
+
for dep in pytype.deps:
|
389
|
+
program.import_(dep, True)
|
390
|
+
|
392
391
|
# private property are available for creating, but not for updating.
|
393
392
|
# so we do not need to skip it.
|
394
393
|
# if prop.data.is_private:
|
@@ -416,7 +415,7 @@ def make_python_data_model(
|
|
416
415
|
|
417
416
|
cls_ast(
|
418
417
|
stmt.DefClassVarStatement(
|
419
|
-
prop.name,
|
418
|
+
prop.name, pytype.type, prop_default_value
|
420
419
|
)
|
421
420
|
)
|
422
421
|
elif isinstance(prop, ObjectProperty):
|
@@ -440,12 +439,10 @@ def make_python_data_model(
|
|
440
439
|
elif prop.is_optional:
|
441
440
|
pytype = pytype.as_optional_type()
|
442
441
|
|
443
|
-
pytype_type = pytype.type
|
444
|
-
|
445
442
|
for dep in pytype.deps:
|
446
443
|
program.import_(dep, True)
|
447
444
|
|
448
|
-
cls_ast(stmt.DefClassVarStatement(prop.name,
|
445
|
+
cls_ast(stmt.DefClassVarStatement(prop.name, pytype.type))
|
449
446
|
|
450
447
|
if is_on_create_value_updated:
|
451
448
|
program.import_("typing.Optional", True)
|
@@ -558,30 +555,30 @@ def make_python_data_model(
|
|
558
555
|
continue
|
559
556
|
|
560
557
|
if isinstance(prop, DataProperty):
|
561
|
-
pytype = prop.get_data_model_datatype().get_python_type()
|
562
|
-
if prop.is_optional:
|
563
|
-
pytype = pytype.as_optional_type()
|
558
|
+
pytype = prop.get_data_model_datatype().get_python_type().clone()
|
564
559
|
|
565
|
-
for dep in pytype.deps:
|
566
|
-
program.import_(dep, True)
|
567
|
-
|
568
|
-
pytype_type = pytype.type
|
569
560
|
if len(prop.data.constraints) > 0:
|
570
561
|
# if the property has constraints, we need to figure out
|
571
562
|
program.import_("typing.Annotated", True)
|
572
563
|
if len(prop.data.constraints) == 1:
|
573
|
-
|
574
|
-
|
564
|
+
pytype.type = "Annotated[%s, %s]" % (
|
565
|
+
pytype.type,
|
575
566
|
prop.data.constraints[0].get_msgspec_constraint(),
|
576
567
|
)
|
577
568
|
else:
|
578
569
|
raise NotImplementedError(prop.data.constraints)
|
579
570
|
|
571
|
+
if prop.is_optional:
|
572
|
+
pytype = pytype.as_optional_type()
|
573
|
+
|
574
|
+
for dep in pytype.deps:
|
575
|
+
program.import_(dep, True)
|
576
|
+
|
580
577
|
if prop.data.is_private:
|
581
578
|
program.import_("typing.Union", True)
|
582
579
|
program.import_("sera.typing.UnsetType", True)
|
583
580
|
program.import_("sera.typing.UNSET", True)
|
584
|
-
|
581
|
+
pytype.type = f"Union[{pytype.type}, UnsetType]"
|
585
582
|
|
586
583
|
prop_default_value = None
|
587
584
|
if prop.data.is_private:
|
@@ -602,7 +599,7 @@ def make_python_data_model(
|
|
602
599
|
|
603
600
|
cls_ast(
|
604
601
|
stmt.DefClassVarStatement(
|
605
|
-
prop.name,
|
602
|
+
prop.name, pytype.type, prop_default_value
|
606
603
|
)
|
607
604
|
)
|
608
605
|
elif isinstance(prop, ObjectProperty):
|
@@ -626,12 +623,10 @@ def make_python_data_model(
|
|
626
623
|
elif prop.is_optional:
|
627
624
|
pytype = pytype.as_optional_type()
|
628
625
|
|
629
|
-
pytype_type = pytype.type
|
630
|
-
|
631
626
|
for dep in pytype.deps:
|
632
627
|
program.import_(dep, True)
|
633
628
|
|
634
|
-
cls_ast(stmt.DefClassVarStatement(prop.name,
|
629
|
+
cls_ast(stmt.DefClassVarStatement(prop.name, pytype.type))
|
635
630
|
|
636
631
|
if is_on_update_value_updated:
|
637
632
|
program.import_("typing.Optional", True)
|
@@ -23,6 +23,7 @@ from sera.models import (
|
|
23
23
|
Schema,
|
24
24
|
TsTypeWithDep,
|
25
25
|
)
|
26
|
+
from sera.typing import is_set
|
26
27
|
|
27
28
|
|
28
29
|
def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
@@ -336,8 +337,8 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
336
337
|
f"{cls.name}Id",
|
337
338
|
deps=[f"@.models.{pkg.dir.name}.{cls.name}.{cls.name}Id"],
|
338
339
|
)
|
339
|
-
|
340
|
-
# for none id properties, we need to include a type for "invalid" value
|
340
|
+
elif tstype.type not in schema.enums:
|
341
|
+
# for none id & none enum properties, we need to include a type for "invalid" value
|
341
342
|
tstype = _inject_type_for_invalid_value(tstype)
|
342
343
|
|
343
344
|
if prop.is_optional:
|
@@ -355,9 +356,15 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
355
356
|
and prop.db.is_auto_increment
|
356
357
|
):
|
357
358
|
create_propvalue = expr.ExprConstant(-1)
|
359
|
+
elif is_set(prop.data.default_value):
|
360
|
+
create_propvalue = expr.ExprConstant(prop.data.default_value)
|
358
361
|
else:
|
359
362
|
if tstype.type in idprop_aliases:
|
360
363
|
create_propvalue = idprop_aliases[tstype.type].get_default()
|
364
|
+
elif tstype.type in schema.enums:
|
365
|
+
create_propvalue = expr.ExprConstant(
|
366
|
+
next(iter(schema.enums[tstype.type].values.values())).value
|
367
|
+
)
|
361
368
|
else:
|
362
369
|
create_propvalue = tstype.get_default()
|
363
370
|
|
@@ -537,7 +544,6 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
537
544
|
],
|
538
545
|
)
|
539
546
|
if prop.cardinality.is_star_to_many():
|
540
|
-
tstype = tstype.as_list_type()
|
541
547
|
create_propvalue = expr.ExprConstant([])
|
542
548
|
update_propvalue = PredefinedFn.map_list(
|
543
549
|
PredefinedFn.attr_getter(
|
@@ -578,6 +584,7 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
578
584
|
),
|
579
585
|
)
|
580
586
|
)
|
587
|
+
|
581
588
|
if not prop.data.is_private:
|
582
589
|
# private property does not include in the public record
|
583
590
|
to_record_args.append(
|
@@ -612,11 +619,9 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
612
619
|
),
|
613
620
|
)
|
614
621
|
)
|
622
|
+
|
623
|
+
tstype = tstype.as_list_type()
|
615
624
|
else:
|
616
|
-
if prop.is_optional:
|
617
|
-
# convert type to optional - for list type, we don't need to do this
|
618
|
-
# as we will use empty list as no value
|
619
|
-
tstype = tstype.as_optional_type()
|
620
625
|
create_propvalue = expr.ExprMethodCall(
|
621
626
|
expr.ExprIdent(tstype.type),
|
622
627
|
"create",
|
@@ -729,6 +734,11 @@ def make_typescript_data_model(schema: Schema, target_pkg: Package):
|
|
729
734
|
)
|
730
735
|
)
|
731
736
|
|
737
|
+
if prop.is_optional:
|
738
|
+
# convert type to optional - for list type, we don't need to do this
|
739
|
+
# as we will use empty list as no value
|
740
|
+
tstype = tstype.as_optional_type()
|
741
|
+
|
732
742
|
for dep in tstype.deps:
|
733
743
|
program.import_(
|
734
744
|
dep,
|
@@ -1407,16 +1417,13 @@ def make_typescript_enum(schema: Schema, target_pkg: Package):
|
|
1407
1417
|
stmt.LineBreak(),
|
1408
1418
|
lambda ast: ast.class_like("enum", enum.name)(
|
1409
1419
|
*[
|
1410
|
-
stmt.
|
1420
|
+
stmt.DefEnumValueStatement(
|
1411
1421
|
name=value.name,
|
1412
|
-
type=None,
|
1413
1422
|
value=expr.ExprConstant(value.value),
|
1414
1423
|
)
|
1415
1424
|
for value in enum.values.values()
|
1416
1425
|
]
|
1417
1426
|
),
|
1418
|
-
stmt.LineBreak(),
|
1419
|
-
stmt.TypescriptStatement("export " + enum.name + ";"),
|
1420
1427
|
)
|
1421
1428
|
pkg.module(enum.get_tsmodule_name()).write(program)
|
1422
1429
|
|
sera/models/_class.py
CHANGED
@@ -51,6 +51,7 @@ class Class:
|
|
51
51
|
Get the ID property of this class.
|
52
52
|
The ID property is the one tagged with is_primary_key
|
53
53
|
"""
|
54
|
+
id_props = []
|
54
55
|
for prop in self.properties.values():
|
55
56
|
if (
|
56
57
|
isinstance(prop, DataProperty)
|
@@ -60,7 +61,14 @@ class Class:
|
|
60
61
|
assert (
|
61
62
|
self.db is not None
|
62
63
|
), "This class is not stored in the database and thus, cannot have a primary key"
|
63
|
-
|
64
|
+
id_props.append(prop)
|
65
|
+
if len(id_props) > 1:
|
66
|
+
raise ValueError(
|
67
|
+
f"Class {self.name} has more than one primary key property: {', '.join(p.name for p in id_props)}"
|
68
|
+
)
|
69
|
+
if len(id_props) == 1:
|
70
|
+
return id_props[0]
|
71
|
+
# if there is no primary key, we return None
|
64
72
|
assert (
|
65
73
|
self.db is None
|
66
74
|
), f"The class {self.name} is stored in the database and thus, must have a primary key"
|
sera/models/_datatype.py
CHANGED
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import datetime
|
4
4
|
from dataclasses import dataclass, field
|
5
|
-
from enum import Enum
|
6
5
|
from typing import Literal
|
7
6
|
|
8
7
|
from codegen.models import expr
|
@@ -64,6 +63,10 @@ class PyTypeWithDep:
|
|
64
63
|
)
|
65
64
|
return PyTypeWithDep(type=f"Optional[{self.type}]", deps=deps)
|
66
65
|
|
66
|
+
def clone(self) -> PyTypeWithDep:
|
67
|
+
"""Clone the type with the same dependencies."""
|
68
|
+
return PyTypeWithDep(type=self.type, deps=list(self.deps))
|
69
|
+
|
67
70
|
|
68
71
|
@dataclass
|
69
72
|
class TsTypeWithDep:
|
@@ -79,7 +82,7 @@ class TsTypeWithDep:
|
|
79
82
|
return expr.ExprConstant(0)
|
80
83
|
if self.type == "boolean":
|
81
84
|
return expr.ExprConstant(False)
|
82
|
-
if self.type
|
85
|
+
if self.type.endswith("| undefined"):
|
83
86
|
return expr.ExprConstant("undefined")
|
84
87
|
if self.type.endswith("| string)") or self.type.endswith("| string"):
|
85
88
|
return expr.ExprConstant("")
|
sera/models/_parse.py
CHANGED
@@ -36,6 +36,7 @@ from sera.models._property import (
|
|
36
36
|
SystemControlledAttrs,
|
37
37
|
)
|
38
38
|
from sera.models._schema import Schema
|
39
|
+
from sera.typing import UNSET
|
39
40
|
|
40
41
|
|
41
42
|
def parse_schema(name: str, files: Sequence[Path | str]) -> Schema:
|
@@ -140,6 +141,7 @@ def _parse_property(
|
|
140
141
|
system_controlled=_parse_system_controlled_attrs(
|
141
142
|
_data.get("system_controlled")
|
142
143
|
),
|
144
|
+
default_value=UNSET if "default_value" not in _data else _data["default_value"],
|
143
145
|
)
|
144
146
|
|
145
147
|
assert isinstance(prop, dict), prop
|
@@ -237,7 +239,9 @@ def _parse_datatype(schema: Schema, datatype: dict | str) -> DataType:
|
|
237
239
|
sqltype=SQLTypeWithDep(
|
238
240
|
type="String", mapped_pytype="str", deps=["sqlalchemy.String"]
|
239
241
|
),
|
240
|
-
tstype=TsTypeWithDep(
|
242
|
+
tstype=TsTypeWithDep(
|
243
|
+
type=enum.name, deps=[f"@.models.enums.{enum.name}"]
|
244
|
+
),
|
241
245
|
is_list=is_list,
|
242
246
|
)
|
243
247
|
|
sera/models/_property.py
CHANGED
@@ -2,12 +2,15 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from dataclasses import dataclass, field
|
4
4
|
from enum import Enum
|
5
|
-
from typing import TYPE_CHECKING, Literal, Optional
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional
|
6
|
+
|
7
|
+
from msgspec import UNSET
|
6
8
|
|
7
9
|
from sera.models._constraints import Constraint
|
8
10
|
from sera.models._datatype import DataType
|
9
11
|
from sera.models._default import DefaultFactory
|
10
12
|
from sera.models._multi_lingual_string import MultiLingualString
|
13
|
+
from sera.typing import UnsetType
|
11
14
|
|
12
15
|
if TYPE_CHECKING:
|
13
16
|
from sera.models._class import Class
|
@@ -111,6 +114,9 @@ class PropDataAttrs:
|
|
111
114
|
# if this property is controlled by the system, the attributes for the system-controlled property
|
112
115
|
system_controlled: Optional[SystemControlledAttrs] = None
|
113
116
|
|
117
|
+
# default value of this property if it is not provided (then optional is false by default)
|
118
|
+
default_value: Any | UnsetType = UNSET
|
119
|
+
|
114
120
|
|
115
121
|
@dataclass(kw_only=True)
|
116
122
|
class Property:
|
@@ -14,28 +14,28 @@ sera/libs/middlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
14
14
|
sera/libs/middlewares/auth.py,sha256=r6aix1ZBwxMd1Jv5hMCTB8a_gFOJQ6egvxIrf3DWEOs,2323
|
15
15
|
sera/libs/middlewares/uscp.py,sha256=H5umW8iEQSCdb_MJ5Im49kxg1E7TpxSg1p2_2A5zI1U,2600
|
16
16
|
sera/make/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
sera/make/__main__.py,sha256=
|
17
|
+
sera/make/__main__.py,sha256=HRfOR53p351h6KblVvYm3DLhDIfEtk6R0kjl78_S_S8,1453
|
18
18
|
sera/make/make_app.py,sha256=n9NtW73O3s_5Q31VHIRmnd-jEIcpDO7ksAsOdovde2s,5999
|
19
19
|
sera/make/make_python_api.py,sha256=iXGbKQ3IJvsY1ur_fhurr_THFNnH66E3Wl85o0emUbw,26853
|
20
|
-
sera/make/make_python_model.py,sha256=
|
20
|
+
sera/make/make_python_model.py,sha256=cRb-fuHX0WH7XPAAliu6lycC0iEjE5kcKg4bBU40GwQ,61275
|
21
21
|
sera/make/make_python_services.py,sha256=0ZpWLwQ7Nwfn8BXAikAB4JRpNknpSJyJgY5b1cjtxV4,2073
|
22
|
-
sera/make/make_typescript_model.py,sha256=
|
22
|
+
sera/make/make_typescript_model.py,sha256=4yLCLIzP2jeXfmOeee6nNS_qd7_7iPinV2vQh1IfbLs,64000
|
23
23
|
sera/misc/__init__.py,sha256=Dh4uDq0D4N53h3zhvmwfa5a0TPVRSUvLzb0hkFuPirk,411
|
24
24
|
sera/misc/_formatter.py,sha256=aCGYL08l8f3aLODHxSocxBBwkRYEo3K1QzCDEn3suj0,1685
|
25
25
|
sera/misc/_utils.py,sha256=V5g4oLGHOhUCR75Kkcn1w01pAvGvaepK-T8Z3pIgHjI,1450
|
26
26
|
sera/models/__init__.py,sha256=vJC5Kzo_N7wd16ocNPy1VvAZDGNiWeiAhWJ4ihATKvA,780
|
27
|
-
sera/models/_class.py,sha256=
|
27
|
+
sera/models/_class.py,sha256=1J4Bd_LanzhhDWwZFHWGtFYD7lupe_alaB3D02ebNDI,2862
|
28
28
|
sera/models/_collection.py,sha256=ZnQEriKC4X88Zz48Kn1AVZKH-1_l8OgWa-zf2kcQOOE,1414
|
29
29
|
sera/models/_constraints.py,sha256=RpWDU-TfCslXaMUaTG9utWbl5z8Z6nzvF_fhqlek6ew,1987
|
30
|
-
sera/models/_datatype.py,sha256=
|
30
|
+
sera/models/_datatype.py,sha256=cC6Wm0IvobDF5Tq9Jy_ncbjPWBRl3ECGBy0wJyDDMzU,7281
|
31
31
|
sera/models/_default.py,sha256=ABggW6qdPR4ZDqIPJdJ0GCGQ-7kfsfZmQ_DchgZEa-I,137
|
32
32
|
sera/models/_enum.py,sha256=sy0q7E646F-APsqrVQ52r1fAQ_DCAeaNq5YM5QN3zIk,2070
|
33
33
|
sera/models/_module.py,sha256=I-GfnTgAa-5R87qTAvEzOt-VVEGeFBBwubGCgUkXVSw,5159
|
34
34
|
sera/models/_multi_lingual_string.py,sha256=JETN6k00VH4wrA4w5vAHMEJV8fp3SY9bJebskFTjQLA,1186
|
35
|
-
sera/models/_parse.py,sha256=
|
36
|
-
sera/models/_property.py,sha256=
|
35
|
+
sera/models/_parse.py,sha256=MaGZty29lsVUFumWqNanIjAwptBNOMbVZMXLZ2A9_2g,12317
|
36
|
+
sera/models/_property.py,sha256=2rSLs9JjSesrxrEugE7krYaBQOivKU882I8mZN94FlI,7017
|
37
37
|
sera/models/_schema.py,sha256=VxJEiqgVvbXgcSUK4UW6JnRcggk4nsooVSE6MyXmfNY,1636
|
38
38
|
sera/typing.py,sha256=Fl4-UzLJu1GdLLk_g87fA7nT9wQGelNnGzag6dg_0gs,980
|
39
|
-
sera_2-1.14.
|
40
|
-
sera_2-1.14.
|
41
|
-
sera_2-1.14.
|
39
|
+
sera_2-1.14.5.dist-info/METADATA,sha256=vwWtB6bjalDopfemBjaZj3CI2D4S9seb-diDw98smxY,852
|
40
|
+
sera_2-1.14.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
41
|
+
sera_2-1.14.5.dist-info/RECORD,,
|
File without changes
|