sera-2 1.1.0__py3-none-any.whl → 1.2.1__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/models/_datatype.py CHANGED
@@ -5,12 +5,29 @@ from dataclasses import dataclass
5
5
  from enum import Enum
6
6
  from typing import Literal
7
7
 
8
+ PyDataType = Literal["str", "int", "datetime", "float", "bool", "bytes", "dict"]
9
+ TypescriptDataType = Literal["string", "number", "boolean"]
10
+ SQLAlchemyDataType = Literal[
11
+ "String",
12
+ "Integer",
13
+ "Float",
14
+ "Boolean",
15
+ "DateTime",
16
+ "JSON",
17
+ "Text",
18
+ "LargeBinary",
19
+ ]
20
+
8
21
 
9
22
  @dataclass
10
23
  class TypeWithDep:
11
24
  type: str
12
25
  dep: str | None = None
13
26
 
27
+
28
+ @dataclass
29
+ class PyTypeWithDep(TypeWithDep):
30
+
14
31
  def get_python_type(self) -> type:
15
32
  """Get the Python type from the type string for typing annotation in Python."""
16
33
  if self.type == "str":
@@ -33,22 +50,43 @@ class TypeWithDep:
33
50
 
34
51
  @dataclass
35
52
  class DataType:
36
- type: Literal["str", "int", "datetime", "float", "bool", "bytes", "dict"]
53
+ pytype: PyDataType
54
+ sqltype: SQLAlchemyDataType
55
+ tstype: TypescriptDataType
56
+
37
57
  is_list: bool = False
38
- parent: DataType | None = None
39
58
 
40
59
  def get_python_type(self) -> TypeWithDep:
41
- if self.type in ["str", "int", "float", "bool", "bytes", "dict"]:
42
- return TypeWithDep(type=self.type)
43
- if self.type == "datetime":
60
+ if self.pytype in ["str", "int", "float", "bool", "bytes", "dict"]:
61
+ return TypeWithDep(type=self.pytype)
62
+ if self.pytype == "datetime":
44
63
  return TypeWithDep(type="datetime", dep="datetime.datetime")
45
- raise NotImplementedError(self.type)
64
+ raise NotImplementedError(self.pytype)
46
65
 
47
66
  def get_sqlalchemy_type(self) -> TypeWithDep:
48
- if self.type in ["str", "int", "float", "bool", "bytes"]:
49
- return TypeWithDep(type=self.type)
50
- if self.type == "dict":
67
+ if self.pytype in ["str", "int", "float", "bool", "bytes"]:
68
+ return TypeWithDep(type=self.pytype)
69
+ if self.pytype == "dict":
51
70
  return TypeWithDep(type="JSON")
52
- if self.type == "datetime":
71
+ if self.pytype == "datetime":
53
72
  return TypeWithDep(type="datetime", dep="datetime.datetime")
54
- raise NotImplementedError(self.type)
73
+ raise NotImplementedError(self.pytype)
74
+
75
+
76
+ predefined_datatypes = {
77
+ "string": DataType(pytype="str", sqltype="String", tstype="string", is_list=False),
78
+ "integer": DataType(
79
+ pytype="int", sqltype="Integer", tstype="number", is_list=False
80
+ ),
81
+ "datetime": DataType(
82
+ pytype="datetime", sqltype="DateTime", tstype="string", is_list=False
83
+ ),
84
+ "float": DataType(pytype="float", sqltype="Float", tstype="number", is_list=False),
85
+ "boolean": DataType(
86
+ pytype="bool", sqltype="Boolean", tstype="boolean", is_list=False
87
+ ),
88
+ "bytes": DataType(
89
+ pytype="bytes", sqltype="LargeBinary", tstype="string", is_list=False
90
+ ),
91
+ "dict": DataType(pytype="dict", sqltype="JSON", tstype="string", is_list=False),
92
+ }
sera/models/_module.py CHANGED
@@ -8,6 +8,7 @@ from typing import Sequence
8
8
 
9
9
  import black
