Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 18 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,36 +38,32 @@ jobs:
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/poetry.lock') }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/uv.lock') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install and configure Poetry
run: |
pip install -U pip
pip install "poetry>=2.0"
poetry env use python${{ matrix.python-version }}
- uses: astral-sh/setup-uv@v6
- name: Install dependencies and check style
run: poetry run make check
run: uv run make check
- name: Install TortoiseORM v0.21
if: matrix.tortoise-orm == 'tortoise021'
run: poetry run pip install --upgrade "tortoise-orm>=0.21,<0.22"
run: uv pip install --upgrade "tortoise-orm>=0.21,<0.22"
- name: Install TortoiseORM v0.22
if: matrix.tortoise-orm == 'tortoise022'
run: poetry run pip install --upgrade "tortoise-orm>=0.22,<0.23"
run: uv pip install --upgrade "tortoise-orm>=0.22,<0.23"
- name: Install TortoiseORM v0.23
if: matrix.tortoise-orm == 'tortoise023'
run: poetry run pip install --upgrade "tortoise-orm>=0.23,<0.24"
run: uv pip install --upgrade "tortoise-orm>=0.23,<0.24"
- name: Install TortoiseORM v0.24
if: matrix.tortoise-orm == 'tortoise024'
run: poetry run pip install --upgrade "tortoise-orm>=0.24,<0.25"
run: uv pip install --upgrade "tortoise-orm>=0.24,<0.25"
- name: Install TortoiseORM v0.25
if: matrix.tortoise-orm == 'tortoise025'
run: poetry run pip install --upgrade "tortoise-orm>=0.25,<0.26"
run: uv pip install --upgrade "tortoise-orm>=0.25,<0.26"
- name: Install TortoiseORM develop branch
if: matrix.tortoise-orm == 'tortoisedev'
run: |
poetry run pip uninstall -y tortoise-orm
poetry run pip install --upgrade "git+https://github.com/tortoise/tortoise-orm"
uv pip uninstall tortoise-orm
uv pip install --upgrade "git+https://github.com/tortoise/tortoise-orm"
- name: CI
env:
MYSQL_PASS: root
Expand All @@ -76,22 +72,24 @@ jobs:
POSTGRES_PASS: 123456
POSTGRES_HOST: 127.0.0.1
POSTGRES_PORT: 5432
run: poetry run make _testall
run: uv run make _testall
- name: Verify aiomysql support
# Only check the latest version of tortoise
if: matrix.tortoise-orm == 'tortoisedev'
run: |
poetry run pip uninstall -y asyncmy
poetry run make test_mysql
poetry run pip install asyncmy
uv pip uninstall asyncmy
uv run make test_mysql
uv pip install asyncmy
env:
MYSQL_PASS: root
MYSQL_HOST: 127.0.0.1
MYSQL_PORT: 3306
- name: Verify psycopg support
- name: Verify psycopg/tortoise-vector support
# Only check the latest version of tortoise
if: matrix.tortoise-orm == 'tortoisedev'
run: poetry run make test_psycopg
run: |
uv run make test_psycopg
uv run make test_postgres_vector
env:
POSTGRES_PASS: 123456
POSTGRES_HOST: 127.0.0.1
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install and configure Poetry
run: |
pip install -U pip poetry
poetry config virtualenvs.create false
- uses: astral-sh/setup-uv@v6
- name: Build dists
run: make build
- name: Pypi Publish
Expand Down
33 changes: 18 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,29 @@ POSTGRES_PORT ?= 5432
POSTGRES_PASS ?= 123456

up:
@poetry update
@uv lock --upgrade

deps:
@poetry install --all-extras --all-groups
@uv sync --all-extras --all-groups $(options)

_style:
@ruff check --fix $(checkfiles)
@ruff format $(checkfiles)
@ruff check --fix $(checkfiles)
style: deps _style

