9 Commits

Author SHA1 Message Date
long2ice
aa921355b9 Store versions in db 2020-05-21 21:22:06 +08:00
long2ice
ea1191bb10 TODO: store version in db 2020-05-21 18:38:45 +08:00
long2ice
23dd29644c fix dependency import 2020-05-21 13:44:09 +08:00
long2ice
bf1d745cef remove cov 2020-05-20 19:00:03 +08:00
long2ice
f5e5d24855 perfect test 2020-05-20 18:42:13 +08:00
long2ice
6d92aec4b1 add pytest.yml 2020-05-19 17:45:41 +08:00
long2ice
55e78bdd2d update regex 2020-05-19 17:16:21 +08:00
long2ice
b07d1abf49 raise Tortoise ConfigurationError 2020-05-19 16:16:07 +08:00
long2ice
ad9c3c809d update setup.py 2020-05-19 14:01:07 +08:00
29 changed files with 712 additions and 253 deletions

View File

@@ -1,12 +1,10 @@
name: pypi name: pypi
on: on:
release: release:
types: types:
- created - created
jobs: jobs:
build: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

34
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: test
on: [push, pull_request]
jobs:
testall:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:latest
ports:
- 5432:5432
env:
POSTGRES_PASSWORD: 123456
POSTGRES_USER: postgres
options: --health-cmd=pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Start MySQL
run: sudo systemctl start mysql.service
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: CI
env:
MYSQL_PASS: root
MYSQL_HOST: 127.0.0.1
MYSQL_PORT: 3306
POSTGRES_PASS: 123456
POSTGRES_HOST: 127.0.0.1
POSTGRES_PORT: 5432
run: make testall

3
.gitignore vendored
View File

@@ -142,4 +142,5 @@ cython_debug/
.idea .idea
migrations migrations
aerich.ini aerich.ini
src

View File

@@ -4,6 +4,12 @@ ChangeLog
0.1 0.1
=== ===
0.1.5
-----
- Add sqlite and postgres support.
- Fix dependency import.
- Store versions in db.
0.1.4 0.1.4
----- -----
- Fix transaction and fields import. - Fix transaction and fields import.

View File

