sera-2 1.12.3__py3-none-any.whl → 1.13.0__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.
@@ -1,9 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
- from operator import is_
4
3
  from typing import Callable, Optional, Sequence
5
4
 
6
- from codegen.models import AST, DeferredVar, PredefinedFn, Program, expr, stmt
5
+ from codegen.models import (
6
+ AST,
7
+ DeferredVar,
8
+ ImportHelper,
9
+ PredefinedFn,
10
+ Program,
11
+ expr,
12
+ stmt,
13
+ )
7
14
 
8
15
  from sera.misc import (
9
16
  assert_isinstance,
@@ -20,6 +27,7 @@ from sera.models import (
20
27
  PyTypeWithDep,
21
28
  Schema,
22
29
  )
30
+ from sera.models._property import SystemControlledMode
23
31
  from sera.typing import ObjectPath
24
32
 
25
33
 
@@ -211,10 +219,19 @@ def make_python_data_model(
211
219
  alias=f"{cls.name}DB",
212
220
  )
213
221
 
214
- has_system_controlled = any(
215
- prop.data.is_system_controlled for prop in cls.properties.values()
222
+ ident_manager = ImportHelper(
223
+ program,
224
+ {
225
+ "UNSET": "sera.typing.UNSET",
226
+ },
227
+ )
228
+
229
+ # property that normal users cannot set, but super users can
230
+ has_restricted_system_controlled = any(
231
+ prop.data.is_system_controlled == SystemControlledMode.RESTRICTED
232
+ for prop in cls.properties.values()
216
233
  )
217
- if has_system_controlled:
234
+ if has_restricted_system_controlled:
218
235
  program.import_("typing.TypedDict", True)
219
236
  program.root(
220
237
  stmt.LineBreak(),
@@ -236,6 +253,7 @@ def make_python_data_model(
236
253
  )
237
254
  for prop in cls.properties.values()
238
255
  if prop.data.is_system_controlled
256
+ == SystemControlledMode.RESTRICTED
239
257
  ],
240
258
  ),
241
259
  )
@@ -246,11 +264,10 @@ def make_python_data_model(
246
264
  [expr.ExprIdent("msgspec.Struct"), expr.ExprIdent("kw_only=True")],
247
265
  )
248
266
  for prop in cls.properties.values():
249
- # this is a create object, so users can create private field
250
- # hence, we do not check for prop.is_private -- however, this field can be omitted
251
- # during update, so we need to mark it as optional
252
- # if prop.data.is_private:
253
- # continue
267
+ # a field that is fully controlled by the system (e.g., cached or derived fields)
268
+ # aren't allowed to be set by the users, so we skip them
269
+ if prop.data.is_system_controlled == SystemControlledMode.AUTO:
270
+ continue
254
271
 
255
272
  if isinstance(prop, DataProperty):
256
273
  pytype = prop.get_data_model_datatype().get_python_type()