_check:
@ruff format --check $(checkfiles) || (echo "Please run 'make style' to auto-fix style issues" && false)
@ruff check $(checkfiles)
@mypy $(checkfiles)
@bandit -r aerich
@twine check dist/*
check: build _check

_lint: _build
ruff format $(checkfiles)
ruff check --fix $(checkfiles)
_codeqc:
mypy $(checkfiles)
bandit -c pyproject.toml -r $(checkfiles)
twine check dist/*
codeqc: build _codeqc

_check: _build
@ruff format --check $(checkfiles) || (echo "Please run 'make style' to auto-fix style issues" && false)
@ruff check $(checkfiles)
$(MAKE) _codeqc
check: deps _check

_lint: _build _style _codeqc
lint: deps _lint

test: deps
Expand All @@ -46,14 +45,18 @@ test_mysql:
test_postgres:
$(py_warn) TEST_DB="postgres://postgres:$(POSTGRES_PASS)@$(POSTGRES_HOST):$(POSTGRES_PORT)/test_\{\}" pytest -vv -s

test_postgres_vector:
$(py_warn) AERICH_TEST_VECTOR=1 TEST_DB="postgres://postgres:$(POSTGRES_PASS)@$(POSTGRES_HOST):$(POSTGRES_PORT)/test_\{\}" pytest -vv -s tests/test_inspectdb.py::test_inspect_vector

test_psycopg:
$(py_warn) TEST_DB="psycopg://postgres:$(POSTGRES_PASS)@$(POSTGRES_HOST):$(POSTGRES_PORT)/test_\{\}" pytest -vv -s

_testall: test_sqlite test_postgres test_mysql
testall: deps _testall

_build:
poetry build --clean
rm -fR dist/
uv build
build: deps _build

ci: build _check _testall
Empty file added aerich/py.typed
Empty file.
29 changes: 17 additions & 12 deletions aerich/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from importlib.machinery import FileFinder
from pathlib import Path
from types import ModuleType
from typing import Any, TypeVar
from typing import Any, TypeVar, cast

from anyio import from_thread
from asyncclick import BadOptionUsage, ClickException, Context
Expand Down Expand Up @@ -45,19 +45,19 @@ def add_src_path(path: str) -> str:
return path


def get_app_connection_name(config: dict, app_name: str) -> str:
def get_app_connection_name(config: dict[str, dict[str, Any]], app_name: str) -> str:
"""
get connection name
:param config:
:param app_name:
:return: the default connection name (Usally it is 'default')
"""
if app := config["apps"].get(app_name):
return app.get("default_connection", "default")
return cast(str, app.get("default_connection", "default"))
raise BadOptionUsage(option_name="--app", message=f"Can't get app named {app_name!r}")


def get_app_connection(config: dict, app: str) -> BaseDBAsyncClient:
def get_app_connection(config: dict[str, Any], app: str) -> BaseDBAsyncClient:
"""
get connection client
:param config:
Expand All @@ -67,7 +67,7 @@ def get_app_connection(config: dict, app: str) -> BaseDBAsyncClient:
return Tortoise.get_connection(get_app_connection_name(config, app))


def get_tortoise_config(ctx: Context, tortoise_orm: str) -> dict:
def get_tortoise_config(ctx: Context, tortoise_orm: str) -> dict[str, Any]:
"""
get tortoise config from module
:param ctx:
Expand Down Expand Up @@ -99,16 +99,16 @@ def get_tortoise_config(ctx: Context, tortoise_orm: str) -> dict:
message=f'Can\'t get "{tortoise_config}" from module "{config_module}"',
ctx=ctx,
)
return config
return cast(dict[str, Any], config)


def get_models_describe(app: str) -> dict:
def get_models_describe(app: str) -> dict[str, dict[str, Any]]:
"""
get app models describe
:param app:
:return:
"""
ret = {}
ret: dict[str, dict[str, Any]] = {}
try:
app_config = Tortoise.apps[app]
except KeyError as e:
Expand All @@ -119,11 +119,16 @@ def get_models_describe(app: str) -> dict:
for model in app_config.values():
managed = getattr(model.Meta, "managed", None)
describe = model.describe()
ret[describe.get("name")] = dict(describe, managed=managed)
try:
qualified_model_name = describe["name"]
except KeyError:
continue
else:
ret[qualified_model_name] = dict(describe, managed=managed)
return ret


def is_default_function(string: Any) -> re.Match | None:
def is_default_function(string: Any) -> re.Match[str] | None:
return re.match(r"^<function.+>$", str(string or ""))


Expand Down Expand Up @@ -167,8 +172,8 @@ def py_module_path(module_info: pkgutil.ModuleInfo) -> Path:


def get_dict_diff_by_key(
old_fields: list[dict], new_fields: list[dict], key="through"
) -> Generator[tuple]:
old_fields: list[dict[str, str]], new_fields: list[dict[str, str]], key: str = "through"
) -> Generator[tuple[str, Any, Any]]:
"""
Compare two list by key instead of by index

Expand Down
4 changes: 1 addition & 3 deletions aerich/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
from importlib.metadata import version

__version__ = version(__package__)
__version__ = "0.9.1"
63 changes: 38 additions & 25 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
[project]
name = "aerich"
version = "0.9.1"
dynamic = ["version"]
description = "A database migrations tool for Tortoise ORM."
authors = [{name="long2ice", email="long2ice@gmail.com>"}]
license = { text = "Apache-2.0" }
license = "Apache-2.0"
readme = "README.md"
keywords = ["migrate", "Tortoise-ORM", "mysql"]
packages = [{ include = "aerich" }]
include = ["CHANGELOG.md", "LICENSE", "README.md"]
requires-python = ">=3.9"
dependencies = [
"tortoise-orm (>=0.21.0,<1.0.0)",
"dictdiffer (>=0.9.0,<1.0.0)",
"asyncclick (>=8.1.7,<9.0.0)",
"anyio (>=3.6.2,<5.0.0)",
]

[project.optional-dependencies]
Expand All @@ -24,7 +23,7 @@ toml = [
asyncpg = ["asyncpg"]
psycopg = ["psycopg[pool,binary] (>=3.0.12,<4.0.0)"]
# Need asyncmy or aiomysql for MySQL
asyncmy = ["asyncmy>=0.2.9; python_version < '4.0'"]
asyncmy = ["asyncmy>=0.2.9"]
mysql = ["aiomysql>=0.2.0"]

[project.urls]
Expand All @@ -37,34 +36,48 @@ aerich = "aerich.cli:main"

[tool.poetry]
requires-poetry = ">=2.0"
packages = [{ include = "aerich" }]
version = "0.0.0"

[dependency-groups]
dev = [
"ruff >=0.9.0",
"bandit >=1.7.0",
"mypy >=1.10.0",
"twine >=6.1.0",
]
test = [
"pytest >=8.3.0",
"pytest-mock >=3.14.0",
"pytest-xdist >=3.6.0",

# Breaking change in 0.23.*
# https://github.com/pytest-dev/pytest-asyncio/issues/706
"pytest-asyncio >=0.21.2,<0.23",

[tool.poetry.group.dev.dependencies]
ruff = "^0.9.0"
bandit = "^1.7.0"
mypy = "^1.10.0"
twine = "^6.1.0"

[tool.poetry.group.test.dependencies]
pytest = "^8.3.0"
pytest-mock = "^3.14.0"
pytest-xdist = "^3.6.0"
# Breaking change in 0.23.*
# https://github.com/pytest-dev/pytest-asyncio/issues/706
pytest-asyncio = "^0.21.2"
# required for sha256_password by asyncmy
cryptography = {version="*", python=">3.9.0,<3.9.1 || >3.9.1"}
tortoise-vector = {version="^0.1.4", python=">=3.11,<4.0"}
async-timeout = {version="^5.0.1", python="<3.11"}
pydantic-settings = "^2.10.1"
# required for sha256_password by asyncmy
"cryptography; python_version >='3.9.0,!=3.9.1'",

"tortoise-vector >=0.1.4; python_version >='3.11'",
"async-timeout >=5.0.1; python_version <'3.11'",
"pydantic-settings >=2.10.1",
]

[tool.aerich]
tortoise_orm = "conftest.tortoise_orm"
location = "./migrations"
src_folder = "./."

[build-system]
requires = ["poetry-core>=2.0.0"]
build-backend = "poetry.core.masonry.api"
requires = ["pdm-backend"]
build-backend = "pdm.backend"

[tool.pdm]
version = {source="file", path="aerich/version.py"}

[tool.pdm.build]
excludes = ["./**/.git", "./**/.*_cache"]
include = ["CHANGELOG.md", "LICENSE", "README.md"]