@@ -1,6 +1,10 @@
checkfiles = aerich/ tests/ checkfiles = aerich/ tests/
black_opts = -l 100 -t py38 black_opts = -l 100 -t py38
py_warn = PYTHONDEVMODE=1 py_warn = PYTHONDEVMODE=1
MYSQL_HOST ?= "127.0.0.1"
MYSQL_PORT ?= 3306
POSTGRES_HOST ?= "127.0.0.1"
POSTGRES_PORT ?= 5432
help: help:
@echo "Aerich development makefile" @echo "Aerich development makefile"
@@ -18,10 +22,6 @@ deps:
@which pip-sync > /dev/null || pip install -q pip-tools @which pip-sync > /dev/null || pip install -q pip-tools
@pip install -r requirements-dev.txt @pip install -r requirements-dev.txt
up:
CUSTOM_COMPILE_COMMAND="make up" pip-compile -o requirements-dev.txt -U
sed -i "s/^-e .*/-e ./" requirements.txt
style: deps style: deps
isort -rc $(checkfiles) isort -rc $(checkfiles)
black $(black_opts) $(checkfiles) black $(black_opts) $(checkfiles)
@@ -36,20 +36,24 @@ endif
bandit -r $(checkfiles) bandit -r $(checkfiles)
python setup.py check -mrs python setup.py check -mrs
lint: deps
ifneq ($(shell which black),)
black --check $(black_opts) $(checkfiles) || (echo "Please run 'make style' to auto-fix style issues" && false)
endif
flake8 $(checkfiles)
mypy $(checkfiles)
pylint $(checkfiles)
bandit -r $(checkfiles)
python setup.py check -mrs
test: deps test: deps
$(py_warn) py.test $(py_warn) TEST_DB=sqlite://:memory: py.test
test_sqlite:
$(py_warn) TEST_DB=sqlite://:memory: py.test
test_mysql:
$(py_warn) TEST_DB="mysql://root:$(MYSQL_PASS)@$(MYSQL_HOST):$(MYSQL_PORT)/test_\{\}" py.test
test_postgres:
$(py_warn) TEST_DB="postgres://postgres:$(POSTGRES_PASS)@$(POSTGRES_HOST):$(POSTGRES_PORT)/test_\{\}" py.test
testall: deps test_sqlite test_postgres test_mysql
publish: deps publish: deps
rm -fR dist/ rm -fR dist/
python setup.py sdist python setup.py sdist
twine upload dist/* twine upload dist/*
ci:
@act -P ubuntu-latest=nektos/act-environments-ubuntu:18.04 -b

View File

@@ -8,6 +8,8 @@ Aerich
:target: https://github.com/long2ice/aerich :target: https://github.com/long2ice/aerich
.. image:: https://github.com/long2ice/aerich/workflows/pypi/badge.svg .. image:: https://github.com/long2ice/aerich/workflows/pypi/badge.svg
:target: https://github.com/long2ice/aerich/actions?query=workflow:pypi :target: https://github.com/long2ice/aerich/actions?query=workflow:pypi
.. image:: https://github.com/long2ice/aerich/workflows/test/badge.svg
:target: https://github.com/long2ice/aerich/actions?query=workflow:test
Introduction Introduction
============ ============
@@ -52,6 +54,19 @@ Quick Start
Usage Usage
===== =====
You need add ``aerich.models`` to your ``Tortoise-ORM`` config first, example:
.. code-block:: python
TORTOISE_ORM = {
"connections": {"default": "mysql://root:123456@127.0.0.1:3306/test"},
"apps": {
"models": {
"models": ["tests.models", "aerich.models"],
"default_connection": "default",
},
},
}
Initialization Initialization
-------------- --------------
@@ -98,7 +113,7 @@ Update models and make migrate
Success migrate 1_202029051520102929_drop_column.json Success migrate 1_202029051520102929_drop_column.json
Format of migrate filename is ``{version}_{datetime}_{name|update}.json`` Format of migrate filename is ``{version_num}_{datetime}_{name|update}.json``
Upgrade to latest version Upgrade to latest version
------------------------- -------------------------

View File

@@ -3,7 +3,7 @@ import os
import sys import sys
from configparser import ConfigParser from configparser import ConfigParser
from enum import Enum from enum import Enum
from . import __version__
import asyncclick as click import asyncclick as click
from asyncclick import Context, UsageError from asyncclick import Context, UsageError
from tortoise import ConfigurationError, Tortoise, generate_schema_for_client from tortoise import ConfigurationError, Tortoise, generate_schema_for_client
@@ -12,6 +12,9 @@ from tortoise.transactions import in_transaction
from aerich.migrate import Migrate from aerich.migrate import Migrate
from aerich.utils import get_app_connection, get_app_connection_name, get_tortoise_config from aerich.utils import get_app_connection, get_app_connection_name, get_tortoise_config
from . import __version__
from .models import Aerich
class Color(str, Enum): class Color(str, Enum):
green = "green" green = "green"
@@ -38,8 +41,10 @@ parser = ConfigParser()
@click.pass_context @click.pass_context
async def cli(ctx: Context, config, app, name): async def cli(ctx: Context, config, app, name):
ctx.ensure_object(dict) ctx.ensure_object(dict)
ctx.obj["config"] = config ctx.obj["config_file"] = config
ctx.obj["name"] = name ctx.obj["name"] = name
ctx.obj["app"] = app
invoked_subcommand = ctx.invoked_subcommand invoked_subcommand = ctx.invoked_subcommand
if invoked_subcommand != "init": if invoked_subcommand != "init":
if not os.path.exists(config): if not os.path.exists(config):
@@ -53,13 +58,12 @@ async def cli(ctx: Context, config, app, name):
ctx.obj["config"] = tortoise_config ctx.obj["config"] = tortoise_config
ctx.obj["location"] = location ctx.obj["location"] = location
ctx.obj["app"] = app
if invoked_subcommand != "init-db": if invoked_subcommand != "init-db":
try: try:
await Migrate.init_with_old_models(tortoise_config, app, location) await Migrate.init_with_old_models(tortoise_config, app, location)
except ConfigurationError: except ConfigurationError:
raise UsageError(ctx=ctx, message="You must exec ini-db first") raise UsageError(ctx=ctx, message="You must exec init-db first")
@cli.command(help="Generate migrate changes file.") @cli.command(help="Generate migrate changes file.")
@@ -70,7 +74,7 @@ async def migrate(ctx: Context, name):
location = ctx.obj["location"] location = ctx.obj["location"]
app = ctx.obj["app"] app = ctx.obj["app"]
ret = Migrate.migrate(name) ret = await Migrate.migrate(name)
if not ret: if not ret:
return click.secho("No changes detected", fg=Color.yellow) return click.secho("No changes detected", fg=Color.yellow)
Migrate.write_old_models(config, app, location) Migrate.write_old_models(config, app, location)
@@ -80,24 +84,23 @@ async def migrate(ctx: Context, name):
@cli.command(help="Upgrade to latest version.") @cli.command(help="Upgrade to latest version.")
@click.pass_context @click.pass_context
async def upgrade(ctx: Context): async def upgrade(ctx: Context):
app = ctx.obj["app"]
config = ctx.obj["config"] config = ctx.obj["config"]
available_versions = Migrate.get_all_version_files(is_all=False) app = ctx.obj["app"]
if not available_versions: migrated = False
return click.secho("No migrate items", fg=Color.yellow) for version in Migrate.get_all_version_files():
async with in_transaction(get_app_connection_name(config, app)) as conn: if not await Aerich.exists(version=version, app=app):
for file in available_versions: async with in_transaction(get_app_connection_name(config, app)) as conn:
file_path = os.path.join(Migrate.migrate_location, file) file_path = os.path.join(Migrate.migrate_location, version)
with open(file_path, "r") as f: with open(file_path, "r") as f:
content = json.load(f) content = json.load(f)
upgrade_query_list = content.get("upgrade") upgrade_query_list = content.get("upgrade")
for upgrade_query in upgrade_query_list: for upgrade_query in upgrade_query_list:
await conn.execute_query(upgrade_query) await conn.execute_query(upgrade_query)
await Aerich.create(version=version, app=app)
with open(file_path, "w") as f: click.secho(f"Success upgrade {version}", fg=Color.green)
content["migrate"] = True migrated = True
json.dump(content, f, indent=2, ensure_ascii=False) if not migrated:
click.secho(f"Success upgrade {file}", fg=Color.green) click.secho("No migrate items", fg=Color.yellow)
@cli.command(help="Downgrade to previous version.") @cli.command(help="Downgrade to previous version.")
@@ -105,39 +108,43 @@ async def upgrade(ctx: Context):
async def downgrade(ctx: Context): async def downgrade(ctx: Context):
app = ctx.obj["app"] app = ctx.obj["app"]
config = ctx.obj["config"] config = ctx.obj["config"]
available_versions = Migrate.get_all_version_files() last_version = await Migrate.get_last_version()
if not available_versions: if not last_version:
return click.secho("No migrate items", fg=Color.yellow) return click.secho("No last version found", fg=Color.yellow)
file = last_version.version
async with in_transaction(get_app_connection_name(config, app)) as conn: async with in_transaction(get_app_connection_name(config, app)) as conn:
for file in reversed(available_versions): file_path = os.path.join(Migrate.migrate_location, file)
file_path = os.path.join(Migrate.migrate_location, file) with open(file_path, "r") as f:
with open(file_path, "r") as f: content = json.load(f)
content = json.load(f) downgrade_query_list = content.get("downgrade")
if content.get("migrate"): for downgrade_query in downgrade_query_list:
downgrade_query_list = content.get("downgrade") await conn.execute_query(downgrade_query)
for downgrade_query in downgrade_query_list: await last_version.delete()
await conn.execute_query(downgrade_query) return click.secho(f"Success downgrade {file}", fg=Color.green)
else:
continue
with open(file_path, "w") as f:
content["migrate"] = False
json.dump(content, f, indent=2, ensure_ascii=False)
return click.secho(f"Success downgrade {file}", fg=Color.green)
@cli.command(help="Show current available heads in migrate location.") @cli.command(help="Show current available heads in migrate location.")
@click.pass_context @click.pass_context
def heads(ctx: Context): async def heads(ctx: Context):
for version in Migrate.get_all_version_files(is_all=False): app = ctx.obj["app"]
click.secho(version, fg=Color.green) versions = Migrate.get_all_version_files()
is_heads = False
for version in versions:
if not await Aerich.exists(version=version, app=app):
click.secho(version, fg=Color.green)
is_heads = True
if not is_heads:
click.secho("No available heads,try migrate", fg=Color.green)
@cli.command(help="List all migrate items.") @cli.command(help="List all migrate items.")
@click.pass_context @click.pass_context
def history(ctx): def history(ctx):
for version in Migrate.get_all_version_files(): versions = Migrate.get_all_version_files()
for version in versions:
click.secho(version, fg=Color.green) click.secho(version, fg=Color.green)
if not versions:
click.secho("No history,try migrate", fg=Color.green)
@cli.command(help="Init config file and generate root migrate location.") @cli.command(help="Init config file and generate root migrate location.")
@@ -152,23 +159,25 @@ def history(ctx):
) )
@click.pass_context @click.pass_context
async def init( async def init(
ctx: Context, tortoise_orm, location, ctx: Context, tortoise_orm, location,
): ):
config = ctx.obj["config"] config_file = ctx.obj["config_file"]
name = ctx.obj["name"] name = ctx.obj["name"]
if os.path.exists(config_file):
return click.secho("You have inited", fg=Color.yellow)
parser.add_section(name) parser.add_section(name)
parser.set(name, "tortoise_orm", tortoise_orm) parser.set(name, "tortoise_orm", tortoise_orm)
parser.set(name, "location", location) parser.set(name, "location", location)
with open(config, "w") as f: with open(config_file, "w") as f:
parser.write(f) parser.write(f)
if not os.path.isdir(location): if not os.path.isdir(location):
os.mkdir(location) os.mkdir(location)
click.secho(f"Success create migrate location {location}", fg=Color.green) click.secho(f"Success create migrate location {location}", fg=Color.green)
click.secho(f"Success generate config file {config}", fg=Color.green) click.secho(f"Success generate config file {config_file}", fg=Color.green)
@cli.command(help="Generate schema and generate app migrate location.") @cli.command(help="Generate schema and generate app migrate location.")
@@ -189,8 +198,6 @@ async def init_db(ctx: Context, safe):
if not os.path.isdir(dirname): if not os.path.isdir(dirname):
os.mkdir(dirname) os.mkdir(dirname)
click.secho(f"Success create app migrate location {dirname}", fg=Color.green) click.secho(f"Success create app migrate location {dirname}", fg=Color.green)
else:
return click.secho(f'Already inited app "{app}"', fg=Color.yellow)
Migrate.write_old_models(config, app, location) Migrate.write_old_models(config, app, location)

View File

@@ -0,0 +1,8 @@
from tortoise.backends.asyncpg.schema_generator import AsyncpgSchemaGenerator
from aerich.ddl import BaseDDL
class PostgresDDL(BaseDDL):
schema_generator_cls = AsyncpgSchemaGenerator
DIALECT = AsyncpgSchemaGenerator.DIALECT

View File

@@ -0,0 +1,8 @@
from tortoise.backends.sqlite.schema_generator import SqliteSchemaGenerator
from aerich.ddl import BaseDDL
class SqliteDDL(BaseDDL):
schema_generator_cls = SqliteSchemaGenerator
DIALECT = SqliteSchemaGenerator.DIALECT

View File

@@ -3,7 +3,7 @@ import os
import re import re
from copy import deepcopy from copy import deepcopy
from datetime import datetime from datetime import datetime
from typing import Dict, List, Type from typing import Dict, List, Tuple, Type
from tortoise import ( from tortoise import (
BackwardFKRelation, BackwardFKRelation,
@@ -13,12 +13,10 @@ from tortoise import (
Model, Model,
Tortoise, Tortoise,
) )
from tortoise.backends.mysql.schema_generator import MySQLSchemaGenerator
from tortoise.fields import Field from tortoise.fields import Field
from aerich.ddl import BaseDDL from aerich.ddl import BaseDDL
from aerich.ddl.mysql import MysqlDDL from aerich.models import Aerich
from aerich.exceptions import ConfigurationError
from aerich.utils import get_app_connection from aerich.utils import get_app_connection
@@ -42,26 +40,12 @@ class Migrate:
return cls.old_models + ".py" return cls.old_models + ".py"
@classmethod @classmethod
def _get_all_migrate_files(cls): def get_all_version_files(cls) -> List[str]:
return sorted(filter(lambda x: x.endswith("json"), os.listdir(cls.migrate_location))) return sorted(filter(lambda x: x.endswith("json"), os.listdir(cls.migrate_location)))
@classmethod @classmethod
def _get_latest_version(cls) -> int: async def get_last_version(cls) -> Aerich:
ret = cls._get_all_migrate_files() return await Aerich.filter(app=cls.app).first()
if ret:
return int(ret[-1].split("_")[0])
return 0
@classmethod
def get_all_version_files(cls, is_all=True):
files = cls._get_all_migrate_files()
ret = []
for file in files:
with open(os.path.join(cls.migrate_location, file), "r") as f:
content = json.load(f)
if is_all or not content.get("migrate"):
ret.append(file)
return ret
@classmethod @classmethod
async def init_with_old_models(cls, config: dict, app: str, location: str): async def init_with_old_models(cls, config: dict, app: str, location: str):
@@ -74,33 +58,49 @@ class Migrate:
await Tortoise.init(config=migrate_config) await Tortoise.init(config=migrate_config)
connection = get_app_connection(config, app) connection = get_app_connection(config, app)
if connection.schema_generator is MySQLSchemaGenerator: if connection.schema_generator.DIALECT == "mysql":
from aerich.ddl.mysql import MysqlDDL
cls.ddl = MysqlDDL(connection) cls.ddl = MysqlDDL(connection)
elif connection.schema_generator.DIALECT == "sqlite":
from aerich.ddl.sqlite import SqliteDDL
cls.ddl = SqliteDDL(connection)
elif connection.schema_generator.DIALECT == "postgres":
from aerich.ddl.postgres import PostgresDDL
cls.ddl = PostgresDDL(connection)
else: else:
raise NotImplementedError("Current only support MySQL") raise NotImplementedError("Current only support MySQL")
@classmethod @classmethod
def _generate_diff_sql(cls, name): async def _get_last_version_num(cls):
last_version = await cls.get_last_version()
if not last_version:
return 0
version = last_version.version
return version.split("_")[0]
@classmethod
async def _generate_diff_sql(cls, name):
now = datetime.now().strftime("%Y%M%D%H%M%S").replace("/", "") now = datetime.now().strftime("%Y%M%D%H%M%S").replace("/", "")
filename = f"{cls._get_latest_version() + 1}_{now}_{name}.json" last_version_num = await cls._get_last_version_num()
version = f"{last_version_num + 1}_{now}_{name}.json"
content = { content = {
"upgrade": cls.upgrade_operators, "upgrade": cls.upgrade_operators,
"downgrade": cls.downgrade_operators, "downgrade": cls.downgrade_operators,
"migrate": False,
} }
with open(os.path.join(cls.migrate_location, filename), "w") as f: with open(os.path.join(cls.migrate_location, version), "w") as f:
json.dump(content, f, indent=2, ensure_ascii=False) json.dump(content, f, indent=2, ensure_ascii=False)
return filename return version
@classmethod @classmethod
def migrate(cls, name): async def migrate(cls, name) -> str:
""" """
diff old models and new models to generate diff content diff old models and new models to generate diff content
:param name: :param name:
:return: :return:
""" """
if not cls.migrate_config:
raise ConfigurationError("You must call init_with_old_models() first!")
apps = Tortoise.apps apps = Tortoise.apps
diff_models = apps.get(cls.diff_app) diff_models = apps.get(cls.diff_app)
app_models = apps.get(cls.app) app_models = apps.get(cls.app)
@@ -111,9 +111,9 @@ class Migrate:
cls._merge_operators() cls._merge_operators()
if not cls.upgrade_operators: if not cls.upgrade_operators:
return False return ""
return cls._generate_diff_sql(name) return await cls._generate_diff_sql(name)
@classmethod @classmethod
def _add_operator(cls, operator: str, upgrade=True, fk=False): def _add_operator(cls, operator: str, upgrade=True, fk=False):
@@ -146,12 +146,13 @@ class Migrate:
:param old_model_file: :param old_model_file:
:return: :return:
""" """
pattern = rf"\(('|\")({app})(.\w+)('|\")" pattern = rf"(\n)?('|\")({app})(.\w+)('|\")"
for i, model_file in enumerate(model_files): for i, model_file in enumerate(model_files):
with open(model_file, "r") as f: with open(model_file, "r") as f:
content = f.read() content = f.read()
ret = re.sub(pattern, rf"(\1{cls.diff_app}\3\4", content) ret = re.sub(pattern, rf"\2{cls.diff_app}\4\5", content)
with open(old_model_file, "w" if i == 0 else "w+a") as f: mode = "w" if i == 0 else "a"
with open(old_model_file, mode) as f:
f.write(ret) f.write(ret)
@classmethod @classmethod
@@ -251,7 +252,7 @@ class Migrate:
): ):
cls._add_operator( cls._add_operator(
cls._remove_index( cls._remove_index(
old_model, [old_field.model_field_name], old_field.unique old_model, (old_field.model_field_name,), old_field.unique
), ),
upgrade, upgrade,
isinstance(old_field, (ForeignKeyFieldInstance, ManyToManyFieldInstance)), isinstance(old_field, (ForeignKeyFieldInstance, ManyToManyFieldInstance)),
@@ -260,7 +261,7 @@ class Migrate:
new_field.unique and not old_field.unique new_field.unique and not old_field.unique
): ):
cls._add_operator( cls._add_operator(
cls._add_index(new_model, [new_field.model_field_name], new_field.unique), cls._add_index(new_model, (new_field.model_field_name,), new_field.unique),
upgrade, upgrade,
isinstance(new_field, (ForeignKeyFieldInstance, ManyToManyFieldInstance)), isinstance(new_field, (ForeignKeyFieldInstance, ManyToManyFieldInstance)),
) )
@@ -290,7 +291,7 @@ class Migrate:
cls._add_operator(cls._remove_index(old_model, old_unique, unique=True), upgrade) cls._add_operator(cls._remove_index(old_model, old_unique, unique=True), upgrade)
@classmethod @classmethod
def _resolve_fk_fields_name(cls, model: Type[Model], fields_name: List[str]): def _resolve_fk_fields_name(cls, model: Type[Model], fields_name: Tuple[str]):
ret = [] ret = []
for field_name in fields_name: for field_name in fields_name:
if field_name in model._meta.fk_fields: if field_name in model._meta.fk_fields:
@@ -300,12 +301,12 @@ class Migrate:
return ret return ret
@classmethod @classmethod
def _remove_index(cls, model: Type[Model], fields_name: List[str], unique=False): def _remove_index(cls, model: Type[Model], fields_name: Tuple[str], unique=False):
fields_name = cls._resolve_fk_fields_name(model, fields_name) fields_name = cls._resolve_fk_fields_name(model, fields_name)
return cls.ddl.drop_index(model, fields_name, unique) return cls.ddl.drop_index(model, fields_name, unique)
@classmethod @classmethod
def _add_index(cls, model: Type[Model], fields_name: List[str], unique=False): def _add_index(cls, model: Type[Model], fields_name: Tuple[str], unique=False):
fields_name = cls._resolve_fk_fields_name(model, fields_name) fields_name = cls._resolve_fk_fields_name(model, fields_name)
return cls.ddl.add_index(model, fields_name, unique) return cls.ddl.add_index(model, fields_name, unique)

9
aerich/models.py Normal file
View File

@@ -0,0 +1,9 @@
from tortoise import Model, fields
class Aerich(Model):
version = fields.CharField(max_length=50)
app = fields.CharField(max_length=20)
class Meta:
ordering = ["-id"]

View File

@@ -1,10 +1,10 @@
import importlib import importlib
from asyncclick import BadOptionUsage, Context from asyncclick import BadOptionUsage, Context
from tortoise import Tortoise from tortoise import BaseDBAsyncClient, Tortoise
def get_app_connection_name(config, app): def get_app_connection_name(config, app) -> str:
""" """
get connection name get connection name
:param config: :param config:
@@ -14,7 +14,7 @@ def get_app_connection_name(config, app):
return config.get("apps").get(app).get("default_connection") return config.get("apps").get(app).get("default_connection")
def get_app_connection(config, app): def get_app_connection(config, app) -> BaseDBAsyncClient:
""" """
get connection name get connection name
:param config: :param config:

11
conftest.py Normal file
View File

@@ -0,0 +1,11 @@
import os
import pytest
from tortoise.contrib.test import finalizer, initializer
@pytest.fixture(scope="module", autouse=True)
def initialize_tests(request):
db_url = os.getenv("TEST_DB", "sqlite://:memory:")
initializer(["tests.models"], db_url=db_url)
request.addfinalizer(finalizer)

327
poetry.lock generated
View File

@@ -1,5 +1,5 @@
[[package]] [[package]]
category = "main" category = "dev"
description = "MySQL driver for asyncio." description = "MySQL driver for asyncio."
name = "aiomysql" name = "aiomysql"
optional = false optional = false
@@ -38,6 +38,14 @@ doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
test = ["coverage (>=4.5)", "hypothesis (>=4.0)", "pytest (>=3.7.2)", "uvloop"] test = ["coverage (>=4.5)", "hypothesis (>=4.0)", "pytest (>=3.7.2)", "uvloop"]
trio = ["trio (>=0.12)"] trio = ["trio (>=0.12)"]
[[package]]
category = "dev"
description = "apipkg: namespace control and lazy-import mechanism"
name = "apipkg"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.5"
[[package]] [[package]]
category = "dev" category = "dev"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
@@ -69,6 +77,19 @@ anyio = "*"
dev = ["coverage", "pytest-runner", "pytest-trio", "pytest (>=3)", "sphinx", "tox"] dev = ["coverage", "pytest-runner", "pytest-trio", "pytest (>=3)", "sphinx", "tox"]
docs = ["sphinx"] docs = ["sphinx"]
[[package]]
category = "dev"
description = "An asyncio PostgreSQL driver"
name = "asyncpg"
optional = false
python-versions = ">=3.5.0"
version = "0.20.1"
[package.extras]
dev = ["Cython (0.29.14)", "pytest (>=3.6.0)", "Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)", "pycodestyle (>=2.5.0,<2.6.0)", "flake8 (>=3.7.9,<3.8.0)", "uvloop (>=0.14.0,<0.15.0)"]
docs = ["Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)"]
test = ["pycodestyle (>=2.5.0,<2.6.0)", "flake8 (>=3.7.9,<3.8.0)", "uvloop (>=0.14.0,<0.15.0)"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Enhance the standard unittest package with features for testing asyncio libraries" description = "Enhance the standard unittest package with features for testing asyncio libraries"
@@ -77,6 +98,15 @@ optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
version = "0.13.0" version = "0.13.0"
[[package]]
category = "dev"
description = "Atomic file writes."
marker = "sys_platform == \"win32\""
name = "atomicwrites"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.4.0"
[[package]] [[package]]
category = "dev" category = "dev"
description = "Classes Without Boilerplate" description = "Classes Without Boilerplate"
@@ -112,7 +142,7 @@ typed-ast = ">=1.4.0"
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
[[package]] [[package]]
category = "main" category = "dev"
description = "Foreign Function Interface for Python calling C code." description = "Foreign Function Interface for Python calling C code."
name = "cffi" name = "cffi"
optional = false optional = false
@@ -140,7 +170,16 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "7.1.2" version = "7.1.2"
[[package]] [[package]]
category = "main" category = "dev"
description = "Cross-platform colored terminal text."
marker = "sys_platform == \"win32\""
name = "colorama"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.3"
[[package]]
category = "dev"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
name = "cryptography" name = "cryptography"
optional = false optional = false
@@ -158,6 +197,20 @@ idna = ["idna (>=2.1)"]
pep8test = ["flake8", "flake8-import-order", "pep8-naming"] pep8test = ["flake8", "flake8-import-order", "pep8-naming"]
test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"]
[[package]]
category = "dev"
description = "execnet: rapid multi-Python deployment"
name = "execnet"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.7.1"
[package.dependencies]
apipkg = ">=1.4"
[package.extras]
testing = ["pre-commit"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "the modular source code checker: pep8 pyflakes and co" description = "the modular source code checker: pep8 pyflakes and co"
@@ -202,6 +255,50 @@ optional = false
python-versions = "*" python-versions = "*"
version = "0.6.1" version = "0.6.1"
[[package]]
category = "dev"
description = "More routines for operating on iterables, beyond itertools"
name = "more-itertools"
optional = false
python-versions = ">=3.5"
version = "8.3.0"
[[package]]
category = "dev"
description = "Optional static typing for Python"
name = "mypy"
optional = false
python-versions = ">=3.5"
version = "0.770"
[package.dependencies]
mypy-extensions = ">=0.4.3,<0.5.0"
typed-ast = ">=1.4.0,<1.5.0"
typing-extensions = ">=3.7.4"
[package.extras]
dmypy = ["psutil (>=4.0)"]
[[package]]
category = "dev"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
name = "mypy-extensions"
optional = false
python-versions = "*"
version = "0.4.3"
[[package]]
category = "dev"
description = "Core utilities for Python packages"
name = "packaging"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "20.4"
[package.dependencies]
pyparsing = ">=2.0.2"
six = "*"
[[package]] [[package]]
category = "dev" category = "dev"
description = "Utility library for gitignore style pattern matching of file paths." description = "Utility library for gitignore style pattern matching of file paths."
@@ -210,6 +307,25 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.8.0" version = "0.8.0"
[[package]]
category = "dev"
description = "plugin and hook calling mechanisms for python"
name = "pluggy"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.13.1"
[package.extras]
dev = ["pre-commit", "tox"]
[[package]]
category = "dev"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
name = "py"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.8.1"
[[package]] [[package]]
category = "dev" category = "dev"
description = "Python style guide checker" description = "Python style guide checker"
@@ -219,13 +335,26 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.6.0" version = "2.6.0"
[[package]] [[package]]
category = "main" category = "dev"
description = "C parser in Python" description = "C parser in Python"
name = "pycparser" name = "pycparser"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.20" version = "2.20"
[[package]]
category = "main"
description = "Data validation and settings management using python 3.6 type hinting"
name = "pydantic"
optional = false
python-versions = ">=3.6"
version = "1.5.1"
[package.extras]
dotenv = ["python-dotenv (>=0.10.4)"]
email = ["email-validator (>=1.0.3)"]
typing_extensions = ["typing-extensions (>=3.7.2)"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "passive checker of Python programs" description = "passive checker of Python programs"
@@ -235,7 +364,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.2.0" version = "2.2.0"
[[package]] [[package]]
category = "main" category = "dev"
description = "Pure Python MySQL Driver" description = "Pure Python MySQL Driver"
name = "pymysql" name = "pymysql"
optional = false optional = false
@@ -245,6 +374,14 @@ version = "0.9.2"
[package.dependencies] [package.dependencies]
cryptography = "*" cryptography = "*"
[[package]]
category = "dev"
description = "Python parsing module"
name = "pyparsing"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "2.4.7"
[[package]] [[package]]
category = "main" category = "main"
description = "A SQL query builder API for Python" description = "A SQL query builder API for Python"
@@ -253,6 +390,56 @@ optional = false
python-versions = "*" python-versions = "*"
version = "0.37.6" version = "0.37.6"
[[package]]
category = "dev"
description = "pytest: simple powerful testing with Python"
name = "pytest"
optional = false
python-versions = ">=3.5"
version = "5.4.2"
[package.dependencies]
atomicwrites = ">=1.0"
attrs = ">=17.4.0"
colorama = "*"
more-itertools = ">=4.0.0"
packaging = "*"
pluggy = ">=0.12,<1.0"
py = ">=1.5.0"
wcwidth = "*"
[package.extras]
checkqa-mypy = ["mypy (v0.761)"]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[[package]]
category = "dev"
description = "run tests in isolated forked subprocesses"
name = "pytest-forked"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.1.3"
[package.dependencies]
pytest = ">=3.1.0"
[[package]]
category = "dev"
description = "pytest xdist plugin for distributed testing and loop-on-failing modes"
name = "pytest-xdist"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "1.32.0"
[package.dependencies]
execnet = ">=1.1"
pytest = ">=4.4.0"
pytest-forked = "*"
six = "*"
[package.extras]
testing = ["filelock"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Alternative regular expression module, to replace re." description = "Alternative regular expression module, to replace re."
@@ -262,7 +449,7 @@ python-versions = "*"
version = "2020.5.14" version = "2020.5.14"
[[package]] [[package]]
category = "main" category = "dev"
description = "Python 2 and 3 compatibility utilities" description = "Python 2 and 3 compatibility utilities"
name = "six" name = "six"
optional = false optional = false
@@ -312,9 +499,9 @@ pypika = ">=0.36.5"
typing-extensions = ">=3.7" typing-extensions = ">=3.7"
[package.source] [package.source]
reference = "95c384a4742ee5980f8e4ae934bfdb0d8137bb40" reference = "1f67b7a0ca1384365d6ff89d9e245e733166d1a6"
type = "git" type = "git"
url = "https://github.com/tortoise/tortoise-orm.git" url = "https://github.com/long2ice/tortoise-orm.git"
[[package]] [[package]]
category = "dev" category = "dev"
description = "a fork of Python 2 and 3 ast modules with type comment support" description = "a fork of Python 2 and 3 ast modules with type comment support"
@@ -331,8 +518,16 @@ optional = false
python-versions = "*" python-versions = "*"
version = "3.7.4.2" version = "3.7.4.2"
[[package]]
category = "dev"
description = "Measures number of Terminal column cells of wide-character codes"
name = "wcwidth"
optional = false
python-versions = "*"
version = "0.1.9"
[metadata] [metadata]
content-hash = "9ce51215dcc82924bab54fca5ee46097cb5ccc2f6ecd455994b9b9f37b801523" content-hash = "58a032bbb47859e87d2bce036af24149060cc531ff9220a14f6cd48db6252f39"
python-versions = "^3.8" python-versions = "^3.8"
[metadata.files] [metadata.files]
@@ -348,6 +543,10 @@ anyio = [
{file = "anyio-1.3.0-py3-none-any.whl", hash = "sha256:db2c3d21576870b95d4fd0b8f4a0f9c64057f777c578f3a8127179a17c8c067e"}, {file = "anyio-1.3.0-py3-none-any.whl", hash = "sha256:db2c3d21576870b95d4fd0b8f4a0f9c64057f777c578f3a8127179a17c8c067e"},
{file = "anyio-1.3.0.tar.gz", hash = "sha256:7deae0315dd10aa41c21528b83352e4b52f44e6153a21081a3d1cd8c03728e46"}, {file = "anyio-1.3.0.tar.gz", hash = "sha256:7deae0315dd10aa41c21528b83352e4b52f44e6153a21081a3d1cd8c03728e46"},
] ]
apipkg = [
{file = "apipkg-1.5-py2.py3-none-any.whl", hash = "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"},
{file = "apipkg-1.5.tar.gz", hash = "sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6"},
]
appdirs = [ appdirs = [
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
@@ -359,10 +558,37 @@ async-generator = [
asyncclick = [ asyncclick = [
{file = "asyncclick-7.0.9.tar.gz", hash = "sha256:62cebf3eca36d973802e2dd521ca1db11c5bf4544e9795e093d1a53cb688a8c2"}, {file = "asyncclick-7.0.9.tar.gz", hash = "sha256:62cebf3eca36d973802e2dd521ca1db11c5bf4544e9795e093d1a53cb688a8c2"},
] ]
asyncpg = [
{file = "asyncpg-0.20.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:f7184689177eeb5a11fa1b2baf3f6f2e26bfd7a85acf4de1a3adbd0867d7c0e2"},
{file = "asyncpg-0.20.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:f0c9719ac00615f097fe91082b785bce36dbf02a5ec4115ede0ebfd2cd9500cb"},
{file = "asyncpg-0.20.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1388caa456070dab102be874205e3ae8fd1de2577d5de9fa22e65ba5c0f8b110"},
{file = "asyncpg-0.20.1-cp35-cp35m-win32.whl", hash = "sha256:ec6e7046c98730cb2ba4df41387e10cb8963a3ac2918f69ae416f8aab9ca7b1b"},
{file = "asyncpg-0.20.1-cp35-cp35m-win_amd64.whl", hash = "sha256:25edb0b947eb632b6b53e5a4b36cba5677297bb34cbaba270019714d0a5fed76"},
{file = "asyncpg-0.20.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:95cd2df61ee00b789bdcd04a080e6d9188693b841db2bf9a87ebaed9e53147e0"},
{file = "asyncpg-0.20.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:058baec9d6b75612412baa872a1aa47317d0ff88c318a49f9c4a2389043d5a8d"},
{file = "asyncpg-0.20.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c773c7dbe2f4d3ebc9e3030e94303e45d6742e6c2fc25da0c46a56ea3d83caeb"},
{file = "asyncpg-0.20.1-cp36-cp36m-win32.whl", hash = "sha256:5664d1bd8abe64fc60a0e701eb85fa1d8c9a4a8018a5a59164d27238f2caf395"},
{file = "asyncpg-0.20.1-cp36-cp36m-win_amd64.whl", hash = "sha256:57666dfae38f4dbf84ffbf0c5c0f78733fef0e8e083230275dcb9ccad1d5ee09"},
{file = "asyncpg-0.20.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:0c336903c3b08e970f8af2f606332f1738dba156bca83ed0467dc2f5c70da796"},
{file = "asyncpg-0.20.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ad5ba062e09673b1a4b8d0facaf5a6d9719bf7b337440d10b07fe994d90a9552"},
{file = "asyncpg-0.20.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba90d3578bc6dddcbce461875672fd9bdb34f0b8215b68612dd3b65a956ff51c"},
{file = "asyncpg-0.20.1-cp37-cp37m-win32.whl", hash = "sha256:da238592235717419a6a7b5edc8564da410ebfd056ca4ecc41e70b1b5df86fba"},
{file = "asyncpg-0.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:74510234c294c6a6767089ba9c938f09a491426c24405634eb357bd91dffd734"},
{file = "asyncpg-0.20.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:391aea89871df8c1560750af6c7170f2772c2d133b34772acf3637e3cf4db93e"},
{file = "asyncpg-0.20.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a981500bf6947926e53c48f4d60ae080af1b4ad7fa78e363465a5b5ad4f2b65e"},
{file = "asyncpg-0.20.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a9e6fd6f0f9e8bd77e9a4e1ef9a4f83a80674d9136a754ae3603e915da96b627"},
{file = "asyncpg-0.20.1-cp38-cp38-win32.whl", hash = "sha256:e39aac2b3a2f839ce65aa255ce416de899c58b7d38d601d24ca35558e13b48e3"},
{file = "asyncpg-0.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:2af6a5a705accd36e13292ea43d08c20b15e52d684beb522cb3a7d3c9c8f3f48"},
{file = "asyncpg-0.20.1.tar.gz", hash = "sha256:394bf19bdddbba07a38cd6fb526ebf66e120444d6b3097332b78efd5b26495b0"},
]
asynctest = [ asynctest = [
{file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"},
{file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"},
] ]
atomicwrites = [
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
]
attrs = [ attrs = [
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
@@ -408,6 +634,10 @@ click = [
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
] ]
colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
]
cryptography = [ cryptography = [
{file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"}, {file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"},
{file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"}, {file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"},
@@ -429,6 +659,10 @@ cryptography = [
{file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"}, {file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"},
{file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"}, {file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"},
] ]
execnet = [
{file = "execnet-1.7.1-py2.py3-none-any.whl", hash = "sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"},
{file = "execnet-1.7.1.tar.gz", hash = "sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50"},
]
flake8 = [ flake8 = [
{file = "flake8-3.8.1-py2.py3-none-any.whl", hash = "sha256:6c1193b0c3f853ef763969238f6c81e9e63ace9d024518edc020d5f1d6d93195"}, {file = "flake8-3.8.1-py2.py3-none-any.whl", hash = "sha256:6c1193b0c3f853ef763969238f6c81e9e63ace9d024518edc020d5f1d6d93195"},
{file = "flake8-3.8.1.tar.gz", hash = "sha256:ea6623797bf9a52f4c9577d780da0bb17d65f870213f7b5bcc9fca82540c31d5"}, {file = "flake8-3.8.1.tar.gz", hash = "sha256:ea6623797bf9a52f4c9577d780da0bb17d65f870213f7b5bcc9fca82540c31d5"},
@@ -446,10 +680,46 @@ mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
] ]
more-itertools = [
{file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"},
{file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"},
]
mypy = [
{file = "mypy-0.770-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:a34b577cdf6313bf24755f7a0e3f3c326d5c1f4fe7422d1d06498eb25ad0c600"},
{file = "mypy-0.770-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:86c857510a9b7c3104cf4cde1568f4921762c8f9842e987bc03ed4f160925754"},
{file = "mypy-0.770-cp35-cp35m-win_amd64.whl", hash = "sha256:a8ffcd53cb5dfc131850851cc09f1c44689c2812d0beb954d8138d4f5fc17f65"},
{file = "mypy-0.770-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:7687f6455ec3ed7649d1ae574136835a4272b65b3ddcf01ab8704ac65616c5ce"},
{file = "mypy-0.770-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3beff56b453b6ef94ecb2996bea101a08f1f8a9771d3cbf4988a61e4d9973761"},
{file = "mypy-0.770-cp36-cp36m-win_amd64.whl", hash = "sha256:15b948e1302682e3682f11f50208b726a246ab4e6c1b39f9264a8796bb416aa2"},
{file = "mypy-0.770-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:b90928f2d9eb2f33162405f32dde9f6dcead63a0971ca8a1b50eb4ca3e35ceb8"},
{file = "mypy-0.770-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c56ffe22faa2e51054c5f7a3bc70a370939c2ed4de308c690e7949230c995913"},
{file = "mypy-0.770-cp37-cp37m-win_amd64.whl", hash = "sha256:8dfb69fbf9f3aeed18afffb15e319ca7f8da9642336348ddd6cab2713ddcf8f9"},
{file = "mypy-0.770-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:219a3116ecd015f8dca7b5d2c366c973509dfb9a8fc97ef044a36e3da66144a1"},
{file = "mypy-0.770-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7ec45a70d40ede1ec7ad7f95b3c94c9cf4c186a32f6bacb1795b60abd2f9ef27"},
{file = "mypy-0.770-cp38-cp38-win_amd64.whl", hash = "sha256:f91c7ae919bbc3f96cd5e5b2e786b2b108343d1d7972ea130f7de27fdd547cf3"},
{file = "mypy-0.770-py3-none-any.whl", hash = "sha256:3b1fc683fb204c6b4403a1ef23f0b1fac8e4477091585e0c8c54cbdf7d7bb164"},
{file = "mypy-0.770.tar.gz", hash = "sha256:8a627507ef9b307b46a1fea9513d5c98680ba09591253082b4c48697ba05a4ae"},
]
mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
packaging = [
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
{file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
]
pathspec = [ pathspec = [
{file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"},
{file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
] ]
pluggy = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
]
py = [
{file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"},
{file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"},
]
pycodestyle = [ pycodestyle = [
{file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
{file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"},
@@ -458,6 +728,25 @@ pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
] ]
pydantic = [
{file = "pydantic-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2a6904e9f18dea58f76f16b95cba6a2f20b72d787abd84ecd67ebc526e61dce6"},
{file = "pydantic-1.5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da8099fca5ee339d5572cfa8af12cf0856ae993406f0b1eb9bb38c8a660e7416"},
{file = "pydantic-1.5.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:68dece67bff2b3a5cc188258e46b49f676a722304f1c6148ae08e9291e284d98"},
{file = "pydantic-1.5.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ab863853cb502480b118187d670f753be65ec144e1654924bec33d63bc8b3ce2"},
{file = "pydantic-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:2007eb062ed0e57875ce8ead12760a6e44bf5836e6a1a7ea81d71eeecf3ede0f"},
{file = "pydantic-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:20a15a303ce1e4d831b4e79c17a4a29cb6740b12524f5bba3ea363bff65732bc"},
{file = "pydantic-1.5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:473101121b1bd454c8effc9fe66d54812fdc128184d9015c5aaa0d4e58a6d338"},
{file = "pydantic-1.5.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:9be755919258d5d168aeffbe913ed6e8bd562e018df7724b68cabdee3371e331"},
{file = "pydantic-1.5.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:b96ce81c4b5ca62ab81181212edfd057beaa41411cd9700fbcb48a6ba6564b4e"},
{file = "pydantic-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:93b9f265329d9827f39f0fca68f5d72cc8321881cdc519a1304fa73b9f8a75bd"},
{file = "pydantic-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2c753d355126ddd1eefeb167fa61c7037ecd30b98e7ebecdc0d1da463b4ea09"},
{file = "pydantic-1.5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8433dbb87246c0f562af75d00fa80155b74e4f6924b0db6a2078a3cd2f11c6c4"},
{file = "pydantic-1.5.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0a1cdf24e567d42dc762d3fed399bd211a13db2e8462af9dfa93b34c41648efb"},
{file = "pydantic-1.5.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:8be325fc9da897029ee48d1b5e40df817d97fe969f3ac3fd2434ba7e198c55d5"},
{file = "pydantic-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:3714a4056f5bdbecf3a41e0706ec9b228c9513eee2ad884dc2c568c4dfa540e9"},
{file = "pydantic-1.5.1-py36.py37.py38-none-any.whl", hash = "sha256:70f27d2f0268f490fe3de0a9b6fca7b7492b8fd6623f9fecd25b221ebee385e3"},
{file = "pydantic-1.5.1.tar.gz", hash = "sha256:f0018613c7a0d19df3240c2a913849786f21b6539b9f23d85ce4067489dfacfa"},
]
pyflakes = [ pyflakes = [
{file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
{file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"},
@@ -466,9 +755,25 @@ pymysql = [
{file = "PyMySQL-0.9.2-py2.py3-none-any.whl", hash = "sha256:95f057328357e0e13a30e67857a8c694878b0175797a9a203ee7adbfb9b1ec5f"}, {file = "PyMySQL-0.9.2-py2.py3-none-any.whl", hash = "sha256:95f057328357e0e13a30e67857a8c694878b0175797a9a203ee7adbfb9b1ec5f"},
{file = "PyMySQL-0.9.2.tar.gz", hash = "sha256:9ec760cbb251c158c19d6c88c17ca00a8632bac713890e465b2be01fdc30713f"}, {file = "PyMySQL-0.9.2.tar.gz", hash = "sha256:9ec760cbb251c158c19d6c88c17ca00a8632bac713890e465b2be01fdc30713f"},
] ]
pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pypika = [ pypika = [
{file = "PyPika-0.37.6.tar.gz", hash = "sha256:64510fa36667e8bb654bdc1be5a3a77bac1dbc2f03d4848efac08e39d9cac6f5"}, {file = "PyPika-0.37.6.tar.gz", hash = "sha256:64510fa36667e8bb654bdc1be5a3a77bac1dbc2f03d4848efac08e39d9cac6f5"},
] ]
pytest = [
{file = "pytest-5.4.2-py3-none-any.whl", hash = "sha256:95c710d0a72d91c13fae35dce195633c929c3792f54125919847fdcdf7caa0d3"},
{file = "pytest-5.4.2.tar.gz", hash = "sha256:eb2b5e935f6a019317e455b6da83dd8650ac9ffd2ee73a7b657a30873d67a698"},
]
pytest-forked = [
{file = "pytest-forked-1.1.3.tar.gz", hash = "sha256:1805699ed9c9e60cb7a8179b8d4fa2b8898098e82d229b0825d8095f0f261100"},
{file = "pytest_forked-1.1.3-py2.py3-none-any.whl", hash = "sha256:1ae25dba8ee2e56fb47311c9638f9e58552691da87e82d25b0ce0e4bf52b7d87"},
]
pytest-xdist = [
{file = "pytest-xdist-1.32.0.tar.gz", hash = "sha256:1d4166dcac69adb38eeaedb88c8fada8588348258a3492ab49ba9161f2971129"},
{file = "pytest_xdist-1.32.0-py2.py3-none-any.whl", hash = "sha256:ba5ec9fde3410bd9a116ff7e4f26c92e02fa3d27975ef3ad03f330b3d4b54e91"},
]
regex = [ regex = [
{file = "regex-2020.5.14-cp27-cp27m-win32.whl", hash = "sha256:e565569fc28e3ba3e475ec344d87ed3cd8ba2d575335359749298a0899fe122e"}, {file = "regex-2020.5.14-cp27-cp27m-win32.whl", hash = "sha256:e565569fc28e3ba3e475ec344d87ed3cd8ba2d575335359749298a0899fe122e"},
{file = "regex-2020.5.14-cp27-cp27m-win_amd64.whl", hash = "sha256:d466967ac8e45244b9dfe302bbe5e3337f8dc4dec8d7d10f5e950d83b140d33a"}, {file = "regex-2020.5.14-cp27-cp27m-win_amd64.whl", hash = "sha256:d466967ac8e45244b9dfe302bbe5e3337f8dc4dec8d7d10f5e950d83b140d33a"},
@@ -537,3 +842,7 @@ typing-extensions = [
{file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"},
{file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"},
] ]
wcwidth = [
{file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"},
{file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"},
]

View File

@@ -6,9 +6,9 @@ authors = ["long2ice <long2ice@gmail.com>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8" python = "^3.8"
tortoise-orm = {git = "https://github.com/tortoise/tortoise-orm.git", branch = "develop"} tortoise-orm = {git = "https://github.com/long2ice/tortoise-orm.git", branch = "develop"}
aiomysql = "*"
asyncclick = "*" asyncclick = "*"
pydantic = "*"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
taskipy = "*" taskipy = "*"
@@ -16,6 +16,11 @@ asynctest = "*"
flake8 = "*" flake8 = "*"
isort = "*" isort = "*"
black = "^19.10b0" black = "^19.10b0"
pytest = "*"
aiomysql = "*"
asyncpg = "*"
pytest-xdist = "*"
mypy = "*"
[tool.taskipy.tasks] [tool.taskipy.tasks]
export = "poetry export -f requirements.txt --without-hashes > requirements.txt" export = "poetry export -f requirements.txt --without-hashes > requirements.txt"

2
pytest.ini Normal file
View File

@@ -0,0 +1,2 @@
[pytest]
addopts = -p no:warnings --ignore=src

View File

@@ -1,31 +1,48 @@
aiomysql==0.0.20 aiomysql==0.0.20
aiosqlite==0.13.0 aiosqlite==0.13.0
anyio==1.3.0 anyio==1.3.0
apipkg==1.5
appdirs==1.4.4 appdirs==1.4.4
async-generator==1.10 async-generator==1.10
asyncclick==7.0.9 asyncclick==7.0.9
asyncpg==0.20.1
asynctest==0.13.0 asynctest==0.13.0
atomicwrites==1.4.0; sys_platform == "win32"
attrs==19.3.0 attrs==19.3.0
black==19.10b0 black==19.10b0
cffi==1.14.0 cffi==1.14.0
ciso8601==2.1.3; sys_platform != "win32" and implementation_name == "cpython" ciso8601==2.1.3; sys_platform != "win32" and implementation_name == "cpython"
click==7.1.2 click==7.1.2
colorama==0.4.3; sys_platform == "win32"
cryptography==2.9.2 cryptography==2.9.2
execnet==1.7.1
flake8==3.8.1 flake8==3.8.1
iso8601==0.1.12; sys_platform == "win32" or implementation_name != "cpython" iso8601==0.1.12; sys_platform == "win32" or implementation_name != "cpython"
isort==4.3.21 isort==4.3.21
mccabe==0.6.1 mccabe==0.6.1
more-itertools==8.3.0
mypy==0.770
mypy-extensions==0.4.3
packaging==20.4
pathspec==0.8.0 pathspec==0.8.0
pluggy==0.13.1
py==1.8.1
pycodestyle==2.6.0 pycodestyle==2.6.0
pycparser==2.20 pycparser==2.20
pydantic==1.5.1
pyflakes==2.2.0 pyflakes==2.2.0
pymysql==0.9.2 pymysql==0.9.2
pyparsing==2.4.7
pypika==0.37.6 pypika==0.37.6
pytest==5.4.2
pytest-forked==1.1.3
pytest-xdist==1.32.0
regex==2020.5.14 regex==2020.5.14
six==1.14.0 six==1.14.0
sniffio==1.1.0 sniffio==1.1.0
taskipy==1.2.1 taskipy==1.2.1
toml==0.10.1 toml==0.10.1
-e git+https://github.com/tortoise/tortoise-orm.git@95c384a4742ee5980f8e4ae934bfdb0d8137bb40#egg=tortoise-orm -e git+https://github.com/long2ice/tortoise-orm.git@1f67b7a0ca1384365d6ff89d9e245e733166d1a6#egg=tortoise-orm
typed-ast==1.4.1 typed-ast==1.4.1
typing-extensions==3.7.4.2 typing-extensions==3.7.4.2
wcwidth==0.1.9

View File

@@ -1,15 +1,10 @@
aiomysql==0.0.20
aiosqlite==0.13.0 aiosqlite==0.13.0
anyio==1.3.0 anyio==1.3.0
async-generator==1.10 async-generator==1.10
asyncclick==7.0.9 asyncclick==7.0.9
cffi==1.14.0
ciso8601==2.1.3; sys_platform != "win32" and implementation_name == "cpython" ciso8601==2.1.3; sys_platform != "win32" and implementation_name == "cpython"
cryptography==2.9.2
iso8601==0.1.12; sys_platform == "win32" or implementation_name != "cpython" iso8601==0.1.12; sys_platform == "win32" or implementation_name != "cpython"
pycparser==2.20 pydantic==1.5.1
pymysql==0.9.2
pypika==0.37.6 pypika==0.37.6
six==1.14.0
sniffio==1.1.0 sniffio==1.1.0
typing-extensions==3.7.4.2 typing-extensions==3.7.4.2

View File

@@ -14,5 +14,34 @@ force_grid_wrap=0
use_parentheses=True use_parentheses=True
line_length=100 line_length=100
[tool:pytest]
addopts = -n auto --tb=native -q
[mypy]
pretty = True
ignore_missing_imports = True
check_untyped_defs = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_defs = False
disallow_incomplete_defs = False
disallow_untyped_decorators = True
no_implicit_optional = True
warn_redundant_casts = True
warn_unused_ignores = True
warn_no_return = True
warn_return_any = False
warn_unused_configs = True
warn_unreachable = True
allow_redefinition = True
strict_equality = True
show_error_context = True
[mypy-tests.*]
check_untyped_defs = False
disallow_untyped_defs = False
disallow_incomplete_defs = False
warn_unreachable = False
[mypy-conftest]
disallow_untyped_defs = False

View File

@@ -39,6 +39,6 @@ setup(
keywords=( keywords=(
'migrate Tortoise-ORM mysql' 'migrate Tortoise-ORM mysql'
), ),
dependency_links=['https://github.com/tortoise/tortoise-orm.git@branch#egg=tortoise-orm'], dependency_links=['https://github.com/long2ice/tortoise-orm.git@develop#egg=tortoise-orm'],
install_requires=requirements(), install_requires=requirements(),
) )

View File

@@ -0,0 +1,6 @@
TORTOISE_ORM = {
"connections": {"default": "mysql://root:123456@127.0.0.1:3306/test"},
"apps": {
"models": {"models": ["tests.models", "aerich.models"], "default_connection": "default"}
},
}

View File

@@ -1,19 +0,0 @@
from asynctest import TestCase
from tortoise import Tortoise
from aerich.ddl.mysql import MysqlDDL
TORTOISE_ORM = {
"connections": {"default": "mysql://root:123456@127.0.0.1:3306/test",},
"apps": {"models": {"models": ["tests.models"], "default_connection": "default",},},
}
class DBTestCase(TestCase):
async def setUp(self) -> None:
await Tortoise.init(config=TORTOISE_ORM)
self.client = Tortoise.get_connection("default")
self.ddl = MysqlDDL(self.client)
async def tearDown(self) -> None:
await Tortoise.close_connections()

View File

@@ -1,55 +0,0 @@
from tests.backends.mysql import DBTestCase
from tests.models import Category
class TestDDL(DBTestCase):
def test_create_table(self):
ret = self.ddl.create_table(Category)
self.assertEqual(
ret,
"""CREATE TABLE IF NOT EXISTS `category` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`slug` VARCHAR(200) NOT NULL,
`name` VARCHAR(200) NOT NULL,
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`user_id` INT NOT NULL COMMENT 'User',
CONSTRAINT `fk_category_user_e2e3874c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;""",
)
def test_drop_table(self):
ret = self.ddl.drop_table(Category)
self.assertEqual(ret, "DROP TABLE category IF EXISTS")
def test_add_column(self):
ret = self.ddl.add_column(Category, Category._meta.fields_map.get("name"))
self.assertEqual(ret, "ALTER TABLE category ADD `name` VARCHAR(200) NOT NULL")
def test_drop_column(self):
ret = self.ddl.drop_column(Category, "name")
self.assertEqual(ret, "ALTER TABLE category DROP COLUMN name")
def test_add_index(self):
ret = self.ddl.add_index(Category, ["name"])
self.assertEqual(ret, "ALTER TABLE category ADD INDEX idx_category_name_8b0cb9 (`name`)")
ret = self.ddl.add_index(Category, ["name"], True)
self.assertEqual(
ret, "ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 (`name`)"
)
def test_drop_index(self):
ret = self.ddl.drop_index(Category, ["name"])
self.assertEqual(ret, "ALTER TABLE category DROP INDEX idx_category_name_8b0cb9")
ret = self.ddl.drop_index(Category, ["name"], True)
self.assertEqual(ret, "ALTER TABLE category DROP INDEX uid_category_name_8b0cb9")
def test_add_fk(self):
ret = self.ddl.add_fk(Category, Category._meta.fields_map.get("user"))
self.assertEqual(
ret,
"ALTER TABLE category ADD CONSTRAINT `fk_category_user_366ffa6f` FOREIGN KEY (`user`) REFERENCES `user` (`id`) ON DELETE CASCADE",
)
def test_drop_fk(self):
ret = self.ddl.drop_fk(Category, Category._meta.fields_map.get("user"))
self.assertEqual(ret, "ALTER TABLE category DROP FOREIGN KEY fk_category_user_366ffa6f")

View File

@@ -1,17 +0,0 @@
from asynctest import TestCase
from tortoise import Tortoise
from aerich.migrate import Migrate
from tests.backends.mysql import TORTOISE_ORM
class TestMigrate(TestCase):
async def setUp(self) -> None:
await Migrate.init_with_old_models(TORTOISE_ORM, "models", "./migrations")
async def test_migrate(self):
Migrate.diff_model(
Tortoise.apps.get("models").get("Category"),
Tortoise.apps.get("diff_models").get("Category"),
)
print(Migrate.upgrade_operators)

View File

@@ -30,9 +30,6 @@ class User(Model):
avatar = fields.CharField(max_length=200, default="") avatar = fields.CharField(max_length=200, default="")
intro = fields.TextField(default="") intro = fields.TextField(default="")
def __str__(self):
return f"{self.pk}#{self.username}"
class Category(Model): class Category(Model):
slug = fields.CharField(max_length=200) slug = fields.CharField(max_length=200)
@@ -40,9 +37,6 @@ class Category(Model):
user = fields.ForeignKeyField("models.User", description="User") user = fields.ForeignKeyField("models.User", description="User")
created_at = fields.DatetimeField(auto_now_add=True) created_at = fields.DatetimeField(auto_now_add=True)
def __str__(self):
return f"{self.pk}#{self.name}"
class Product(Model): class Product(Model):
categories = fields.ManyToManyField("models.Category") categories = fields.ManyToManyField("models.Category")
@@ -55,15 +49,9 @@ class Product(Model):
body = fields.TextField() body = fields.TextField()
created_at = fields.DatetimeField(auto_now_add=True) created_at = fields.DatetimeField(auto_now_add=True)
def __str__(self):
return f"{self.pk}#{self.name}"
class Config(Model): class Config(Model):
label = fields.CharField(max_length=200) label = fields.CharField(max_length=200)
key = fields.CharField(max_length=20) key = fields.CharField(max_length=20)
value = fields.JSONField() value = fields.JSONField()
status: Status = fields.IntEnumField(Status, default=Status.on) status: Status = fields.IntEnumField(Status, default=Status.on)
def __str__(self):
return f"{self.pk}#{self.label}"

114
tests/test_ddl.py Normal file
View File

@@ -0,0 +1,114 @@
from tortoise import Tortoise
from tortoise.backends.asyncpg.schema_generator import AsyncpgSchemaGenerator
from tortoise.backends.mysql.schema_generator import MySQLSchemaGenerator
from tortoise.backends.sqlite.schema_generator import SqliteSchemaGenerator
from tortoise.contrib import test
from aerich.ddl.mysql import MysqlDDL
from aerich.ddl.postgres import PostgresDDL
from aerich.ddl.sqlite import SqliteDDL
from tests.models import Category
class TestDDL(test.TruncationTestCase):
maxDiff = None
def setUp(self) -> None:
client = Tortoise.get_connection("models")
if client.schema_generator is MySQLSchemaGenerator:
self.ddl = MysqlDDL(client)
elif client.schema_generator is SqliteSchemaGenerator:
self.ddl = SqliteDDL(client)
elif client.schema_generator is AsyncpgSchemaGenerator:
self.ddl = PostgresDDL(client)
def test_create_table(self):
ret = self.ddl.create_table(Category)
if isinstance(self.ddl, MysqlDDL):
self.assertEqual(
ret,
"""CREATE TABLE IF NOT EXISTS `category` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`slug` VARCHAR(200) NOT NULL,
`name` VARCHAR(200) NOT NULL,
`created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`user_id` INT NOT NULL COMMENT 'User',
CONSTRAINT `fk_category_user_e2e3874c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;""",
)
elif isinstance(self.ddl, SqliteDDL):
self.assertEqual(
ret,
"""CREATE TABLE IF NOT EXISTS "category" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"slug" VARCHAR(200) NOT NULL,
"name" VARCHAR(200) NOT NULL,
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"user_id" INT NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE /* User */
);""",
)
elif isinstance(self.ddl, PostgresDDL):
self.assertEqual(
ret,
"""CREATE TABLE IF NOT EXISTS "category" (
"id" SERIAL NOT NULL PRIMARY KEY,
"slug" VARCHAR(200) NOT NULL,
"name" VARCHAR(200) NOT NULL,
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"user_id" INT NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE
);
COMMENT ON COLUMN "category"."user_id" IS 'User';""",
)
def test_drop_table(self):
ret = self.ddl.drop_table(Category)
self.assertEqual(ret, "DROP TABLE IF EXISTS category")
def test_add_column(self):
ret = self.ddl.add_column(Category, Category._meta.fields_map.get("name"))
if isinstance(self.ddl, MysqlDDL):
self.assertEqual(ret, "ALTER TABLE category ADD `name` VARCHAR(200) NOT NULL")
elif isinstance(self.ddl, PostgresDDL):
self.assertEqual(ret, 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL')
elif isinstance(self.ddl, SqliteDDL):
self.assertEqual(ret, 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL')
def test_drop_column(self):
ret = self.ddl.drop_column(Category, "name")
self.assertEqual(ret, "ALTER TABLE category DROP COLUMN name")
self.assertEqual(ret, "ALTER TABLE category DROP COLUMN name")
def test_add_index(self):
index = self.ddl.add_index(Category, ["name"])
index_u = self.ddl.add_index(Category, ["name"], True)
if isinstance(self.ddl, MysqlDDL):
self.assertEqual(
index, "ALTER TABLE category ADD INDEX idx_category_name_8b0cb9 (`name`)"
)
self.assertEqual(
index_u, "ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 (`name`)"
)
elif isinstance(self.ddl, SqliteDDL):
self.assertEqual(
index_u, 'ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 ("name")'
)
self.assertEqual(
index_u, 'ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 ("name")'
)
def test_drop_index(self):
ret = self.ddl.drop_index(Category, ["name"])
self.assertEqual(ret, "ALTER TABLE category DROP INDEX idx_category_name_8b0cb9")
ret = self.ddl.drop_index(Category, ["name"], True)
self.assertEqual(ret, "ALTER TABLE category DROP INDEX uid_category_name_8b0cb9")
def test_add_fk(self):
ret = self.ddl.add_fk(Category, Category._meta.fields_map.get("user"))
self.assertEqual(
ret,
"ALTER TABLE category ADD CONSTRAINT `fk_category_user_e2e3874c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE",
)
def test_drop_fk(self):
ret = self.ddl.drop_fk(Category, Category._meta.fields_map.get("user"))
self.assertEqual(ret, "ALTER TABLE category DROP FOREIGN KEY fk_category_user_e2e3874c")

View File

@@ -1,6 +0,0 @@
from unittest import TestCase
class TestUtils(TestCase):
def test_get_app_connection(self):
pass

11
tox.ini
View File

@@ -1,11 +0,0 @@
[tox]
envlist = py{37,38,39}
skip_missing_interpreters = True
[testenv]
whitelist_externals=
make
commands=
make ci
deps =
-r requirements-dev.txt