10
10
  import black.mode
11
+ import isort
11
12
  from codegen.models import Program
12
13
  from loguru import logger
13
14
 
@@ -63,9 +64,9 @@ class Module:
63
64
  program.root.to_python(),
64
65
  mode=black.Mode(
65
66
  target_versions={black.mode.TargetVersion.PY312},
66
- line_length=120,
67
67
  ),
68
68
  )
69
+ code = isort.code(code, profile="black")
69
70
  except:
70
71
  logger.error("Error writing module {}", self.path)
71
72
  print(">>> Program")
@@ -76,8 +77,16 @@ class Module:
76
77
  assert self.language == Language.Typescript
77
78
  raise NotImplementedError()
78
79
 
79
- copyright_statement = f"# Generated automatically at {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}. All rights reserved.\n\n"
80
- (self.package.dir / f"{self.name}.py").write_text(copyright_statement + code)
80
+ outfile = self.package.dir / f"{self.name}.py"
81
+ if outfile.exists():
82
+ if outfile.read_text().startswith("# sera:skip"):
83
+ logger.info(
84
+ "`{}` already exists and is in manual edit mode. Skip updating it.",
85
+ outfile,
86
+ )
87
+ return
88
+ copyright_statement = f"# Generated by SERA \n\n"
89
+ outfile.write_text(copyright_statement + code)
81
90
 
82
91
  def exists(self) -> bool:
83
92
  """Check if the module exists"""
sera/models/_parse.py CHANGED
@@ -1,11 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from copy import deepcopy
3
4
  from pathlib import Path
4
5
  from typing import Sequence
5
6
 
6
7
  import serde.yaml
7
8
  from sera.models._class import Class, ClassDBMapInfo
8
- from sera.models._datatype import DataType
9
+ from sera.models._datatype import DataType, predefined_datatypes
9
10
  from sera.models._multi_lingual_string import MultiLingualString
