Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9817c43

Browse files
authoredMay 12, 2024
fix sqlmodels generation (xnuinside#60)
* fix sqlmodels generation * fix flake8 issues
1 parent 4893e38 commit 9817c43

File tree

16 files changed

+115
-70
lines changed

16 files changed

+115
-70
lines changed
 

‎CHANGELOG.txt

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
**v0.16.0**
2+
3+
### Updates
4+
1. fix character varying type - https://github.com/xnuinside/omymodels/issues/59
5+
2. sqlalchemy import removed from generation in sqlmodels if it is not used
6+
3. = Field() - is not placed in SQLModel if there is no defaults or other settings to the field
7+
8+
19
**v0.15.1**
210
## Updates
311
1. Foreign Key processing updates - https://github.com/xnuinside/omymodels/pull/55

‎README.md

+8
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,14 @@ If you see any bugs or have any suggestions - feel free to open the issue. Any h
307307
One more time, big 'thank you!' goes to https://github.com/archongum for Web-version: https://archon-omymodels-online.hf.space/
308308

309309
## Changelog
310+
**v0.16.0**
311+
312+
### Updates
313+
1. fix character varying type - https://github.com/xnuinside/omymodels/issues/59
314+
2. sqlalchemy import removed from generation in sqlmodels if it is not used
315+
3. = Field() - is not placed in SQLModel if there is no defaults or other settings to the field
316+
317+
310318
**v0.15.1**
311319
## Updates
312320
1. Foreign Key processing updates - https://github.com/xnuinside/omymodels/pull/55

‎docs/README.rst

+10
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,16 @@ One more time, big 'thank you!' goes to https://github.com/archongum for Web-ver
330330
Changelog
331331
---------
332332

333+
**v0.16.0**
334+
335+
Updates
336+
^^^^^^^
337+
338+
339+
#. fix character varying type - https://github.com/xnuinside/omymodels/issues/59
340+
#. sqlalchemy import removed from generation in sqlmodels if it is not used
341+
#. = Field() - is not placed in SQLModel if there is no defaults or other settings to the field
342+
333343
**v0.15.1**
334344

335345
Updates

‎omymodels/cli.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ def version(**kwargs):
1313

1414
def cli():
1515
omm_cli = argparse.ArgumentParser(
16-
description="O! My Models. Create GinoORM models from SQL DDL"
16+
description="O! My Models. "
17+
"Create SQLModels, SQLAlchemy, GinoORM and other models from SQL DDL or another models"
1718
)
1819

1920
omm_cli.add_argument(

‎omymodels/from_ddl.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ def generate_models_file(
153153
schema_global=schema_global,
154154
defaults_off=defaults_off,
155155
)
156-
header += generator.create_header(data["tables"], schema=schema_global)
156+
header += generator.create_header(
157+
data["tables"], schema=schema_global, models_str=models_str
158+
)
157159
else:
158160
models_type = "enum"
159161
output = render_jinja2_template(models_type, models_str, header)

‎omymodels/models/enum/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def create_types(self) -> str:
7474
self.custom_types = {x.name: ("db.Enum", x.name) for x in self.types}
7575
return types_str
7676

77-
def create_header(self) -> str:
77+
def create_header(self, *args, **kwargs) -> str:
7878
self.enum_imports = list(self.enum_imports)
7979
self.enum_imports.sort()
8080
return enum_import.format(enums=", ".join(self.enum_imports)) + "\n"

‎omymodels/models/gino/core.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ def generate_model(
5959
# create sequence
6060
return model
6161

62-
def create_header(self, tables: List[Dict], schema: bool = False) -> str:
62+
def create_header(
63+
self, tables: List[Dict], schema: bool = False, *args, **kwargs
64+
) -> str:
6365
"""header of the file - imports & gino init"""
6466
header = ""
6567
if "func" in self.state:

‎omymodels/models/sqlalchemy/core.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ def generate_model(
6464
model = logic.add_table_args(self, model, table, schema_global)
6565
return model
6666

67-
def create_header(self, tables: List[Dict], schema: bool = False) -> str:
67+
def create_header(
68+
self, tables: List[Dict], schema: bool = False, *args, **kwargs
69+
) -> str:
6870
"""header of the file - imports & sqlalchemy init"""
6971
header = ""
7072
if "func" in self.state:

‎omymodels/models/sqlalchemy_core/core.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,9 @@ def generate_model(self, data: Dict, *args, **kwargs) -> str:
234234
model += index
235235
return model
236236

237-
def create_header(self, tables: List[Dict], schema: bool = False) -> str:
237+
def create_header(
238+
self, tables: List[Dict], schema: bool = False, *args, **kwargs
239+
) -> str:
238240
"""header of the file - imports & sqlalchemy init"""
239241
header = ""
240242
if "func" in self.state:

‎omymodels/models/sqlmodel/core.py

+15-11
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ def generate_model(
119119
**kwargs,
120120
) -> str:
121121
"""method to prepare one Model defention - name & tablename & columns"""
122-
model = ""
123122

124123
model = st.model_template.format(
125124
model_name=create_class_name(table.name, singular, exceptions),
@@ -133,26 +132,31 @@ def generate_model(
133132
col_str = st.column_template.format(
134133
column_name=column.name.replace(" ", "_"), column_type=pydantic_type_str
135134
)
136-
137-
col_str = logic.setup_column_attributes(
138-
column, table.primary_key, col_str, table, schema_global, st, self
135+
attrs_col_str = logic.setup_column_attributes(
136+
column, table.primary_key, "", table, schema_global, st, self
139137
)
140138
if column_type["sa"]:
141139
sa_type = types.add_size_to_orm_column(column_type["sa"], column)
142-
col_str += st.sa_type.format(satype=sa_type)
143-
col_str += ")\n"
144-
145-
col_str = col_str.replace("(, ", "(")
146-
140+
attrs_col_str += st.sa_type.format(satype=sa_type)
141+
if attrs_col_str:
142+
attrs_col_str = attrs_col_str.replace(",", "", 1).strip()
143+
col_str += st.field_template.format(attr_data=attrs_col_str)
144+
col_str += "\n"
147145
model += col_str
148146
if table.indexes or table.alter or table.checks or not schema_global:
149147
model = self.add_table_args(model, table, schema_global)
150148
return model
151149

152-
def create_header(self, tables: List[Dict], schema: bool = False) -> str:
150+
def create_header(
151+
self,
152+
tables: List[Dict],
153+
models_str: str,
154+
schema: bool = False,
155+
) -> str:
153156
"""header of the file - imports & sqlalchemy init"""
154157
header = ""
155-
header += st.sqlalchemy_import # Do we always need this import?
158+
if "sa." in models_str:
159+
header += st.sqlalchemy_import # Do we always need this import?
156160
if "func" in self.state:
157161
header += st.sql_alchemy_func_import + "\n"
158162
if self.postgresql_dialect_cols:

‎omymodels/models/sqlmodel/sqlmodel.jinja2

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,4 @@ import datetime
22
import decimal
33
from typing import Optional
44
from sqlmodel import Field, SQLModel
5-
6-
{{ headers }}
7-
{{ models }}
5+
{{ headers }}{{ models }}

‎omymodels/models/sqlmodel/templates.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ class {model_name}(SQLModel, table=True):\n
1717
"""
1818

1919
# columns defenition
20-
column_template = """ {column_name}: {column_type} = Field("""
20+
column_template = """ {column_name}: {column_type}"""
21+
field_template = """ = Field({attr_data})"""
2122
required = ""
2223
default = ", sa_column_kwargs={{'server_default': {default}}}"
2324
pk_template = ", default=None, primary_key=True"

‎omymodels/types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"str",
99
"varchar",
1010
"character",
11-
"character_vying",
11+
"character varying",
1212
"varying",
1313
"char",
1414
"string",

‎one.ddl

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CREATE TABLE `option` (
2+
FIELD1 VARCHAR(256),
3+
) ;

‎pyproject.toml

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "omymodels"
3-
version = "0.15.1"
3+
version = "0.16.0"
44
description = "O! My Models (omymodels) is a library to generate Python Models for SQLAlchemy (ORM & Core), GinoORM, Pydantic, Pydal tables & Python Dataclasses from SQL DDL. And convert one models to another."
55
authors = ["Iuliia Volkova <xnuinside@gmail.com>"]
66
license = "MIT"
@@ -32,14 +32,10 @@ table-meta = "^0.1.5"
3232

3333
[tool.poetry.dev-dependencies]
3434
pytest = "^7.4"
35-
m2r = "^0.3.1"
3635

3736
[tool.poetry.scripts]
3837
omm = 'omymodels.cli:main'
3938

40-
[tool.poetry.group.dev.dependencies]
41-
twine = "^4.0.2"
42-
4339
[build-system]
4440
requires = ["poetry-core>=1.0.0"]
4541
build-backend = "poetry.core.masonry.api"

‎tests/functional/generator/test_sqlmodel.py

+51-43
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@ def test_with_enums():
66
import decimal
77
from typing import Optional
88
from sqlmodel import Field, SQLModel
9-
109
from enum import Enum
1110
import sqlalchemy as sa
1211
from sqlalchemy.sql import func
1312
from sqlalchemy.dialects.postgresql import JSON
1413
from pydantic import Json, UUID4
1514
1615
17-
1816
class MaterialType(str, Enum):
1917
2018
article = 'article'
@@ -26,13 +24,13 @@ class Material(SQLModel, table=True):
2624
__tablename__ = 'material'
2725
2826
id: Optional[int] = Field(default=None, primary_key=True)
29-
title: str = Field()
27+
title: str
3028
description: Optional[str] = Field(sa_type=sa.Text())
31-
link: str = Field()
29+
link: str
3230
type: Optional[MaterialType] = Field(sa_type=sa.Enum(MaterialType))
3331
additional_properties: Optional[Json] = Field(sa_column_kwargs={'server_default': '{"key": "value"}'}, sa_type=JSON())
3432
created_at: Optional[datetime.datetime] = Field(sa_column_kwargs={'server_default': func.now()})
35-
updated_at: Optional[datetime.datetime] = Field()
33+
updated_at: Optional[datetime.datetime]
3634
""" # noqa: E501
3735
ddl = """
3836
CREATE TYPE "material_type" AS ENUM (
@@ -61,20 +59,17 @@ def test_foreign_keys():
6159
from typing import Optional
6260
from sqlmodel import Field, SQLModel
6361
64-
import sqlalchemy as sa
65-
66-
6762
6863
class Materials(SQLModel, table=True):
6964
7065
__tablename__ = 'materials'
7166
7267
id: Optional[int] = Field(default=None, primary_key=True)
73-
title: str = Field()
74-
description: Optional[str] = Field()
75-
link: Optional[str] = Field()
76-
created_at: Optional[datetime.datetime] = Field()
77-
updated_at: Optional[datetime.datetime] = Field()
68+
title: str
69+
description: Optional[str]
70+
link: Optional[str]
71+
created_at: Optional[datetime.datetime]
72+
updated_at: Optional[datetime.datetime]
7873
7974
8075
class MaterialAttachments(SQLModel, table=True):
@@ -90,10 +85,10 @@ class Attachments(SQLModel, table=True):
9085
__tablename__ = 'attachments'
9186
9287
id: Optional[int] = Field(default=None, primary_key=True)
93-
title: Optional[str] = Field()
94-
description: Optional[str] = Field()
95-
created_at: Optional[datetime.datetime] = Field()
96-
updated_at: Optional[datetime.datetime] = Field()
88+
title: Optional[str]
89+
description: Optional[str]
90+
created_at: Optional[datetime.datetime]
91+
updated_at: Optional[datetime.datetime]
9792
"""
9893
ddl = """
9994
@@ -139,20 +134,17 @@ def test_foreign_keys_defined_inline():
139134
from typing import Optional
140135
from sqlmodel import Field, SQLModel
141136
142-
import sqlalchemy as sa
143-
144-
145137
146138
class Materials(SQLModel, table=True):
147139
148140
__tablename__ = 'materials'
149141
150142
id: Optional[int] = Field(default=None, primary_key=True)
151-
title: str = Field()
152-
description: Optional[str] = Field()
153-
link: Optional[str] = Field()
154-
created_at: Optional[datetime.datetime] = Field()
155-
updated_at: Optional[datetime.datetime] = Field()
143+
title: str
144+
description: Optional[str]
145+
link: Optional[str]
146+
created_at: Optional[datetime.datetime]
147+
updated_at: Optional[datetime.datetime]
156148
157149
158150
class MaterialAttachments(SQLModel, table=True):
@@ -168,10 +160,10 @@ class Attachments(SQLModel, table=True):
168160
__tablename__ = 'attachments'
169161
170162
id: Optional[int] = Field(default=None, primary_key=True)
171-
title: Optional[str] = Field()
172-
description: Optional[str] = Field()
173-
created_at: Optional[datetime.datetime] = Field()
174-
updated_at: Optional[datetime.datetime] = Field()
163+
title: Optional[str]
164+
description: Optional[str]
165+
created_at: Optional[datetime.datetime]
166+
updated_at: Optional[datetime.datetime]
175167
"""
176168
ddl = """
177169
@@ -212,20 +204,17 @@ def test_multi_col_pk_and_fk():
212204
import decimal
213205
from typing import Optional
214206
from sqlmodel import Field, SQLModel
215-
216-
import sqlalchemy as sa
217207
from sqlalchemy.sql import func
218208
219209
220-
221210
class Complexpk(SQLModel, table=True):
222211
223212
__tablename__ = 'complexpk'
224213
225214
complex_id: Optional[int] = Field(default=None, primary_key=True)
226215
date_part: Optional[datetime.datetime] = Field(sa_column_kwargs={'server_default': func.now()}, default=None, primary_key=True)
227-
title: str = Field()
228-
description: Optional[str] = Field()
216+
title: str
217+
description: Optional[str]
229218
230219
231220
class LinkedTo(SQLModel, table=True):
@@ -235,7 +224,7 @@ class LinkedTo(SQLModel, table=True):
235224
id: Optional[int] = Field(default=None, primary_key=True)
236225
complexpk_complex_id: Optional[int] = Field(foreign_key='complexpk.complex_id')
237226
complexpk_date_part: Optional[int] = Field(foreign_key='complexpk.date_part')
238-
comment: Optional[str] = Field()
227+
comment: Optional[str]
239228
""" # noqa: E501
240229

241230
ddl = """
@@ -267,15 +256,13 @@ def test_upper_name_produces_the_same_result():
267256
import decimal
268257
from typing import Optional
269258
from sqlmodel import Field, SQLModel
270-
271259
from enum import Enum
272260
import sqlalchemy as sa
273261
from sqlalchemy.sql import func
274262
from sqlalchemy.dialects.postgresql import JSON
275263
from pydantic import Json, UUID4
276264
277265
278-
279266
class MaterialType(str, Enum):
280267
281268
article = 'article'
@@ -287,13 +274,13 @@ class Material(SQLModel, table=True):
287274
__tablename__ = 'material'
288275
289276
id: Optional[int] = Field(default=None, primary_key=True)
290-
title: str = Field()
277+
title: str
291278
description: Optional[str] = Field(sa_type=sa.Text())
292-
link: str = Field()
279+
link: str
293280
type: Optional[MaterialType] = Field(sa_type=sa.Enum(MaterialType))
294281
additional_properties: Optional[Json] = Field(sa_column_kwargs={'server_default': '{"key": "value"}'}, sa_type=JSON())
295282
created_at: Optional[datetime.datetime] = Field(sa_column_kwargs={'server_default': func.now()})
296-
updated_at: Optional[datetime.datetime] = Field()
283+
updated_at: Optional[datetime.datetime]
297284
""" # noqa: E501
298285
ddl = """
299286
CREATE TYPE "material_type" AS ENUM (
@@ -322,9 +309,6 @@ def test_foreign_keys_in_different_schema():
322309
from typing import Optional
323310
from sqlmodel import Field, SQLModel
324311
325-
import sqlalchemy as sa
326-
327-
328312
329313
class Table1(SQLModel, table=True):
330314
@@ -371,3 +355,27 @@ class Table2(SQLModel, table=True):
371355
"""
372356
result = create_models(ddl, schema_global=False, models_type="sqlmodel")["code"]
373357
assert result == expected
358+
359+
360+
def test_sqlmodel_varying():
361+
ddl = """
362+
CREATE TABLE qwe (
363+
id integer NOT NULL,
364+
name character varying(255),
365+
);
366+
"""
367+
result = create_models(ddl, models_type="sqlmodel")["code"]
368+
expected = """import datetime
369+
import decimal
370+
from typing import Optional
371+
from sqlmodel import Field, SQLModel
372+
373+
374+
class Qwe(SQLModel, table=True):
375+
376+
__tablename__ = 'qwe'
377+
378+
id: int
379+
name: Optional[str]
380+
"""
381+
assert expected == result

0 commit comments

Comments
 (0)
Please sign in to comment.