@@ -272,14 +289,20 @@ def make_python_data_model(
272
289
  else:
273
290
  raise NotImplementedError(prop.data.constraints)
274
291
 
275
- if prop.data.is_private:
292
+ if (
293
+ prop.data.is_private
294
+ or prop.data.is_system_controlled == SystemControlledMode.RESTRICTED
295
+ ):
276
296
  program.import_("typing.Union", True)
277
297
  program.import_("sera.typing.UnsetType", True)
278
298
  program.import_("sera.typing.UNSET", True)
279
299
  pytype_type = f"Union[{pytype_type}, UnsetType]"
280
300
 
281
301
  prop_default_value = None
282
- if prop.data.is_private:
302
+ if (
303
+ prop.data.is_private
304
+ or prop.data.is_system_controlled == SystemControlledMode.RESTRICTED
305
+ ):
283
306
  prop_default_value = expr.ExprIdent("UNSET")
284
307
  elif prop.default_value is not None:
285
308
  prop_default_value = expr.ExprConstant(prop.default_value)
@@ -321,25 +344,28 @@ def make_python_data_model(
321
344
  elif prop.is_optional:
322
345
  pytype = pytype.as_optional_type()
323
346
 
347
+ pytype_type = pytype.type
348
+ prop_default_value = None
349
+ if prop.data.is_system_controlled == SystemControlledMode.RESTRICTED:
350
+ program.import_("typing.Union", True)
351
+ program.import_("sera.typing.UnsetType", True)
352
+ program.import_("sera.typing.UNSET", True)
353
+ pytype_type = f"Union[{pytype_type}, UnsetType]"
354
+ prop_default_value = expr.ExprIdent("UNSET")
355
+
324
356
  for dep in pytype.deps:
325
357
  program.import_(dep, True)
326
358
 
327
- cls_ast(stmt.DefClassVarStatement(prop.name, pytype.type))
328
-
329
- # has_to_db = True
330
- # if any(prop for prop in cls.properties.values() if isinstance(prop, ObjectProperty) and prop.cardinality == Cardinality.MANY_TO_MANY):
331
- # # if the class has many-to-many relationship, we need to
359
+ cls_ast(
360
+ stmt.DefClassVarStatement(
361
+ prop.name, pytype_type, prop_default_value
362
+ )
363
+ )
332
364
 
333
- if has_system_controlled:
365
+ if has_restricted_system_controlled:
334
366
  program.import_("typing.Optional", True)
367
+ program.import_("sera.typing.is_set", True)
335
368
  cls_ast(
336
- stmt.LineBreak(),
337
- stmt.Comment(
338
- "_verified is a special marker to indicate whether the data is updated by the system."
339
- ),
340
- stmt.DefClassVarStatement(
341
- "_verified", "bool", expr.ExprConstant(False)
342
- ),
343
369
  stmt.LineBreak(),
344
370
  lambda ast: ast.func(
345
371
  "__post_init__",
@@ -347,12 +373,17 @@ def make_python_data_model(
347
373
  DeferredVar.simple("self"),
348
374
  ],
349
375
  )(
350
- stmt.AssignStatement(
351
- PredefinedFn.attr_getter(
352
- expr.ExprIdent("self"), expr.ExprIdent("_verified")
353
- ),
354
- expr.ExprConstant(False),
355
- )
376
+ *[
377
+ stmt.AssignStatement(
378
+ PredefinedFn.attr_getter(
379
+ expr.ExprIdent("self"), expr.ExprIdent(prop.name)
380
+ ),
381
+ expr.ExprIdent("UNSET"),
382
+ )
383
+ for prop in cls.properties.values()
384
+ if prop.data.is_system_controlled
385
+ == SystemControlledMode.RESTRICTED
386
+ ]
356
387
  ),
357
388
  stmt.LineBreak(),
358
389
  lambda ast: ast.func(
@@ -381,14 +412,9 @@ def make_python_data_model(
381
412
  )
382
413
  for prop in cls.properties.values()
383
414
  if prop.data.is_system_controlled
415
+ == SystemControlledMode.RESTRICTED
384
416
  ]
385
417
  ),
386
- stmt.AssignStatement(
387
- PredefinedFn.attr_getter(
388
- expr.ExprIdent("self"), expr.ExprIdent("_verified")
389
- ),
390
- expr.ExprConstant(True),
391
- ),
392
418
  ),
393
419
  )
394
420
 