10
11
  from sera.models._property import (
11
12
  Cardinality,
@@ -111,8 +112,18 @@ def _parse_property(
111
112
  db=(
112
113
  ObjectPropDBInfo(
113
114
  is_embedded=db.get("is_embedded", None),
114
- on_delete=ForeignKeyOnDelete(db.get("on_delete", "restrict")),
115
- on_update=ForeignKeyOnUpdate(db.get("on_update", "restrict")),
115
+ on_target_delete=ForeignKeyOnDelete(
116
+ db.get("on_target_delete", "restrict")
117
+ ),
118
+ on_target_update=ForeignKeyOnUpdate(
119
+ db.get("on_target_update", "restrict")
120
+ ),
121
+ on_source_delete=ForeignKeyOnDelete(
122
+ db.get("on_source_delete", "restrict")
123
+ ),
124
+ on_source_update=ForeignKeyOnUpdate(
125
+ db.get("on_source_update", "restrict")
126
+ ),
116
127
  )
117
128
  if "db" in prop
118
129
  else None
@@ -135,19 +146,9 @@ def _parse_datatype(datatype: str) -> DataType:
135
146
  else:
136
147
  is_list = False
137
148
 
138
- if datatype == "string":
139
- return DataType("str", is_list=is_list, parent=None)
140
- if datatype == "integer":
141
- return DataType("int", is_list=is_list, parent=None)
142
- if datatype == "datetime":
143
- return DataType("datetime", is_list=is_list, parent=None)
144
- if datatype == "bool":
145
- return DataType("bool", is_list=is_list, parent=None)
146
- if datatype == "float":
147
- return DataType("float", is_list=is_list, parent=None)
148
- if datatype == "bytes":
149
- return DataType("bytes", is_list=is_list, parent=None)
150
- if datatype == "dict":
151
- return DataType("dict", is_list=is_list, parent=None)
152
-
153
- raise NotImplementedError(datatype)
149
+ if datatype not in predefined_datatypes:
150
+ raise NotImplementedError(datatype)
151
+
152
+ dt = deepcopy(predefined_datatypes[datatype])
153
+ dt.is_list = is_list
154
+ return dt
sera/models/_property.py CHANGED
@@ -103,8 +103,12 @@ class ObjectPropDBInfo:
103
103
  is_embedded: Optional[Literal["composite", "json"]] = None
104
104
 
105
105
  # if the target class is stored in the database, control the cascade behavior
106
- on_delete: ForeignKeyOnDelete = ForeignKeyOnDelete.RESTRICT
107
- on_update: ForeignKeyOnUpdate = ForeignKeyOnUpdate.RESTRICT
106
+ on_target_delete: ForeignKeyOnDelete = ForeignKeyOnDelete.RESTRICT
107
+ on_target_update: ForeignKeyOnUpdate = ForeignKeyOnUpdate.RESTRICT
108
+
109
+ # this is the case for many-to-many relationships
110
+ on_source_delete: ForeignKeyOnDelete = ForeignKeyOnDelete.RESTRICT
111
+ on_source_update: ForeignKeyOnUpdate = ForeignKeyOnUpdate.RESTRICT
108
112
 
109
113
 
110
114
  @dataclass(kw_only=True)
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sera-2
3
- Version: 1.1.0
3
+ Version: 1.2.1
4
4
  Summary:
5
+ Home-page: https://github.com/binh-vu/sera
5
6
  Author: Binh Vu
6
7
  Author-email: bvu687@gmail.com
7
8
  Requires-Python: >=3.12,<4.0
@@ -12,6 +13,7 @@ Requires-Dist: black (>=25.0.1,<26.0.0)
12
13
  Requires-Dist: codegen-2 (>=2.1.4,<3.0.0)
13
14
  Requires-Dist: litestar (>=2.15.1,<3.0.0)
14
15
  Requires-Dist: msgspec (>=0.19.0,<0.20.0)
16
+ Project-URL: Repository, https://github.com/binh-vu/sera
15
17
  Description-Content-Type: text/markdown
16
18
 
17
19
  # Overview
@@ -1,29 +1,29 @@
1
1
  sera/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  sera/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  sera/libs/api_helper.py,sha256=hUEy0INHM18lxTQ348tgbXNceOHcjiAnqmuL_8CRpLQ,2509
4
- sera/libs/base_orm.py,sha256=IxsHjNPjF60YbLyTsMTOhQbjQX-L30UZtvE_vJDgZfo,2950
5
- sera/libs/base_service.py,sha256=nVHODZjdTqC8rrDKxYUWrK95APrtdMSCYzflePNxXns,2379
4
+ sera/libs/base_orm.py,sha256=Xs1rx_c3FfCQ2EUA8plqBLvZEABqsscLTaCYRhXbIas,2913
5
+ sera/libs/base_service.py,sha256=mC4s2SREWoOtr3JcHPHQ_MvcFaguNEKZ0CmqvBqlnBw,2729
6
6
  sera/make/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  sera/make/__main__.py,sha256=TLHA3e9QVoE0Nic6HSQDNiAe1MrTTw5IdYlNSNxjN5Q,912
8
- sera/make/make_app.py,sha256=e0DQpx6ilB76lxg2BYF6wjL7RFRQzvmOXq2322xm2SQ,4398
9
- sera/make/make_python_api.py,sha256=ikZfJrJ4B606td4os1QgX-7G5QJypmR-3qgLvGOIRh0,8765
10
- sera/make/make_python_model.py,sha256=1zC_NaFkyLYpZ3ytT-ZV6d8xmxtQHUpEFsqd0PkJ6x4,12031
8
+ sera/make/make_app.py,sha256=QDMN1wwfIKu3d68ovapMZWig24hDKJ4hJilNHjJq4EU,4598
9
+ sera/make/make_python_api.py,sha256=lYNitE1a1Es29fB7p5ryD6X_NASBlwNYAbH-rZ5pBbI,28337
10
+ sera/make/make_python_model.py,sha256=2KFgATb1DRZ3M8_cVVuhAZWuGamkO4HMfAqqr5fVUEs,25688
11
11
  sera/make/make_python_services.py,sha256=RsinYZdfkrTlTn9CT50VgqGs9w6IZawsJx-KEmqfnEY,2062
12
12
  sera/make/make_typescript_model.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
13
13
  sera/misc/__init__.py,sha256=hjW2Lf1itdqlDjf1X8hwSZZfmE0XKDFlYtMMC1AXkT4,300
14
14
  sera/misc/_rdf.py,sha256=G0ekWLUSw-eiKUOaPSGkELbZld19S9d36gWwiswjrrs,1671
15
15
  sera/misc/_utils.py,sha256=MY85CZruRLYI2bf44d-a8g4lJibznD2MnAfd9VY1UdQ,1094
16
- sera/models/__init__.py,sha256=3ooJQulUc7oyUoMM89KT5f6nsoYagCjYEyC0AmyYyzY,661
17
- sera/models/_class.py,sha256=vFCuzG0vfAHYBjk1HQMFszT7zUAqGex-VAVJ2CUPIaE,1824
16
+ sera/models/__init__.py,sha256=1B3b-MOMh6_Xe3CsPouOjXLDuJg5G6NcRDPXcA0sQjA,687
17
+ sera/models/_class.py,sha256=saWzNGtw0BIuisgd_6PI5-0pFN690TBHp_7KCTMoh28,1923
18
18
  sera/models/_collection.py,sha256=u3k4t7Z38FiZj9CstPArnf9KsIGr05zbwUn2ZrbQVJE,1078
19
- sera/models/_datatype.py,sha256=JkD3aRQ11DWicS2xaiNPwhBzJNJPwSkktBunx3EVr1s,1714
20
- sera/models/_module.py,sha256=-XW4bJ3v4QZPYPRMnbUW2zp0F5aJVH8uve_MrnwYz7w,3736
19
+ sera/models/_datatype.py,sha256=tGpgZhFeHMA6sJdG5lyMQon2OC1r-fxo_IRGA1GyRtc,2762
20
+ sera/models/_module.py,sha256=YB2w9CZR7d_rF_W09dNZ9Pr4HXW2thXaWMgof1yYo8c,3982
21
21
  sera/models/_multi_lingual_string.py,sha256=cVoxge1SW68dVmOjDZJU93tUq2ccJse3kSPqxrNkmgc,1091
22
- sera/models/_parse.py,sha256=l106WMAFTLjKio5L3rBK3B0NtwjnXh-sLF4Ofk2uFHE,5072
23
- sera/models/_property.py,sha256=lrI6V2zEblUVuEy9lahbLPLFisFRX6zrkO8wFWzU35k,4018
22
+ sera/models/_parse.py,sha256=1WKiiU_P46ynWqGNYhU6KqCX7p0s6wq7mwPqFSiGfAQ,4986
23
+ sera/models/_property.py,sha256=uOVP154lafx10GFsdKuETHdho2SDm663BvO5umHEMlE,4229
24
24
  sera/models/_schema.py,sha256=1F_Ict1NLvDcQDUZwcvnRS5MtsOTv584y3ChymUeUYA,1046
25
25
  sera/namespace.py,sha256=5NJ0A7weZwblqkncpgY2Vfcat04mNtigNcVrqu7TGOc,123
26
26
  sera/typing.py,sha256=CsazgVptDN-far3yISogTtA2KBJlFFOn0lK_WyZFDv8,230
27
- sera_2-1.1.0.dist-info/METADATA,sha256=zmJ_UdY6SLvr7d6pkcQL-oCo9DYB8gxpiM3CikxzySU,599
28
- sera_2-1.1.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
29
- sera_2-1.1.0.dist-info/RECORD,,
27
+ sera_2-1.2.1.dist-info/METADATA,sha256=qXSlZLBNmIQgGSckMb5MfnP5fCuGEViVI4JgwpYiS0A,699
28
+ sera_2-1.2.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
29
+ sera_2-1.2.1.dist-info/RECORD,,
File without changes