Compare commits
	
		
			9 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | aa921355b9 | ||
|  | ea1191bb10 | ||
|  | 23dd29644c | ||
|  | bf1d745cef | ||
|  | f5e5d24855 | ||
|  | 6d92aec4b1 | ||
|  | 55e78bdd2d | ||
|  | b07d1abf49 | ||
|  | ad9c3c809d | 
							
								
								
									
										4
									
								
								.github/workflows/pypi.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/pypi.yml
									
									
									
									
										vendored
									
									
								
							| @@ -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
									
								
							
							
						
						
									
										34
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
										Normal 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 | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -143,3 +143,4 @@ cython_debug/ | |||||||
| .idea | .idea | ||||||
| migrations | migrations | ||||||
| aerich.ini | aerich.ini | ||||||
|  | src | ||||||
| @@ -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. | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								Makefile
									
									
									
									
									
								
							| @@ -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 | ||||||
							
								
								
									
										17
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								README.rst
									
									
									
									
									
								
							| @@ -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 | ||||||
| ------------------------- | ------------------------- | ||||||
|   | |||||||
| @@ -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(): | ||||||
|  |         if not await Aerich.exists(version=version, app=app): | ||||||
|             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 available_versions: |                 file_path = os.path.join(Migrate.migrate_location, version) | ||||||
|             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) | ||||||
|                     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) | ||||||
|                 if content.get("migrate"): |  | ||||||
|             downgrade_query_list = content.get("downgrade") |             downgrade_query_list = content.get("downgrade") | ||||||
|             for downgrade_query in downgrade_query_list: |             for downgrade_query in downgrade_query_list: | ||||||
|                 await conn.execute_query(downgrade_query) |                 await conn.execute_query(downgrade_query) | ||||||
|                 else: |             await last_version.delete() | ||||||
|                     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) |         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"] | ||||||
|  |     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) |             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.") | ||||||
| @@ -154,21 +161,23 @@ def history(ctx): | |||||||
| 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) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								aerich/ddl/postgres/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								aerich/ddl/postgres/__init__.py
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										8
									
								
								aerich/ddl/sqlite/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								aerich/ddl/sqlite/__init__.py
									
									
									
									
									
										Normal 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 | ||||||
| @@ -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
									
								
							
							
						
						
									
										9
									
								
								aerich/models.py
									
									
									
									
									
										Normal 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"] | ||||||
| @@ -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
									
								
							
							
						
						
									
										11
									
								
								conftest.py
									
									
									
									
									
										Normal 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
									
									
									
								
							
							
						
						
									
										327
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							| @@ -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"}, | ||||||
|  | ] | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										2
									
								
								pytest.ini
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | [pytest] | ||||||
|  | addopts = -p no:warnings --ignore=src | ||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								setup.cfg
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								setup.cfg
									
									
									
									
									
								
							| @@ -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 | ||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @@ -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(), | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -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"} | ||||||
|  |     }, | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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() |  | ||||||
| @@ -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") |  | ||||||
| @@ -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) |  | ||||||
| @@ -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
									
								
							
							
						
						
									
										114
									
								
								tests/test_ddl.py
									
									
									
									
									
										Normal 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") | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| from unittest import TestCase |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestUtils(TestCase): |  | ||||||
|     def test_get_app_connection(self): |  | ||||||
|         pass |  | ||||||
		Reference in New Issue
	
	Block a user