@@ -405,14 +431,27 @@ def make_python_data_model(
405
431
  )(
406
432
  (
407
433
  stmt.AssertionStatement(
408
- PredefinedFn.attr_getter(
409
- expr.ExprIdent("self"), expr.ExprIdent("_verified")
434
+ expr.ExprLogicalAnd(
435
+ [
436
+ expr.ExprFuncCall(
437
+ expr.ExprIdent("is_set"),
438
+ [
439
+ PredefinedFn.attr_getter(
440
+ expr.ExprIdent("self"),
441
+ expr.ExprIdent(prop.name),
442
+ )
443
+ ],
444
+ )
445
+ for prop in cls.properties.values()
446
+ if prop.data.is_system_controlled
447
+ == SystemControlledMode.RESTRICTED
448
+ ]
410
449
  ),
411
450
  expr.ExprConstant(
412
451
  "The model data must be verified before converting to db model"
413
452
  ),
414
453
  )
415
- if has_system_controlled
454
+ if has_restricted_system_controlled
416
455
  else None
417
456
  ),
418
457
  lambda ast10: ast10.return_(
@@ -421,8 +460,13 @@ def make_python_data_model(
421
460
  f"{cls.name}DB" if cls.db is not None else cls.name
422
461
  ),
423
462
  [
424
- to_db_type_conversion(
425
- program, expr.ExprIdent("self"), cls, prop
463
+ (
464
+ to_db_type_conversion(
465
+ program, expr.ExprIdent("self"), cls, prop
466
+ )
467
+ if prop.data.is_system_controlled
468
+ != SystemControlledMode.AUTO
469
+ else ident_manager.use("UNSET")
426
470
  )
427
471
  for prop in cls.properties.values()
428
472
  ],
@@ -623,8 +667,11 @@ def make_python_relational_model(
623
667
  program.import_("__future__.annotations", True)
624
668
  program.import_("sera.libs.base_orm.BaseORM", True)
625
669
  program.import_("sera.libs.base_orm.create_engine", True)
670
+ program.import_("sera.libs.base_orm.create_async_engine", True)
626
671
  program.import_("sqlalchemy.orm.DeclarativeBase", True)
627
672
  program.import_("sqlalchemy.orm.Session", True)
673
+ program.import_("sqlalchemy.ext.asyncio.AsyncSession", True)
674
+ program.import_("sqlalchemy.text", True)
628
675
 
629
676
  # assume configuration for the app at the top level
630
677
  program.import_(f"{app.config.path}.DB_CONNECTION", True)
@@ -673,14 +720,22 @@ def make_python_relational_model(
673
720
 
674
721
  program.root.linebreak()
675
722
  program.root.assign(
676
- DeferredVar("engine", force_name="engine"),
723
+ DeferredVar.simple("engine"),
677
724
  expr.ExprFuncCall(
678
725
  expr.ExprIdent("create_engine"),
679
726
  [
680
727
  expr.ExprIdent("DB_CONNECTION"),
681
- PredefinedFn.keyword_assignment(
682
- "debug", expr.ExprIdent("DB_DEBUG")
683
- ),
728
+ PredefinedFn.keyword_assignment("echo", expr.ExprIdent("DB_DEBUG")),
729
+ ],
730
+ ),
731
+ )
732
+ program.root.assign(
733
+ DeferredVar.simple("async_engine"),
734
+ expr.ExprFuncCall(
735
+ expr.ExprIdent("create_async_engine"),
736
+ [
737
+ expr.ExprIdent("DB_CONNECTION"),
738
+ PredefinedFn.keyword_assignment("echo", expr.ExprIdent("DB_DEBUG")),
684
739
  ],
685
740
  ),
686
741
  )
@@ -691,17 +746,96 @@ def make_python_relational_model(
691
746
  )
692
747
 
693
748
  program.root.linebreak()
694
- program.root.func("async_get_session", [], is_async=True)(
695
- lambda ast00: ast00.python_stmt("with Session(engine) as session:")(
696
- lambda ast01: ast01.python_stmt("yield session")
749
+ program.root.func("get_async_session", [], is_async=True)(
750
+ lambda ast: ast.python_stmt(
751
+ "async with AsyncSession(async_engine, expire_on_commit=False) as session:"
752
+ )(
753
+ lambda ast_l1: ast_l1.try_()(stmt.PythonStatement("yield session")),
754
+ lambda ast_l1: ast_l1.catch()(
755
+ stmt.SingleExprStatement(
756
+ expr.ExprAwait(
757
+ expr.ExprFuncCall(
758
+ PredefinedFn.attr_getter(
759
+ expr.ExprIdent("session"),
760
+ expr.ExprIdent("rollback"),
761
+ ),
762
+ [],
763
+ )
764
+ )
765
+ ),
766
+ stmt.PythonStatement("raise"),
767
+ ),
768
+ lambda ast_l1: ast_l1.else_()(
769
+ stmt.SingleExprStatement(
770
+ expr.ExprAwait(
771
+ expr.ExprFuncCall(
772
+ PredefinedFn.attr_getter(
773
+ expr.ExprIdent("session"), expr.ExprIdent("execute")
774
+ ),
775
+ [
776
+ expr.ExprFuncCall(
777
+ expr.ExprIdent("text"),
778
+ [expr.ExprConstant("RESET ROLE;")],
779
+ )
780
+ ],
781
+ )
782
+ )
783
+ ),
784
+ stmt.SingleExprStatement(
785
+ expr.ExprAwait(
786
+ expr.ExprFuncCall(
787
+ PredefinedFn.attr_getter(
788
+ expr.ExprIdent("session"), expr.ExprIdent("commit")
789
+ ),
790
+ [],
791
+ )
792
+ )
793
+ ),
794
+ ),
697
795
  )
698
796
  )
699
797
 
700
798
  program.root.linebreak()
701
799
  program.root.python_stmt("@contextmanager")
702
800
  program.root.func("get_session", [])(
703
- lambda ast00: ast00.python_stmt("with Session(engine) as session:")(
704
- lambda ast01: ast01.python_stmt("yield session")
801
+ lambda ast: ast.python_stmt(
802
+ "with Session(engine, expire_on_commit=False) as session:"
803
+ )(
804
+ lambda ast_l1: ast_l1.try_()(stmt.PythonStatement("yield session")),
805
+ lambda ast_l1: ast_l1.catch()(
806
+ stmt.SingleExprStatement(
807
+ expr.ExprFuncCall(
808
+ PredefinedFn.attr_getter(
809
+ expr.ExprIdent("session"), expr.ExprIdent("rollback")
810
+ ),
811
+ [],
812
+ )
813
+ ),
814
+ stmt.PythonStatement("raise"),
815
+ ),
816
+ lambda ast_l1: ast_l1.else_()(
817
+ stmt.SingleExprStatement(
818
+ expr.ExprFuncCall(
819
+ PredefinedFn.attr_getter(
820
+ expr.ExprIdent("session"), expr.ExprIdent("execute")
821
+ ),
822
+ [
823
+ expr.ExprFuncCall(
824
+ expr.ExprIdent("text"),
825
+ [expr.ExprConstant("RESET ROLE;")],
826
+ )
827
+ ],
828
+ )
829
+ ),
830
+ stmt.SingleExprStatement(
831
+ expr.ExprFuncCall(
832
+ PredefinedFn.attr_getter(
833
+ expr.ExprIdent("session"), expr.ExprIdent("commit")
834
+ ),
835
+ [],
836
+ )
837
+ ),
838
+ ),
705
839
  )
706
840
  )
707
841
 
@@ -4,6 +4,7 @@ from typing import Sequence
4
4
 
5
5
  from codegen.models import DeferredVar, Program, expr, stmt
6
6
  from loguru import logger
7
+
7
8
  from sera.misc import assert_not_null
8
9
  from sera.models import App, DataCollection, Package
9
10
 
@@ -35,13 +36,13 @@ def make_python_service(collection: DataCollection, target_pkg: Package):
35
36
  True,
36
37
  )
37
38
  program.import_(app.config.path + f".schema", True)
38
- program.import_("sera.libs.base_service.BaseService", True)
39
+ program.import_("sera.libs.base_service.BaseAsyncService", True)
39
40
 
40
41
  program.root(
41
42
  stmt.LineBreak(),
42
43
  lambda ast00: ast00.class_(
43
44
  collection.get_service_name(),
44
- [expr.ExprIdent(f"BaseService[{id_type}, {cls.name}]")],
45
+ [expr.ExprIdent(f"BaseAsyncService[{id_type}, {cls.name}]")],
45
46
  )(
46
47
  lambda ast01: ast01.func(
47
48
  "__init__",
sera/models/__init__.py CHANGED
@@ -5,7 +5,13 @@ from sera.models._enum import Enum
5
5
  from sera.models._module import App, Module, Package
6
6
  from sera.models._multi_lingual_string import MultiLingualString
7
7
  from sera.models._parse import parse_schema
8
- from sera.models._property import Cardinality, DataProperty, ObjectProperty, Property
8
+ from sera.models._property import (
9
+ Cardinality,
10
+ DataProperty,
11
+ ObjectProperty,
12
+ Property,
13
+ SystemControlledMode,
14
+ )
9
15
  from sera.models._schema import Schema
10
16
 
11
17
  __all__ = [
@@ -25,4 +31,5 @@ __all__ = [
25
31
  "PyTypeWithDep",
26
32
  "TsTypeWithDep",
27
33
  "Enum",
34
+ "SystemControlledMode",
28
35
  ]
@@ -3,7 +3,15 @@ from __future__ import annotations
3
3
  from dataclasses import dataclass
4
4
  from typing import Literal
5
5
 
6
- ConstraintName = Literal["phone_number", "email", "not_empty", "username", "password"]
6
+ ConstraintName = Literal[
7
+ "phone_number",
8
+ "email",
9
+ "not_empty",
10
+ "username",
11
+ "password",
12
+ "whole_number",
13
+ "positive_number",
14
+ ]
7
15
 
8
16
 
9
17
  @dataclass
@@ -25,6 +33,10 @@ class Constraint:
25
33
  )
26
34
  elif self.name == "password":
27
35
  return "msgspec.Meta(min_length=8, max_length=40)"
36
+ elif self.name == "whole_number":
37
+ return "msgspec.Meta(ge=0)"
38
+ elif self.name == "positive_number":
39
+ return "msgspec.Meta(gt=0)"
28
40
 
29
41
  raise NotImplementedError()
30
42
 
@@ -43,4 +55,6 @@ predefined_constraints: dict[ConstraintName, Constraint] = {
43
55
  "not_empty": Constraint("not_empty", ()),
44
56
  "username": Constraint("username", ()),
45
57
  "password": Constraint("password", ()),
58
+ "whole_number": Constraint("whole_number", ()),
59
+ "positive_number": Constraint("positive_number", ()),
46
60
  }
sera/models/_datatype.py CHANGED
@@ -164,6 +164,16 @@ predefined_datatypes = {
164
164
  tstype=TsTypeWithDep(type="number"),
165
165
  is_list=False,
166
166
  ),
167
+ "date": DataType(
168
+ pytype=PyTypeWithDep(type="date", deps=["datetime.date"]),
169
+ sqltype=SQLTypeWithDep(
170
+ type="Date",
171
+ mapped_pytype="date",
172
+ deps=["sqlalchemy.Date", "datetime.date"],
173
+ ),
174
+ tstype=TsTypeWithDep(type="string"),
175
+ is_list=False,
176
+ ),
167
177
  "datetime": DataType(
168
178
  pytype=PyTypeWithDep(type="datetime", deps=["datetime.datetime"]),
169
179
  sqltype=SQLTypeWithDep(
sera/models/_parse.py CHANGED
@@ -31,6 +31,7 @@ from sera.models._property import (
31
31
  ObjectPropDBInfo,
32
32
  ObjectProperty,
33
33
  PropDataAttrs,
34
+ SystemControlledMode,
34
35
  )
35
36
  from sera.models._schema import Schema
36
37
 
@@ -76,7 +77,7 @@ def _parse_class_without_prop(schema: Schema, clsname: str, cls: dict) -> Class:
76
77
  return Class(
77
78
  name=clsname,
78
79
  label=_parse_multi_lingual_string(cls["label"]),
79
- description=_parse_multi_lingual_string(cls["desc"]),
80
+ description=_parse_multi_lingual_string(cls.get("desc", "")),
80
81
  properties={},
81
82
  db=db,
82
83
  )
@@ -131,7 +132,9 @@ def _parse_property(
131
132
  constraints=[
132
133
  _parse_constraint(constraint) for constraint in _data.get("constraints", [])
133
134
  ],
134
- is_system_controlled=prop.get("is_system_controlled", False),
135
+ is_system_controlled=SystemControlledMode(
136
+ _data.get("is_system_controlled", SystemControlledMode.NO.value)
137
+ ),
135
138
  )
136
139
 
137
140
  assert isinstance(prop, dict), prop
@@ -222,12 +225,14 @@ def _parse_datatype(schema: Schema, datatype: dict | str) -> DataType:
222
225
  # the correct package yet.
223
226
  pytype=PyTypeWithDep(
224
227
  type=enum.name,
225
- dep=f"{schema.name}.models.enums.{enum.get_pymodule_name()}.{enum.name}",
228
+ deps=[
229
+ f"{schema.name}.models.enums.{enum.get_pymodule_name()}.{enum.name}"
230
+ ],
226
231
  ),
227
232
  sqltype=SQLTypeWithDep(
228
233
  type="String", mapped_pytype="str", deps=["sqlalchemy.String"]
229
234
  ),
230
- tstype=TsTypeWithDep(type=enum.name, dep="@/models/enums"),
235
+ tstype=TsTypeWithDep(type=enum.name, deps=["@/models/enums"]),
231
236
  is_list=is_list,
232
237
  )
233
238
 
sera/models/_property.py CHANGED
@@ -56,6 +56,19 @@ class Cardinality(str, Enum):
56
56
  ]
57
57
 
58
58
 
59
+ class SystemControlledMode(str, Enum):
60
+ """Indicates if this property is controlled by the system.
61
+
62
+ There are two modes:
63
+ 1. The system automatically sets the value, and users cannot modify it.
64
+ 2. Users with special roles are allowed to set the value and other users cannot modify it
65
+ """
66
+
67
+ AUTO = "auto"
68
+ RESTRICTED = "restricted"
69
+ NO = "no"
70
+
71
+
59
72
  @dataclass(kw_only=True)
60
73
  class PropDataAttrs:
61
74
  """Storing other attributes for generating data model (upsert & public) -- this is different from a db model"""
@@ -72,7 +85,7 @@ class PropDataAttrs:
72
85
  constraints: list[Constraint] = field(default_factory=list)
73
86
 
74
87
  # whether this property is controlled by the system or not
75
- is_system_controlled: bool = False
88
+ is_system_controlled: SystemControlledMode = SystemControlledMode.NO
76
89
 
77
90
 
78
91
  @dataclass(kw_only=True)
sera/models/_schema.py CHANGED
@@ -34,3 +34,14 @@ class Schema:
34
34
 
35
35
  # Convert sorted names back to Class objects
36
36
  return [self.classes[name] for name in sorted_names]
37
+
38
+ def get_upstream_classes(self, cls: Class) -> list[tuple[Class, ObjectProperty]]:
39
+ """
40
+ Get all classes that depend on the given class.
41
+ """
42
+ upstream_classes = []
43
+ for other_cls in self.classes.values():
44
+ for prop in other_cls.properties.values():
45
+ if isinstance(prop, ObjectProperty) and prop.target.name == cls.name:
46
+ upstream_classes.append((other_cls, prop))
47
+ return upstream_classes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sera-2
3
- Version: 1.12.3
3
+ Version: 1.13.0
4
4
  Summary:
5
5
  Author: Binh Vu
6
6
  Author-email: bvu687@gmail.com
@@ -9,13 +9,13 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
10
  Classifier: Programming Language :: Python :: 3.13
11
11
  Requires-Dist: black (>=25.1.0,<26.0.0)
12
- Requires-Dist: codegen-2 (>=2.10.0,<3.0.0)
12
+ Requires-Dist: codegen-2 (>=2.11.0,<3.0.0)
13
13
  Requires-Dist: isort (>=6.0.1,<7.0.0)
14
14
  Requires-Dist: litestar (>=2.15.1,<3.0.0)
15
15
  Requires-Dist: loguru (>=0.7.0,<0.8.0)
16
16
  Requires-Dist: msgspec (>=0.19.0,<0.20.0)
17
17
  Requires-Dist: serde2 (>=1.9.0,<2.0.0)
18
- Requires-Dist: sqlalchemy (>=2.0.40,<3.0.0)
18
+ Requires-Dist: sqlalchemy[asyncio] (>=2.0.41,<3.0.0)
19
19
  Requires-Dist: typer (>=0.12.3,<0.13.0)
20
20
  Project-URL: Repository, https://github.com/binh-vu/sera
21
21
  Description-Content-Type: text/markdown
@@ -1,37 +1,40 @@
1
1
  sera/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  sera/constants.py,sha256=mzAaMyIx8TJK0-RYYJ5I24C4s0Uvj26OLMJmBo0pxHI,123
3
+ sera/exports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ sera/exports/schema.py,sha256=3F5Kx3r0zOmiVpDf9vnzGhtdcuF-vfgMhBbp4Ko4fgw,4740
5
+ sera/exports/test.py,sha256=jK1EJmLGiy7eREpnY_68IIVRH43uH8S_u5Z7STPbXOM,2002
3
6
  sera/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
7
  sera/libs/api_helper.py,sha256=47y1kcwk3Xd2ZEMnUj_0OwCuUmgwOs5kYrE95BDVUn4,5411
5
- sera/libs/base_orm.py,sha256=dyh0OT2sbHku5qPJXvRzYAHRTSXvvbQaS-Qwg65Bw04,2918
6
- sera/libs/base_service.py,sha256=8uKMaIicLc8LbN5vyaK9dGWoCLf_wuaaOw9ooSiqSWM,4614
8
+ sera/libs/base_orm.py,sha256=5hOH_diUeaABm3cpE2-9u50VRqG1QW2osPQnvVHIhIA,3365
9
+ sera/libs/base_service.py,sha256=AX1WoTHte6Z_birkkfagkNE6BrCLTlTjQE4jEsKEaAY,5152
7
10
  sera/libs/dag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
11
  sera/libs/dag/_dag.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
12
  sera/libs/middlewares/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- sera/libs/middlewares/auth.py,sha256=aH2fJshQpJT_dw3lUr67doZ8zdf90XyakdY35qZ1iZs,2443
13
+ sera/libs/middlewares/auth.py,sha256=r6aix1ZBwxMd1Jv5hMCTB8a_gFOJQ6egvxIrf3DWEOs,2323
11
14
  sera/libs/middlewares/uscp.py,sha256=H5umW8iEQSCdb_MJ5Im49kxg1E7TpxSg1p2_2A5zI1U,2600
12
15
  sera/make/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- sera/make/__main__.py,sha256=G5O7s6135-708honwqMFn2yPTs06WbGQTHpupID0eZ4,1417
16
+ sera/make/__main__.py,sha256=bt-gDF8E026OWc2zqr9_a3paMOiDkFd3ybWn8ltL2g0,1448
14
17
  sera/make/make_app.py,sha256=n9NtW73O3s_5Q31VHIRmnd-jEIcpDO7ksAsOdovde2s,5999
15
- sera/make/make_python_api.py,sha256=CM0NTcSUMgRagscvpZwrbI_PR9d4CsgZ2xUVM0rCVVg,26031
16
- sera/make/make_python_model.py,sha256=ldaDnuwudkq81w2hwKZIuRqFnqhxOAaIT_VhYandXG4,46128
17
- sera/make/make_python_services.py,sha256=RsinYZdfkrTlTn9CT50VgqGs9w6IZawsJx-KEmqfnEY,2062
18
+ sera/make/make_python_api.py,sha256=sf-J5Pt1LTyM_H-SgXSAvKjEMDrRA6WnDpgDPbJG360,26896
19
+ sera/make/make_python_model.py,sha256=XWoNmfVNfdzF3lwEaItPZjo27ibqL9yjHA3a0vrHsnA,51708
20
+ sera/make/make_python_services.py,sha256=0ZpWLwQ7Nwfn8BXAikAB4JRpNknpSJyJgY5b1cjtxV4,2073
18
21
  sera/make/make_typescript_model.py,sha256=ugDdSTw_1ayHLuL--92RQ8hf_D-dpJtnvmUZNxcwcDs,63687
19
22
  sera/misc/__init__.py,sha256=Dh4uDq0D4N53h3zhvmwfa5a0TPVRSUvLzb0hkFuPirk,411
20
23
  sera/misc/_formatter.py,sha256=aCGYL08l8f3aLODHxSocxBBwkRYEo3K1QzCDEn3suj0,1685
21
24
  sera/misc/_utils.py,sha256=V5g4oLGHOhUCR75Kkcn1w01pAvGvaepK-T8Z3pIgHjI,1450
22
- sera/models/__init__.py,sha256=vJC5Kzo_N7wd16ocNPy1VvAZDGNiWeiAhWJ4ihATKvA,780
25
+ sera/models/__init__.py,sha256=VcC7HvqXuYrkgXwzs2vOH6LJPpzFBkeDvYVNrd3P-6E,855
23
26
  sera/models/_class.py,sha256=Wf0e8x6-szG9TzoFkAlqj7_dG0SCICMBw_333n3paxk,2514
24
27
  sera/models/_collection.py,sha256=ZnQEriKC4X88Zz48Kn1AVZKH-1_l8OgWa-zf2kcQOOE,1414
25
- sera/models/_constraints.py,sha256=L6QwKL3hRJ5DvvIB4JNgLoyvTKbE9FrpYRzezM4CweE,1484
26
- sera/models/_datatype.py,sha256=RDn0lDl_b0O_PwRqobcD1O903owEAEoMzRf4dyRcgBk,6819
28
+ sera/models/_constraints.py,sha256=PsSOX94b9-73wZTcUif9KTzV9uTfoF0WN87g4GZXQmU,1827
29
+ sera/models/_datatype.py,sha256=y5kfim0G3gLhnGjiokFBr8leU1Y6as_Vw7oK-caOo68,7140
27
30
  sera/models/_default.py,sha256=ABggW6qdPR4ZDqIPJdJ0GCGQ-7kfsfZmQ_DchgZEa-I,137
28
31
  sera/models/_enum.py,sha256=sy0q7E646F-APsqrVQ52r1fAQ_DCAeaNq5YM5QN3zIk,2070
29
32
  sera/models/_module.py,sha256=8QRSCubZmdDP9rL58rGAS6X5VCrkc1ZHvuMu1I1KrWk,5043
30
33
  sera/models/_multi_lingual_string.py,sha256=JETN6k00VH4wrA4w5vAHMEJV8fp3SY9bJebskFTjQLA,1186
31
- sera/models/_parse.py,sha256=uw6fvvh1ucGqE2jFTCCr-e6_qMfZfSVpaPolNxmrHww,9897
32
- sera/models/_property.py,sha256=SJSm5fZJimd2rQuL4UH_aZuNyp9v7x64xMbEVbtYx8Q,5633
33
- sera/models/_schema.py,sha256=r-Gqg9Lb_wR3UrbNvfXXgt_qs5bts0t2Ve7aquuF_OI,1155
34
+ sera/models/_parse.py,sha256=q_YZ7PrHWIN85_WW-fPP7-2gLXlGWM2-EIdbYXuG7Xg,10052
35
+ sera/models/_property.py,sha256=4y9F58D6DoX25-6aWPBRiE72nCPQy0KWlGNDTZXSV-8,6038
36
+ sera/models/_schema.py,sha256=VxJEiqgVvbXgcSUK4UW6JnRcggk4nsooVSE6MyXmfNY,1636
34
37
  sera/typing.py,sha256=Q4QMfbtfrCjC9tFfsZPhsAnbNX4lm4NHQ9lmjNXYdV0,772
35
- sera_2-1.12.3.dist-info/METADATA,sha256=5KV9Z9cwjWA1UZKqo9iCrj0XRwL54xS7JmRrGAc5S7s,858
36
- sera_2-1.12.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
- sera_2-1.12.3.dist-info/RECORD,,
38
+ sera_2-1.13.0.dist-info/METADATA,sha256=IFUs-nyqkQ4yDQeCL507_8not1XYcKeLFYrLxLg4lc8,867
39
+ sera_2-1.13.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
40
+ sera_2-1.13.0.dist-info/RECORD,,