Skip to content

Commit 0eac860

Browse files
authored
Create Dynamic classes with create_model instead of class (#484)
This avoids the SAWarning on startup that was caused by temporary name shadowing.
2 parents 185dd9d + 06095bc commit 0eac860

File tree

4 files changed

+76
-44
lines changed

4 files changed

+76
-44
lines changed

src/database/model/ai_asset/distribution.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import datetime
22
from typing import Type
33

4+
from pydantic import create_model
45
from sqlalchemy import Column, Integer, ForeignKey
56
from sqlmodel import Field
67

@@ -52,16 +53,23 @@ class DistributionBase(AIoDConceptBase):
5253

5354

5455
def distribution_factory(table_from: str, distribution_name="distribution") -> Type:
55-
class DistributionORM(DistributionBase, table=True): # type: ignore [call-arg]
56-
__tablename__ = f"{distribution_name}_{table_from}"
57-
58-
identifier: int | None = Field(primary_key=True)
59-
60-
asset_identifier: int | None = Field(
61-
sa_column=Column(Integer, ForeignKey(table_from + ".identifier", ondelete="CASCADE"))
62-
)
63-
64-
DistributionORM.__name__ = DistributionORM.__qualname__ = f"{distribution_name}_{table_from}"
56+
name = f"{distribution_name}_{table_from}"
57+
DistributionORM = create_model(
58+
name,
59+
__base__=(DistributionBase,),
60+
__cls_kwargs__=dict(table=True),
61+
identifier=(int | None, Field(primary_key=True)),
62+
asset_identifier=(
63+
int | None,
64+
Field(
65+
sa_column=Column(
66+
Integer, ForeignKey(table_from + ".identifier", ondelete="CASCADE")
67+
)
68+
),
69+
),
70+
)
71+
# Pydantic will issue a warning for non-default dunder attributes, so we add it after creation
72+
DistributionORM.__tablename__ = name
6573
return DistributionORM
6674

6775

src/database/model/ai_resource/note.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Type
22

3+
from pydantic import create_model
34
from sqlalchemy import Column, Integer, ForeignKey
45
from sqlmodel import Field, SQLModel
56

@@ -17,15 +18,22 @@ class NoteBase(SQLModel):
1718

1819

1920
def note_factory(table_from: str) -> Type:
20-
class NoteORM(NoteBase, table=True): # type: ignore [call-arg]
21-
__tablename__ = f"note_{table_from}"
22-
23-
identifier: int | None = Field(primary_key=True)
24-
linked_identifier: int | None = Field(
25-
sa_column=Column(Integer, ForeignKey(table_from + ".identifier", ondelete="CASCADE"))
26-
)
27-
28-
NoteORM.__name__ = NoteORM.__qualname__ = f"note_{table_from}"
21+
NoteORM = create_model(
22+
f"note_{table_from}",
23+
__base__=(NoteBase,),
24+
__cls_kwargs__=dict(table=True),
25+
identifier=(int | None, Field(primary_key=True)),
26+
linked_identifier=(
27+
int | None,
28+
Field(
29+
sa_column=Column(
30+
Integer, ForeignKey(table_from + ".identifier", ondelete="CASCADE")
31+
)
32+
),
33+
),
34+
)
35+
# Pydantic will issue a warning for non-default dunder attributes, so we add it after creation
36+
NoteORM.__tablename__ = f"note_{table_from}"
2937
return NoteORM
3038

3139

src/database/model/helper_functions.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Type, TYPE_CHECKING
22

3+
from pydantic import create_model
34
from sqlalchemy import Column, Integer, ForeignKey
45
from sqlmodel import SQLModel, Field
56

@@ -18,21 +19,31 @@ def many_to_many_link_factory(
1819
sides.
1920
"""
2021
prefix = "" if table_prefix is None else f"{table_prefix}_"
21-
22-
class LinkTable(SQLModel, table=True): # type: ignore [call-arg]
23-
__tablename__ = f"{prefix}{table_from}_{table_to}_link"
24-
from_identifier: int = Field(
25-
sa_column=Column(
26-
Integer,
27-
ForeignKey(f"{table_from}.{table_from_identifier}", ondelete="CASCADE"),
22+
name = f"{prefix}{table_from}_{table_to}_link"
23+
LinkTable = create_model(
24+
name,
25+
__base__=(SQLModel,),
26+
__cls_kwargs__=dict(table=True),
27+
from_identifier=(
28+
int,
29+
Field(
30+
sa_column=Column(
31+
Integer,
32+
ForeignKey(f"{table_from}.{table_from_identifier}", ondelete="CASCADE"),
33+
primary_key=True,
34+
)
35+
),
36+
),
37+
linked_identifier=(
38+
int,
39+
Field(
40+
foreign_key=f"{table_to}.{table_to_identifier}",
2841
primary_key=True,
29-
)
30-
)
31-
linked_identifier: int = Field(
32-
foreign_key=f"{table_to}.{table_to_identifier}", primary_key=True
33-
)
34-
35-
LinkTable.__name__ = LinkTable.__qualname__ = LinkTable.__tablename__
42+
),
43+
),
44+
)
45+
# Pydantic will issue a warning for non-default dunder attributes, so we add it after creation
46+
LinkTable.__tablename__ = name
3647
return LinkTable
3748

3849

src/database/model/models_and_experiments/runnable_distribution.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Type
22

3+
from pydantic import create_model
34
from sqlalchemy import Column, Integer, ForeignKey
45
from sqlmodel import Field
56

@@ -75,18 +76,22 @@ class RunnableDistributionBase(DistributionBase):
7576

7677

7778
def runnable_distribution_factory(table_from: str, distribution_name="distribution") -> Type:
78-
class RunnableDistributionORM(RunnableDistributionBase, table=True): # type: ignore [call-arg]
79-
__tablename__ = f"{distribution_name}_{table_from}"
80-
81-
identifier: int | None = Field(primary_key=True)
82-
83-
asset_identifier: int | None = Field(
84-
sa_column=Column(Integer, ForeignKey(table_from + ".identifier", ondelete="CASCADE"))
85-
)
86-
87-
RunnableDistributionORM.__name__ = RunnableDistributionORM.__qualname__ = (
88-
f"{distribution_name}_{table_from}"
79+
RunnableDistributionORM = create_model(
80+
f"{distribution_name}_{table_from}",
81+
__base__=(RunnableDistributionBase,),
82+
__cls_kwargs__=dict(table=True),
83+
identifier=(int | None, Field(primary_key=True)),
84+
asset_identifier=(
85+
int | None,
86+
Field(
87+
sa_column=Column(
88+
Integer, ForeignKey(table_from + ".identifier", ondelete="CASCADE")
89+
)
90+
),
91+
),
8992
)
93+
# Pydantic will issue a warning for non-default dunder attributes, so we add it after creation
94+
RunnableDistributionORM.__tablename__ = f"{distribution_name}_{table_from}"
9095
return RunnableDistributionORM
9196

9297

0 commit comments

Comments
 (0)