sera-2 1.6.1__py3-none-any.whl → 1.6.2__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/libs/base_orm.py +9 -1
- sera/libs/base_service.py +1 -1
- sera/make/make_app.py +2 -2
- sera/make/make_python_model.py +30 -5
- sera/misc/_formatter.py +4 -2
- sera/models/_module.py +5 -1
- sera/typing.py +13 -1
- {sera_2-1.6.1.dist-info → sera_2-1.6.2.dist-info}/METADATA +1 -1
- {sera_2-1.6.1.dist-info → sera_2-1.6.2.dist-info}/RECORD +10 -10
- {sera_2-1.6.1.dist-info → sera_2-1.6.2.dist-info}/WHEEL +0 -0
sera/libs/base_orm.py
CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
3
3
|
from typing import Optional
|
4
4
|
|
5
5
|
import orjson
|
6
|
+
from sera.typing import UNSET
|
6
7
|
from sqlalchemy import LargeBinary, TypeDecorator
|
7
8
|
from sqlalchemy import create_engine as sqlalchemy_create_engine
|
8
9
|
from sqlalchemy import update
|
@@ -15,6 +16,8 @@ class BaseORM:
|
|
15
16
|
args = {}
|
16
17
|
for col in self.__table__.columns: # type: ignore
|
17
18
|
val = getattr(self, col.name)
|
19
|
+
if val is UNSET:
|
20
|
+
continue
|
18
21
|
if col.primary_key:
|
19
22
|
q = q.where(getattr(self.__class__, col.name) == val)
|
20
23
|
args[col.name] = val
|
@@ -22,7 +25,12 @@ class BaseORM:
|
|
22
25
|
return q.values(**args)
|
23
26
|
|
24
27
|
def get_update_args(self):
|
25
|
-
|
28
|
+
table = self.__table__ # type: ignore
|
29
|
+
return {
|
30
|
+
col.name: val
|
31
|
+
for col in table.columns
|
32
|
+
if (val := getattr(self, col.name)) is not UNSET
|
33
|
+
}
|
26
34
|
|
27
35
|
@classmethod
|
28
36
|
def from_dict(cls, data: dict):
|
sera/libs/base_service.py
CHANGED
sera/make/make_app.py
CHANGED
@@ -7,7 +7,6 @@ from typing import Annotated
|
|
7
7
|
|
8
8
|
from codegen.models import DeferredVar, PredefinedFn, Program, expr, stmt
|
9
9
|
from loguru import logger
|
10
|
-
|
11
10
|
from sera.make.make_python_api import make_python_api
|
12
11
|
from sera.make.make_python_model import (
|
13
12
|
make_python_data_model,
|
@@ -83,6 +82,7 @@ def make_config(app: App):
|
|
83
82
|
expr.ExprFuncCall(
|
84
83
|
expr.ExprIdent("parse_schema"),
|
85
84
|
[
|
85
|
+
expr.ExprConstant(app.name),
|
86
86
|
PredefinedFn.list(
|
87
87
|
[
|
88
88
|
expr.ExprDivision(
|
@@ -93,7 +93,7 @@ def make_config(app: App):
|
|
93
93
|
)
|
94
94
|
for path in app.schema_files
|
95
95
|
]
|
96
|
-
)
|
96
|
+
),
|
97
97
|
],
|
98
98
|
),
|
99
99
|
),
|
sera/make/make_python_model.py
CHANGED
@@ -159,11 +159,24 @@ def make_python_data_model(
|
|
159
159
|
else:
|
160
160
|
value = expr.ExprMethodCall(value, "to_db", [])
|
161
161
|
elif isinstance(prop, DataProperty) and prop.is_diff_data_model_datatype():
|
162
|
-
# convert the value to the python type used in db
|
163
|
-
|
162
|
+
# convert the value to the python type used in db
|
163
|
+
converted_value = get_data_conversion(
|
164
164
|
prop.get_data_model_datatype().get_python_type().type,
|
165
165
|
prop.datatype.get_python_type().type,
|
166
166
|
)(value)
|
167
|
+
|
168
|
+
if prop.data.is_private:
|
169
|
+
# if the property is private and it's UNSET, we cannot transform it to the database type
|
170
|
+
# and has to use the UNSET value (the update query will ignore this field)
|
171
|
+
program.import_("sera.typing.UNSET", True)
|
172
|
+
program.import_("sera.typing.is_set", True)
|
173
|
+
value = expr.ExprTernary(
|
174
|
+
expr.ExprFuncCall(expr.ExprIdent("is_set"), [value]),
|
175
|
+
converted_value,
|
176
|
+
expr.ExprIdent("UNSET"),
|
177
|
+
)
|
178
|
+
else:
|
179
|
+
value = converted_value
|
167
180
|
return value
|
168
181
|
|
169
182
|
def make_upsert(program: Program, cls: Class):
|
@@ -177,11 +190,13 @@ def make_python_data_model(
|
|
177
190
|
alias=f"{cls.name}DB",
|
178
191
|
)
|
179
192
|
cls_ast = program.root.class_(
|
180
|
-
"Upsert" + cls.name,
|
193
|
+
"Upsert" + cls.name,
|
194
|
+
[expr.ExprIdent("msgspec.Struct"), expr.ExprIdent("kw_only=True")],
|
181
195
|
)
|
182
196
|
for prop in cls.properties.values():
|
183
197
|
# this is a create object, so users can create private field
|
184
|
-
# hence, we do not check for prop.is_private
|
198
|
+
# hence, we do not check for prop.is_private -- however, this field can be omitted
|
199
|
+
# during update, so we need to mark it as optional
|
185
200
|
# if prop.data.is_private:
|
186
201
|
# continue
|
187
202
|
|
@@ -189,7 +204,14 @@ def make_python_data_model(
|
|
189
204
|
pytype = prop.get_data_model_datatype().get_python_type()
|
190
205
|
if pytype.dep is not None:
|
191
206
|
program.import_(pytype.dep, True)
|
207
|
+
|
192
208
|
pytype_type = pytype.type
|
209
|
+
if prop.data.is_private:
|
210
|
+
program.import_("typing.Union", True)
|
211
|
+
program.import_("sera.typing.UnsetType", True)
|
212
|
+
program.import_("sera.typing.UNSET", True)
|
213
|
+
pytype_type = f"Union[{pytype_type}, UnsetType]"
|
214
|
+
|
193
215
|
if len(prop.data.constraints) > 0:
|
194
216
|
# if the property has constraints, we need to figure out
|
195
217
|
program.import_("typing.Annotated", True)
|
@@ -202,7 +224,9 @@ def make_python_data_model(
|
|
202
224
|
raise NotImplementedError(prop.data.constraints)
|
203
225
|
|
204
226
|
prop_default_value = None
|
205
|
-
if prop.
|
227
|
+
if prop.data.is_private:
|
228
|
+
prop_default_value = expr.ExprIdent("UNSET")
|
229
|
+
elif prop.default_value is not None:
|
206
230
|
prop_default_value = expr.ExprConstant(prop.default_value)
|
207
231
|
elif prop.default_factory is not None:
|
208
232
|
program.import_(prop.default_factory.pyfunc, True)
|
@@ -215,6 +239,7 @@ def make_python_data_model(
|
|
215
239
|
)
|
216
240
|
],
|
217
241
|
)
|
242
|
+
|
218
243
|
cls_ast(
|
219
244
|
stmt.DefClassVarStatement(
|
220
245
|
prop.name, pytype_type, prop_default_value
|
sera/misc/_formatter.py
CHANGED
@@ -5,9 +5,8 @@ from concurrent.futures import ThreadPoolExecutor
|
|
5
5
|
from dataclasses import dataclass
|
6
6
|
from pathlib import Path
|
7
7
|
|
8
|
-
from tqdm import tqdm
|
9
|
-
|
10
8
|
from sera.typing import Language
|
9
|
+
from tqdm import tqdm
|
11
10
|
|
12
11
|
|
13
12
|
@dataclass
|
@@ -49,6 +48,9 @@ class Formatter:
|
|
49
48
|
f"Formatting not implemented for {file.language}"
|
50
49
|
)
|
51
50
|
|
51
|
+
if len(self.pending_files) == 0:
|
52
|
+
return
|
53
|
+
|
52
54
|
with ThreadPoolExecutor() as executor:
|
53
55
|
list(
|
54
56
|
tqdm(
|
sera/models/_module.py
CHANGED
@@ -10,7 +10,6 @@ import black.mode
|
|
10
10
|
import isort
|
11
11
|
from codegen.models import Program
|
12
12
|
from loguru import logger
|
13
|
-
|
14
13
|
from sera.misc import File, Formatter
|
15
14
|
from sera.typing import Language
|
16
15
|
|
@@ -169,3 +168,8 @@ class App:
|
|
169
168
|
self.schema_files = schema_files
|
170
169
|
|
171
170
|
self.language = language
|
171
|
+
|
172
|
+
@property
|
173
|
+
def name(self) -> str:
|
174
|
+
"""Get the name of the application"""
|
175
|
+
return self.root.dir.name
|
sera/typing.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from enum import Enum
|
4
|
-
from typing import Annotated, TypeVar
|
4
|
+
from typing import Annotated, Any, TypeGuard, TypeVar, Union
|
5
|
+
|
6
|
+
import msgspec
|
5
7
|
|
6
8
|
|
7
9
|
class doc(str):
|
@@ -18,3 +20,13 @@ ObjectPath = Annotated[
|
|
18
20
|
class Language(str, Enum):
|
19
21
|
Python = "python"
|
20
22
|
Typescript = "typescript"
|
23
|
+
|
24
|
+
|
25
|
+
# re-export msgspec.UnsetType & msgspec.UNSET, so that we are consistent with ORM & data modules
|
26
|
+
UnsetType = msgspec.UnsetType
|
27
|
+
UNSET: Any = msgspec.UNSET
|
28
|
+
|
29
|
+
|
30
|
+
def is_set(value: Union[T, UnsetType]) -> TypeGuard[T]:
|
31
|
+
"""Typeguard to check if a value is set (not UNSET)"""
|
32
|
+
return value is not UNSET
|
@@ -2,17 +2,17 @@ sera/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
sera/constants.py,sha256=mzAaMyIx8TJK0-RYYJ5I24C4s0Uvj26OLMJmBo0pxHI,123
|
3
3
|
sera/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
sera/libs/api_helper.py,sha256=hUEy0INHM18lxTQ348tgbXNceOHcjiAnqmuL_8CRpLQ,2509
|
5
|
-
sera/libs/base_orm.py,sha256=
|
6
|
-
sera/libs/base_service.py,sha256=
|
5
|
+
sera/libs/base_orm.py,sha256=sTiHvbvLALSFygCITKFTXK1w-8UtxXGT_Te-1PEAiCI,3094
|
6
|
+
sera/libs/base_service.py,sha256=l5D4IjxIiz8LBRranUYddb8J0Y6SwSyetKYTLrCUdQA,4098
|
7
7
|
sera/make/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
sera/make/__main__.py,sha256=G5O7s6135-708honwqMFn2yPTs06WbGQTHpupID0eZ4,1417
|
9
|
-
sera/make/make_app.py,sha256=
|
9
|
+
sera/make/make_app.py,sha256=n9NtW73O3s_5Q31VHIRmnd-jEIcpDO7ksAsOdovde2s,5999
|
10
10
|
sera/make/make_python_api.py,sha256=RuJUm9z-4plBEtjobeOPr12o27OT-0tSeXI4ZlM3IY0,29433
|
11
|
-
sera/make/make_python_model.py,sha256=
|
11
|
+
sera/make/make_python_model.py,sha256=xf4revAwVWEnF6QhxbbqPyUGgXOOB--Gu3jPxsESg0Y,36593
|
12
12
|
sera/make/make_python_services.py,sha256=RsinYZdfkrTlTn9CT50VgqGs9w6IZawsJx-KEmqfnEY,2062
|
13
13
|
sera/make/make_typescript_model.py,sha256=dT1ZHpsDvegX07jxDRncd_iu4FAiaV_7xyioWBJdbes,36999
|
14
14
|
sera/misc/__init__.py,sha256=Dh4uDq0D4N53h3zhvmwfa5a0TPVRSUvLzb0hkFuPirk,411
|
15
|
-
sera/misc/_formatter.py,sha256=
|
15
|
+
sera/misc/_formatter.py,sha256=aCGYL08l8f3aLODHxSocxBBwkRYEo3K1QzCDEn3suj0,1685
|
16
16
|
sera/misc/_utils.py,sha256=V5g4oLGHOhUCR75Kkcn1w01pAvGvaepK-T8Z3pIgHjI,1450
|
17
17
|
sera/models/__init__.py,sha256=vJC5Kzo_N7wd16ocNPy1VvAZDGNiWeiAhWJ4ihATKvA,780
|
18
18
|
sera/models/_class.py,sha256=Wf0e8x6-szG9TzoFkAlqj7_dG0SCICMBw_333n3paxk,2514
|
@@ -21,12 +21,12 @@ sera/models/_constraints.py,sha256=lZmCh6Py0UVMdhTR7zUOPPzGqJGbmDCzf7xH7yITcbQ,1
|
|
21
21
|
sera/models/_datatype.py,sha256=uMxK_8wBLowaIMIAYCb3V17YmkzJrKKc5orjImzqWbA,5818
|
22
22
|
sera/models/_default.py,sha256=ABggW6qdPR4ZDqIPJdJ0GCGQ-7kfsfZmQ_DchgZEa-I,137
|
23
23
|
sera/models/_enum.py,sha256=sy0q7E646F-APsqrVQ52r1fAQ_DCAeaNq5YM5QN3zIk,2070
|
24
|
-
sera/models/_module.py,sha256=
|
24
|
+
sera/models/_module.py,sha256=8QRSCubZmdDP9rL58rGAS6X5VCrkc1ZHvuMu1I1KrWk,5043
|
25
25
|
sera/models/_multi_lingual_string.py,sha256=JETN6k00VH4wrA4w5vAHMEJV8fp3SY9bJebskFTjQLA,1186
|
26
26
|
sera/models/_parse.py,sha256=sJYfQtwek96ltpgxExG4xUbiLnU3qvNYhTP1CeyXGjs,9746
|
27
27
|
sera/models/_property.py,sha256=CmEmgOShtSyNFq05YW3tGupwCIVRzPMKudXWld8utPk,5530
|
28
28
|
sera/models/_schema.py,sha256=r-Gqg9Lb_wR3UrbNvfXXgt_qs5bts0t2Ve7aquuF_OI,1155
|
29
|
-
sera/typing.py,sha256=
|
30
|
-
sera_2-1.6.
|
31
|
-
sera_2-1.6.
|
32
|
-
sera_2-1.6.
|
29
|
+
sera/typing.py,sha256=Q4QMfbtfrCjC9tFfsZPhsAnbNX4lm4NHQ9lmjNXYdV0,772
|
30
|
+
sera_2-1.6.2.dist-info/METADATA,sha256=B_Brp3KBIu2C0iqX-5cjwdWAfen1DttoeUyj0ms_7-4,856
|
31
|
+
sera_2-1.6.2.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
32
|
+
sera_2-1.6.2.dist-info/RECORD,,
|
File without changes
|