[tool.pytest.ini_options]
asyncio_mode = 'auto'
Expand Down
4 changes: 4 additions & 0 deletions tests/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ def requires_dialect(

@contextlib.contextmanager
def tmp_daily_db(env_name="AERICH_DONT_DROP_TMP_DB") -> Generator[None]:
me = Path(__file__)
if not me.is_relative_to(Path.cwd()):
shutil.copy(me, ".")
run_in_subprocess("python db.py drop")
ok, out = run_in_subprocess("python db.py create")
if not ok:
raise OperationalError(out)
Expand Down
3 changes: 1 addition & 2 deletions tests/assets/postgres_vector/db.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import asyncclick as click
from _utils import drop_db, init_db
from settings import TORTOISE_ORM

from tests._utils import drop_db, init_db


@click.group()
def cli(): ...
Expand Down
5 changes: 4 additions & 1 deletion tests/assets/remove_constraint/db.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import asyncclick as click
from settings import TORTOISE_ORM

from tests._utils import drop_db, init_db
try:
from _utils import drop_db, init_db
except ImportError:
from tests._utils import drop_db, init_db


@click.group()
Expand Down
5 changes: 5 additions & 0 deletions tests/test_inspectdb.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import sys
from pathlib import Path

Expand Down Expand Up @@ -35,6 +36,10 @@ def test_inspect(new_aerich_project):

@requires_dialect("postgres")
@test.skipIf(sys.version_info < (3, 11), "tortoise-vector requires python>=3.11")
@test.skipIf(
not (_v := os.getenv("AERICH_TEST_VECTOR")) or _v.lower() not in ("1", "on", "yes", "true"),
"Skip as os env 'AERICH_TEST_VECTOR' is not true",
)
def test_inspect_vector(tmp_work_dir: Path):
prepare_py_files("postgres_vector", suffix=".*")
with tmp_daily_db():
Expand Down
Loading