Skip to content

Commit 0364ae3

Browse files
authored
feat: add project section (#424)
* refactor: apply future style type hints * chore: use project section * ci: upgrade to poetry v2 * ci: explicit declare python version for poetry * fix error for generate index name * fix _generate_fk_name * ci: verify aiomysql support * tests: poetry add * Add patch to fix tortoise 0.24.1 * docs: update changelog
1 parent 91adf93 commit 0364ae3

File tree

9 files changed

+442
-101
lines changed

9 files changed

+442
-101
lines changed

.github/workflows/ci.yml

+22-4
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,16 @@ jobs:
4343
${{ runner.os }}-pip-
4444
- name: Install and configure Poetry
4545
run: |
46-
pip install -U pip poetry
47-
poetry config virtualenvs.create false
46+
pip install -U pip
47+
if [[ "${{ matrix.python-version }}" == "3.8" ]]; then
48+
# poetry2.0+ does not support installed by python3.8, but can manage project using py38
49+
python3.12 -m pip install "poetry>=2.0"
50+
else
51+
pip install "poetry>=2.0"
52+
fi
53+
poetry env use python${{ matrix.python-version }}
4854
- name: Install dependencies and check style
49-
run: make check
55+
run: poetry run make check
5056
- name: Install TortoiseORM v0.21
5157
if: matrix.tortoise-orm == 'tortoise021'
5258
run: poetry run pip install --upgrade "tortoise-orm>=0.21,<0.22"
@@ -81,4 +87,16 @@ jobs:
8187
POSTGRES_PASS: 123456
8288
POSTGRES_HOST: 127.0.0.1
8389
POSTGRES_PORT: 5432
84-
run: make _testall
90+
run: poetry run make _testall
91+
- name: Verify aiomysql support
92+
if: matrix.tortoise-orm == 'tortoise024'
93+
run: |
94+
poetry run pip uninstall -y asyncmy
95+
poetry run pip install aiomysql
96+
poetry run make test_mysql
97+
poetry run pip uninstall -y aiomysql
98+
poetry run pip install asyncmy
99+
env:
100+
MYSQL_PASS: root
101+
MYSQL_HOST: 127.0.0.1
102+
MYSQL_PORT: 3306

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- feat: support command `python -m aerich`. ([#417])
99
- feat: add --fake to upgrade/downgrade. ([#398])
1010
- Support ignore table by settings `managed=False` in `Meta` class. ([#397])
11+
- Support run `poetry add aerich` in project that inited by poetry v2. ([#424])
1112

1213
#### Fixed
1314
- fix: aerich migrate raises tortoise.exceptions.FieldError when `index.INDEX_TYPE` is not empty. ([#415])
@@ -25,6 +26,7 @@
2526
[#412]: https://github.com/tortoise/aerich/pull/412
2627
[#415]: https://github.com/tortoise/aerich/pull/415
2728
[#417]: https://github.com/tortoise/aerich/pull/417
29+
[#424]: https://github.com/tortoise/aerich/pull/424
2830

2931
### [0.8.1](../../releases/tag/v0.8.1) - 2024-12-27
3032

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ up:
1111
@poetry update
1212

1313
deps:
14-
@poetry install -E asyncpg -E asyncmy -E toml
14+
@poetry install --all-extras --all-groups
1515

1616
_style:
1717
@ruff check --fix $(checkfiles)

aerich/__init__.py

+86
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from pathlib import Path
66
from typing import TYPE_CHECKING
77

8+
import tortoise
89
from tortoise import Tortoise, generate_schema_for_client
910
from tortoise.exceptions import OperationalError
1011
from tortoise.transactions import in_transaction
@@ -24,6 +25,9 @@
2425
)
2526

2627
if TYPE_CHECKING:
28+
from tortoise import Model
29+
from tortoise.fields.relational import ManyToManyFieldInstance # NOQA:F401
30+
2731
from aerich.inspectdb import Inspect
2832

2933

@@ -47,7 +51,89 @@ def _init_asyncio_patch():
4751
set_event_loop_policy(WindowsSelectorEventLoopPolicy())
4852

4953

54+
def _init_tortoise_0_24_1_patch():
55+
# this patch is for "tortoise-orm==0.24.1" to fix:
56+
# https://github.com/tortoise/tortoise-orm/issues/1893
57+
if tortoise.__version__ != "0.24.1":
58+
return
59+
from tortoise.backends.base.schema_generator import BaseSchemaGenerator, cast, re
60+
61+
def _get_m2m_tables(
62+
self, model: type[Model], table_name: str, safe: bool, models_tables: list[str]
63+
) -> list[str]:
64+
m2m_tables_for_create = []
65+
db_table = table_name
66+
for m2m_field in model._meta.m2m_fields:
67+
field_object = cast("ManyToManyFieldInstance", model._meta.fields_map[m2m_field])
68+
if field_object._generated or field_object.through in models_tables:
69+
continue
70+
backward_key, forward_key = field_object.backward_key, field_object.forward_key
71+
if field_object.db_constraint:
72+
backward_fk = self._create_fk_string(
73+
"",
74+
backward_key,
75+
db_table,
76+
model._meta.db_pk_column,
77+
field_object.on_delete,
78+
"",
79+
)
80+
forward_fk = self._create_fk_string(
81+
"",
82+
forward_key,
83+
field_object.related_model._meta.db_table,
84+
field_object.related_model._meta.db_pk_column,
85+
field_object.on_delete,
86+
"",
87+
)
88+
else:
89+
backward_fk = forward_fk = ""
90+
exists = "IF NOT EXISTS " if safe else ""
91+
table_name = field_object.through
92+
backward_type = self._get_pk_field_sql_type(model._meta.pk)
93+
forward_type = self._get_pk_field_sql_type(field_object.related_model._meta.pk)
94+
comment = ""
95+
if desc := field_object.description:
96+
comment = self._table_comment_generator(table=table_name, comment=desc)
97+
m2m_create_string = self.M2M_TABLE_TEMPLATE.format(
98+
exists=exists,
99+
table_name=table_name,
100+
backward_fk=backward_fk,
101+
forward_fk=forward_fk,
102+
backward_key=backward_key,
103+
backward_type=backward_type,
104+
forward_key=forward_key,
105+
forward_type=forward_type,
106+
extra=self._table_generate_extra(table=field_object.through),
107+
comment=comment,
108+
)
109+
if not field_object.db_constraint:
110+
m2m_create_string = m2m_create_string.replace(
111+
""",
112+
,
113+
""",
114+
"",
115+
) # may have better way
116+
m2m_create_string += self._post_table_hook()
117+
if field_object.create_unique_index:
118+
unique_index_create_sql = self._get_unique_index_sql(
119+
exists, table_name, [backward_key, forward_key]
120+
)
121+
if unique_index_create_sql.endswith(";"):
122+
m2m_create_string += "\n" + unique_index_create_sql
123+
else:
124+
lines = m2m_create_string.splitlines()
125+
lines[-2] += ","
126+
indent = m.group() if (m := re.match(r"\s+", lines[-2])) else ""
127+
lines.insert(-1, indent + unique_index_create_sql)
128+
m2m_create_string = "\n".join(lines)
129+
m2m_tables_for_create.append(m2m_create_string)
130+
return m2m_tables_for_create
131+
132+
BaseSchemaGenerator._get_m2m_tables = _get_m2m_tables
133+
134+
50135
_init_asyncio_patch()
136+
_init_tortoise_0_24_1_patch()
51137

52138

53139
class Command:

aerich/ddl/__init__.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,11 @@ def change_column(
182182
)
183183

184184
def _index_name(self, unique: bool | None, model: type[Model], field_names: list[str]) -> str:
185-
return self.schema_generator._generate_index_name(
185+
func_name = "_get_index_name"
186+
if not hasattr(self.schema_generator, func_name):
187+
# For tortoise-orm<0.24.1
188+
func_name = "_generate_index_name"
189+
return getattr(self.schema_generator, func_name)(
186190
"idx" if not unique else "uid", model, field_names
187191
)
188192

@@ -227,7 +231,11 @@ def _generate_fk_name(
227231
pk_field = cast(dict, reference_table_describe.get("pk_field"))
228232
to_field = cast(str, pk_field.get("db_column"))
229233
to_table = cast(str, reference_table_describe.get("table"))
230-
return self.schema_generator._generate_fk_name(
234+
func_name = "_get_fk_name"
235+
if not hasattr(self.schema_generator, func_name):
236+
# For tortoise-orm<0.24.1
237+
func_name = "_generate_fk_name"
238+
return getattr(self.schema_generator, func_name)(
231239
from_table=db_table,
232240
from_field=db_column,
233241
to_table=to_table,

aerich/ddl/mysql/__init__.py

+6-10
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,12 @@ class MysqlDDL(BaseDDL):
4343
_RENAME_TABLE_TEMPLATE = "ALTER TABLE `{old_table_name}` RENAME TO `{new_table_name}`"
4444

4545
def _index_name(self, unique: bool | None, model: type[Model], field_names: list[str]) -> str:
46-
if unique:
47-
if len(field_names) == 1:
48-
# Example: `email = CharField(max_length=50, unique=True)`
49-
# Generate schema: `"email" VARCHAR(10) NOT NULL UNIQUE`
50-
# Unique index key is the same as field name: `email`
51-
return field_names[0]
52-
index_prefix = "uid"
53-
else:
54-
index_prefix = "idx"
55-
return self.schema_generator._generate_index_name(index_prefix, model, field_names)
46+
if unique and len(field_names) == 1:
47+
# Example: `email = CharField(max_length=50, unique=True)`
48+
# Generate schema: `"email" VARCHAR(10) NOT NULL UNIQUE`
49+
# Unique index key is the same as field name: `email`
50+
return field_names[0]
51+
return super()._index_name(unique, model, field_names)
5652

5753
def alter_indexed_column_unique(
5854
self, model: type[Model], field_name: str, drop: bool = False

0 commit comments

Comments
 (0)