diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db88c07..75efb6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,9 +26,9 @@ jobs: with: python-version: '3.x' - name: Install and configure Poetry - uses: snok/install-poetry@v1.1.1 - with: - virtualenvs-create: false + run: | + pip install -U pip poetry + poetry config virtualenvs.create false - name: CI env: MYSQL_PASS: root diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 3ee17f3..c07d631 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -12,9 +12,9 @@ jobs: with: python-version: '3.x' - name: Install and configure Poetry - uses: snok/install-poetry@v1.1.1 - with: - virtualenvs-create: false + run: | + pip install -U pip poetry + poetry config virtualenvs.create false - name: Build dists run: make build - name: Pypi Publish diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fb2137..490d4f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ ## 0.6 +### 0.6.4 + +- Improve `inspectdb` adding support to `postgresql::numeric` data type +- Add support for dynamically load DDL classes easing to add support to + new databases without changing `Migrate` class logic +- Fix decimal field change. (#246) +- Support add/remove field with index. + +### 0.6.3 + +- Improve `inspectdb` and support `postgres` & `sqlite`. + +### 0.6.2 + +- Support migration for specified index. (#203) + +### 0.6.1 + +- Fix `pyproject.toml` not existing error. (#217) + ### 0.6.0 - Change default config file from `aerich.ini` to `pyproject.toml`. (#197) @@ -10,6 +30,7 @@ 1. Run `aerich init -t config.TORTOISE_ORM`. 2. Remove `aerich.ini`. - Remove `pydantic` dependency. (#198) +- `inspectdb` support `DATE`. (#215) ## 0.5 diff --git a/Makefile b/Makefile index e5124f2..1522fdf 100644 --- a/Makefile +++ b/Makefile @@ -12,16 +12,15 @@ up: @poetry update deps: - @poetry install -E asyncpg -E asyncmy -E aiomysql + @poetry install -E asyncpg -E asyncmy style: deps - isort -src $(checkfiles) - black $(black_opts) $(checkfiles) + @isort -src $(checkfiles) + @black $(black_opts) $(checkfiles) check: deps - black --check $(black_opts) $(checkfiles) || (echo "Please run 'make style' to auto-fix style issues" && false) - flake8 $(checkfiles) - bandit -x tests -r $(checkfiles) + @black --check $(black_opts) $(checkfiles) || (echo "Please run 'make style' to auto-fix style issues" && false) + @pflake8 $(checkfiles) test: deps $(py_warn) TEST_DB=sqlite://:memory: py.test diff --git a/README.md b/README.md index 439c05e..7456d46 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Introduction -Aerich is a database migrations tool for Tortoise-ORM, which is like alembic for SQLAlchemy, or like Django ORM with +Aerich is a database migrations tool for TortoiseORM, which is like alembic for SQLAlchemy, or like Django ORM with it\'s own migration solution. ## Install @@ -165,7 +165,7 @@ Now your db is rolled back to the specified version. ### Inspect db tables to TortoiseORM model -Currently `inspectdb` only supports MySQL. +Currently `inspectdb` support MySQL & Postgres & SQLite. ```shell Usage: aerich inspectdb [OPTIONS] @@ -189,7 +189,44 @@ Inspect a specified table in the default app and redirect to `models.py`: aerich inspectdb -t user > models.py ``` -Note that this command is limited and cannot infer some fields, such as `IntEnumField`, `ForeignKeyField`, and others. +For example, you table is: + +```sql +CREATE TABLE `test` +( + `id` int NOT NULL AUTO_INCREMENT, + `decimal` decimal(10, 2) NOT NULL, + `date` date DEFAULT NULL, + `datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `time` time DEFAULT NULL, + `float` float DEFAULT NULL, + `string` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL, + `tinyint` tinyint DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `asyncmy_string_index` (`string`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci +``` + +Now run `aerich inspectdb -t test` to see the generated model: + +```python +from tortoise import Model, fields + + +class Test(Model): + date = fields.DateField(null=True, ) + datetime = fields.DatetimeField(auto_now=True, ) + decimal = fields.DecimalField(max_digits=10, decimal_places=2, ) + float = fields.FloatField(null=True, ) + id = fields.IntField(pk=True, ) + string = fields.CharField(max_length=200, null=True, ) + time = fields.TimeField(null=True, ) + tinyint = fields.BooleanField(null=True, ) +``` + +Note that this command is limited and can't infer some fields, such as `IntEnumField`, `ForeignKeyField`, and others. ### Multiple databases diff --git a/aerich/__init__.py b/aerich/__init__.py index f9f4e26..7e256ed 100644 --- a/aerich/__init__.py +++ b/aerich/__init__.py @@ -8,7 +8,9 @@ from tortoise.transactions import in_transaction from tortoise.utils import get_schema_sql from aerich.exceptions import DowngradeError -from aerich.inspectdb import InspectDb +from aerich.inspectdb.mysql import InspectMySQL +from aerich.inspectdb.postgres import InspectPostgres +from aerich.inspectdb.sqlite import InspectSQLite from aerich.migrate import Migrate from aerich.models import Aerich from aerich.utils import ( @@ -103,10 +105,19 @@ class Command: versions = Migrate.get_all_version_files() return [version for version in versions] - async def inspectdb(self, tables: List[str]): + async def inspectdb(self, tables: List[str] = None) -> str: connection = get_app_connection(self.tortoise_config, self.app) - inspect = InspectDb(connection, tables) - await inspect.inspect() + dialect = connection.schema_generator.DIALECT + if dialect == "mysql": + cls = InspectMySQL + elif dialect == "postgres": + cls = InspectPostgres + elif dialect == "sqlite": + cls = InspectSQLite + else: + raise NotImplementedError(f"{dialect} is not supported") + inspect = cls(connection, tables) + return await inspect.inspect() async def migrate(self, name: str = "update"): return await Migrate.migrate(name) diff --git a/aerich/cli.py b/aerich/cli.py index 458a923..564dfca 100644 --- a/aerich/cli.py +++ b/aerich/cli.py @@ -10,12 +10,11 @@ from click import Context, UsageError from tomlkit.exceptions import NonExistentKey from tortoise import Tortoise +from aerich import Command +from aerich.enums import Color from aerich.exceptions import DowngradeError from aerich.utils import add_src_path, get_tortoise_config - -from . import Command -from .enums import Color -from .version import __version__ +from aerich.version import __version__ CONFIG_DEFAULT_VALUES = { "src_folder": ".", @@ -27,11 +26,11 @@ def coro(f): def wrapper(*args, **kwargs): loop = asyncio.get_event_loop() - # Close db connections at the end of all all but the cli group function + # Close db connections at the end of all but the cli group function try: loop.run_until_complete(f(*args, **kwargs)) finally: - if f.__name__ != "cli": + if f.__name__ not in ["cli", "init_db"]: loop.run_until_complete(Tortoise.close_connections()) return wrapper @@ -55,10 +54,10 @@ async def cli(ctx: Context, config, app): invoked_subcommand = ctx.invoked_subcommand if invoked_subcommand != "init": - if not Path(config).exists(): + config_path = Path(config) + if not config_path.exists(): raise UsageError("You must exec init first", ctx=ctx) - with open(config, "r") as f: - content = f.read() + content = config_path.read_text() doc = tomlkit.parse(content) try: tool = doc["tool"]["aerich"] @@ -193,18 +192,19 @@ async def init(ctx: Context, tortoise_orm, location, src_folder): # check that we can find the configuration, if not we can fail before the config file gets created add_src_path(src_folder) get_tortoise_config(ctx, tortoise_orm) - - with open(config_file, "r") as f: - content = f.read() - doc = tomlkit.parse(content) + config_path = Path(config_file) + if config_path.exists(): + content = config_path.read_text() + doc = tomlkit.parse(content) + else: + doc = tomlkit.parse("[tool.aerich]") table = tomlkit.table() table["tortoise_orm"] = tortoise_orm table["location"] = location table["src_folder"] = src_folder doc["tool"]["aerich"] = table - with open(config_file, "w") as f: - f.write(tomlkit.dumps(doc)) + config_path.write_text(tomlkit.dumps(doc)) Path(location).mkdir(parents=True, exist_ok=True) @@ -214,15 +214,17 @@ async def init(ctx: Context, tortoise_orm, location, src_folder): @cli.command(help="Generate schema and generate app migrate location.") @click.option( + "-s", "--safe", type=bool, + is_flag=True, default=True, help="When set to true, creates the table only when it does not already exist.", show_default=True, ) @click.pass_context @coro -async def init_db(ctx: Context, safe): +async def init_db(ctx: Context, safe: bool): command = ctx.obj["command"] app = command.app dirname = Path(command.location, app) @@ -248,7 +250,8 @@ async def init_db(ctx: Context, safe): @coro async def inspectdb(ctx: Context, table: List[str]): command = ctx.obj["command"] - await command.inspectdb(table) + ret = await command.inspectdb(table) + click.secho(ret) def main(): diff --git a/aerich/coder.py b/aerich/coder.py new file mode 100644 index 0000000..3501c24 --- /dev/null +++ b/aerich/coder.py @@ -0,0 +1,31 @@ +import base64 +import json +import pickle # nosec: B301,B403 + +from tortoise.indexes import Index + + +class JsonEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Index): + return { + "type": "index", + "val": base64.b64encode(pickle.dumps(obj)).decode(), # nosec: B301 + } + else: + return super().default(obj) + + +def object_hook(obj): + _type = obj.get("type") + if not _type: + return obj + return pickle.loads(base64.b64decode(obj["val"])) # nosec: B301 + + +def encoder(obj: dict): + return json.dumps(obj, cls=JsonEncoder) + + +def decoder(obj: str): + return json.loads(obj, object_hook=object_hook) diff --git a/aerich/ddl/__init__.py b/aerich/ddl/__init__.py index ed94ffc..422287e 100644 --- a/aerich/ddl/__init__.py +++ b/aerich/ddl/__init__.py @@ -78,15 +78,11 @@ class BaseDDL: auto_now_add = field_describe.get("auto_now_add", False) auto_now = field_describe.get("auto_now", False) if default is not None or auto_now_add: - if ( - field_describe.get("field_type") - in [ - "UUIDField", - "TextField", - "JSONField", - ] - or is_default_function(default) - ): + if field_describe.get("field_type") in [ + "UUIDField", + "TextField", + "JSONField", + ] or is_default_function(default): default = "" else: try: @@ -195,6 +191,12 @@ class BaseDDL: table_name=model._meta.db_table, ) + def drop_index_by_name(self, model: "Type[Model]", index_name: str): + return self._DROP_INDEX_TEMPLATE.format( + index_name=index_name, + table_name=model._meta.db_table, + ) + def add_fk(self, model: "Type[Model]", field_describe: dict, reference_table_describe: dict): db_table = model._meta.db_table diff --git a/aerich/inspectdb.py b/aerich/inspectdb.py deleted file mode 100644 index b2eb3aa..0000000 --- a/aerich/inspectdb.py +++ /dev/null @@ -1,86 +0,0 @@ -import sys -from typing import List, Optional - -from ddlparse import DdlParse -from tortoise import BaseDBAsyncClient - - -class InspectDb: - _table_template = "class {table}(Model):\n" - _field_template_mapping = { - "INT": " {field} = fields.IntField({pk}{unique}{comment})", - "SMALLINT": " {field} = fields.IntField({pk}{unique}{comment})", - "TINYINT": " {field} = fields.BooleanField({null}{default}{comment})", - "VARCHAR": " {field} = fields.CharField({pk}{unique}{length}{null}{default}{comment})", - "LONGTEXT": " {field} = fields.TextField({null}{default}{comment})", - "TEXT": " {field} = fields.TextField({null}{default}{comment})", - "DATETIME": " {field} = fields.DatetimeField({null}{default}{comment})", - "FLOAT": " {field} = fields.FloatField({null}{default}{comment})", - } - - def __init__(self, conn: BaseDBAsyncClient, tables: Optional[List[str]] = None): - self.conn = conn - self.tables = tables - self.DIALECT = conn.schema_generator.DIALECT - - async def show_create_tables(self): - if self.DIALECT == "mysql": - if not self.tables: - sql_tables = f"SELECT table_name FROM information_schema.tables WHERE table_schema = '{self.conn.database}';" # nosec: B608 - ret = await self.conn.execute_query(sql_tables) - self.tables = map(lambda x: x["TABLE_NAME"], ret[1]) - for table in self.tables: - sql_show_create_table = f"SHOW CREATE TABLE {table}" - ret = await self.conn.execute_query(sql_show_create_table) - yield ret[1][0]["Create Table"] - else: - raise NotImplementedError("Currently only support MySQL") - - async def inspect(self): - ddl_list = self.show_create_tables() - result = "from tortoise import Model, fields\n\n\n" - tables = [] - async for ddl in ddl_list: - parser = DdlParse(ddl, DdlParse.DATABASE.mysql) - table = parser.parse() - name = table.name.title() - columns = table.columns - fields = [] - model = self._table_template.format(table=name) - for column_name, column in columns.items(): - comment = default = length = unique = null = pk = "" - if column.primary_key: - pk = "pk=True, " - if column.unique: - unique = "unique=True, " - if column.data_type == "VARCHAR": - length = f"max_length={column.length}, " - if not column.not_null: - null = "null=True, " - if column.default is not None: - if column.data_type == "TINYINT": - default = f"default={'True' if column.default == '1' else 'False'}, " - elif column.data_type == "DATETIME": - if "CURRENT_TIMESTAMP" in column.default: - if "ON UPDATE CURRENT_TIMESTAMP" in ddl: - default = "auto_now_add=True, " - else: - default = "auto_now=True, " - else: - default = f"default={column.default}, " - - if column.comment: - comment = f"description='{column.comment}', " - - field = self._field_template_mapping[column.data_type].format( - field=column_name, - pk=pk, - unique=unique, - length=length, - null=null, - default=default, - comment=comment, - ) - fields.append(field) - tables.append(model + "\n".join(fields)) - sys.stdout.write(result + "\n\n\n".join(tables)) diff --git a/aerich/inspectdb/__init__.py b/aerich/inspectdb/__init__.py new file mode 100644 index 0000000..16da8ec --- /dev/null +++ b/aerich/inspectdb/__init__.py @@ -0,0 +1,168 @@ +from typing import Any, List, Optional + +from pydantic import BaseModel +from tortoise import BaseDBAsyncClient + + +class Column(BaseModel): + name: str + data_type: str + null: bool + default: Any + comment: Optional[str] + pk: bool + unique: bool + index: bool + length: Optional[int] + extra: Optional[str] + decimal_places: Optional[int] + max_digits: Optional[int] + + def translate(self) -> dict: + comment = default = length = index = null = pk = "" + if self.pk: + pk = "pk=True, " + else: + if self.unique: + index = "unique=True, " + else: + if self.index: + index = "index=True, " + if self.data_type in ["varchar", "VARCHAR"]: + length = f"max_length={self.length}, " + if self.data_type in ["decimal", "numeric"]: + length_parts = [] + if self.max_digits: + length_parts.append(f"max_digits={self.max_digits}") + if self.decimal_places: + length_parts.append(f"decimal_places={self.decimal_places}") + length = ", ".join(length_parts) + if self.null: + null = "null=True, " + if self.default is not None: + if self.data_type in ["tinyint", "INT"]: + default = f"default={'True' if self.default == '1' else 'False'}, " + elif self.data_type == "bool": + default = f"default={'True' if self.default == 'true' else 'False'}, " + elif self.data_type in ["datetime", "timestamptz", "TIMESTAMP"]: + if "CURRENT_TIMESTAMP" == self.default: + if "DEFAULT_GENERATED on update CURRENT_TIMESTAMP" == self.extra: + default = "auto_now=True, " + else: + default = "auto_now_add=True, " + else: + if "::" in self.default: + default = f"default={self.default.split('::')[0]}, " + elif self.default.endswith("()"): + default = "" + else: + default = f"default={self.default}, " + + if self.comment: + comment = f"description='{self.comment}', " + return { + "name": self.name, + "pk": pk, + "index": index, + "null": null, + "default": default, + "length": length, + "comment": comment, + } + + +class Inspect: + _table_template = "class {table}(Model):\n" + + def __init__(self, conn: BaseDBAsyncClient, tables: Optional[List[str]] = None): + self.conn = conn + try: + self.database = conn.database + except AttributeError: + pass + self.tables = tables + + @property + def field_map(self) -> dict: + raise NotImplementedError + + async def inspect(self) -> str: + if not self.tables: + self.tables = await self.get_all_tables() + result = "from tortoise import Model, fields\n\n\n" + tables = [] + for table in self.tables: + columns = await self.get_columns(table) + fields = [] + model = self._table_template.format(table=table.title().replace("_", "")) + for column in columns: + field = self.field_map[column.data_type](**column.translate()) + fields.append(" " + field) + tables.append(model + "\n".join(fields)) + return result + "\n\n\n".join(tables) + + async def get_columns(self, table: str) -> List[Column]: + raise NotImplementedError + + async def get_all_tables(self) -> List[str]: + raise NotImplementedError + + @classmethod + def decimal_field(cls, **kwargs) -> str: + return "{name} = fields.DecimalField({pk}{index}{length}{null}{default}{comment})".format( + **kwargs + ) + + @classmethod + def time_field(cls, **kwargs) -> str: + return "{name} = fields.TimeField({null}{default}{comment})".format(**kwargs) + + @classmethod + def date_field(cls, **kwargs) -> str: + return "{name} = fields.DateField({null}{default}{comment})".format(**kwargs) + + @classmethod + def float_field(cls, **kwargs) -> str: + return "{name} = fields.FloatField({null}{default}{comment})".format(**kwargs) + + @classmethod + def datetime_field(cls, **kwargs) -> str: + return "{name} = fields.DatetimeField({null}{default}{comment})".format(**kwargs) + + @classmethod + def text_field(cls, **kwargs) -> str: + return "{name} = fields.TextField({null}{default}{comment})".format(**kwargs) + + @classmethod + def char_field(cls, **kwargs) -> str: + return "{name} = fields.CharField({pk}{index}{length}{null}{default}{comment})".format( + **kwargs + ) + + @classmethod + def int_field(cls, **kwargs) -> str: + return "{name} = fields.IntField({pk}{index}{comment})".format(**kwargs) + + @classmethod + def smallint_field(cls, **kwargs) -> str: + return "{name} = fields.SmallIntField({pk}{index}{comment})".format(**kwargs) + + @classmethod + def bigint_field(cls, **kwargs) -> str: + return "{name} = fields.BigIntField({pk}{index}{default}{comment})".format(**kwargs) + + @classmethod + def bool_field(cls, **kwargs) -> str: + return "{name} = fields.BooleanField({null}{default}{comment})".format(**kwargs) + + @classmethod + def uuid_field(cls, **kwargs) -> str: + return "{name} = fields.UUIDField({pk}{index}{default}{comment})".format(**kwargs) + + @classmethod + def json_field(cls, **kwargs) -> str: + return "{name} = fields.JSONField({null}{default}{comment})".format(**kwargs) + + @classmethod + def binary_field(cls, **kwargs) -> str: + return "{name} = fields.BinaryField({null}{default}{comment})".format(**kwargs) diff --git a/aerich/inspectdb/mysql.py b/aerich/inspectdb/mysql.py new file mode 100644 index 0000000..64dc2ba --- /dev/null +++ b/aerich/inspectdb/mysql.py @@ -0,0 +1,69 @@ +from typing import List + +from aerich.inspectdb import Column, Inspect + + +class InspectMySQL(Inspect): + @property + def field_map(self) -> dict: + return { + "int": self.int_field, + "smallint": self.smallint_field, + "tinyint": self.bool_field, + "bigint": self.bigint_field, + "varchar": self.char_field, + "longtext": self.text_field, + "text": self.text_field, + "datetime": self.datetime_field, + "float": self.float_field, + "date": self.date_field, + "time": self.time_field, + "decimal": self.decimal_field, + "json": self.json_field, + "longblob": self.binary_field, + } + + async def get_all_tables(self) -> List[str]: + sql = "select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=%s" + ret = await self.conn.execute_query_dict(sql, [self.database]) + return list(map(lambda x: x["TABLE_NAME"], ret)) + + async def get_columns(self, table: str) -> List[Column]: + columns = [] + sql = """select c.*, s.NON_UNIQUE, s.INDEX_NAME +from information_schema.COLUMNS c + left join information_schema.STATISTICS s on c.TABLE_NAME = s.TABLE_NAME + and c.TABLE_SCHEMA = s.TABLE_SCHEMA + and c.COLUMN_NAME = s.COLUMN_NAME +where c.TABLE_SCHEMA = %s + and c.TABLE_NAME = %s""" + ret = await self.conn.execute_query_dict(sql, [self.database, table]) + for row in ret: + non_unique = row["NON_UNIQUE"] + if non_unique is None: + unique = False + else: + unique = not non_unique + index_name = row["INDEX_NAME"] + if index_name is None: + index = False + else: + index = row["INDEX_NAME"] != "PRIMARY" + columns.append( + Column( + name=row["COLUMN_NAME"], + data_type=row["DATA_TYPE"], + null=row["IS_NULLABLE"] == "YES", + default=row["COLUMN_DEFAULT"], + pk=row["COLUMN_KEY"] == "PRI", + comment=row["COLUMN_COMMENT"], + unique=row["COLUMN_KEY"] == "UNI", + extra=row["EXTRA"], + unque=unique, + index=index, + length=row["CHARACTER_MAXIMUM_LENGTH"], + max_digits=row["NUMERIC_PRECISION"], + decimal_places=row["NUMERIC_SCALE"], + ) + ) + return columns diff --git a/aerich/inspectdb/postgres.py b/aerich/inspectdb/postgres.py new file mode 100644 index 0000000..0f22bb1 --- /dev/null +++ b/aerich/inspectdb/postgres.py @@ -0,0 +1,76 @@ +from typing import List, Optional + +from tortoise import BaseDBAsyncClient + +from aerich.inspectdb import Column, Inspect + + +class InspectPostgres(Inspect): + def __init__(self, conn: BaseDBAsyncClient, tables: Optional[List[str]] = None): + super().__init__(conn, tables) + self.schema = self.conn.server_settings.get("schema") or "public" + + @property + def field_map(self) -> dict: + return { + "int4": self.int_field, + "int8": self.int_field, + "smallint": self.smallint_field, + "varchar": self.char_field, + "text": self.text_field, + "bigint": self.bigint_field, + "timestamptz": self.datetime_field, + "float4": self.float_field, + "float8": self.float_field, + "date": self.date_field, + "time": self.time_field, + "decimal": self.decimal_field, + "numeric": self.decimal_field, + "uuid": self.uuid_field, + "jsonb": self.json_field, + "bytea": self.binary_field, + "bool": self.bool_field, + "timestamp": self.datetime_field, + } + + async def get_all_tables(self) -> List[str]: + sql = "select TABLE_NAME from information_schema.TABLES where table_catalog=$1 and table_schema=$2" + ret = await self.conn.execute_query_dict(sql, [self.database, self.schema]) + return list(map(lambda x: x["table_name"], ret)) + + async def get_columns(self, table: str) -> List[Column]: + columns = [] + sql = f"""select c.column_name, + col_description('public.{table}'::regclass, ordinal_position) as column_comment, + t.constraint_type as column_key, + udt_name as data_type, + is_nullable, + column_default, + character_maximum_length, + numeric_precision, + numeric_scale +from information_schema.constraint_column_usage const + join information_schema.table_constraints t + using (table_catalog, table_schema, table_name, constraint_catalog, constraint_schema, constraint_name) + right join information_schema.columns c using (column_name, table_catalog, table_schema, table_name) +where c.table_catalog = $1 + and c.table_name = $2 + and c.table_schema = $3""" + ret = await self.conn.execute_query_dict(sql, [self.database, table, self.schema]) + for row in ret: + columns.append( + Column( + name=row["column_name"], + data_type=row["data_type"], + null=row["is_nullable"] == "YES", + default=row["column_default"], + length=row["character_maximum_length"], + max_digits=row["numeric_precision"], + decimal_places=row["numeric_scale"], + comment=row["column_comment"], + pk=row["column_key"] == "PRIMARY KEY", + unique=False, # can't get this simply + index=False, # can't get this simply + ) + ) + return columns diff --git a/aerich/inspectdb/sqlite.py b/aerich/inspectdb/sqlite.py new file mode 100644 index 0000000..7f35e1f --- /dev/null +++ b/aerich/inspectdb/sqlite.py @@ -0,0 +1,61 @@ +from typing import List + +from aerich.inspectdb import Column, Inspect + + +class InspectSQLite(Inspect): + @property + def field_map(self) -> dict: + return { + "INTEGER": self.int_field, + "INT": self.bool_field, + "SMALLINT": self.smallint_field, + "VARCHAR": self.char_field, + "TEXT": self.text_field, + "TIMESTAMP": self.datetime_field, + "REAL": self.float_field, + "BIGINT": self.bigint_field, + "DATE": self.date_field, + "TIME": self.time_field, + "JSON": self.json_field, + "BLOB": self.binary_field, + } + + async def get_columns(self, table: str) -> List[Column]: + columns = [] + sql = f"PRAGMA table_info({table})" + ret = await self.conn.execute_query_dict(sql) + columns_index = await self._get_columns_index(table) + for row in ret: + try: + length = row["type"].split("(")[1].split(")")[0] + except IndexError: + length = None + columns.append( + Column( + name=row["name"], + data_type=row["type"].split("(")[0], + null=row["notnull"] == 0, + default=row["dflt_value"], + length=length, + pk=row["pk"] == 1, + unique=columns_index.get(row["name"]) == "unique", + index=columns_index.get(row["name"]) == "index", + ) + ) + return columns + + async def _get_columns_index(self, table: str): + sql = f"PRAGMA index_list ({table})" + indexes = await self.conn.execute_query_dict(sql) + ret = {} + for index in indexes: + sql = f"PRAGMA index_info({index['name']})" + index_info = (await self.conn.execute_query_dict(sql))[0] + ret[index_info["name"]] = "unique" if index["unique"] else "index" + return ret + + async def get_all_tables(self) -> List[str]: + sql = "select tbl_name from sqlite_master where type='table' and name!='sqlite_sequence'" + ret = await self.conn.execute_query_dict(sql) + return list(map(lambda x: x["tbl_name"], ret)) diff --git a/aerich/migrate.py b/aerich/migrate.py index ab2f361..a38b973 100644 --- a/aerich/migrate.py +++ b/aerich/migrate.py @@ -1,12 +1,15 @@ +import importlib import os from datetime import datetime +from hashlib import md5 from pathlib import Path -from typing import Dict, List, Optional, Tuple, Type +from typing import Dict, List, Optional, Tuple, Type, Union import click from dictdiffer import diff from tortoise import BaseDBAsyncClient, Model, Tortoise from tortoise.exceptions import OperationalError +from tortoise.indexes import Index from aerich.ddl import BaseDDL from aerich.models import MAX_VERSION_LENGTH, Aerich @@ -32,7 +35,7 @@ class Migrate: ddl: BaseDDL _last_version_content: Optional[dict] = None app: str - migrate_location: str + migrate_location: Path dialect: str _db_version: Optional[str] = None @@ -61,6 +64,11 @@ class Migrate: ret = await connection.execute_query(sql) cls._db_version = ret[1][0].get("version") + @classmethod + async def load_ddl_class(cls): + ddl_dialect_module = importlib.import_module(f"aerich.ddl.{cls.dialect}") + return getattr(ddl_dialect_module, f"{cls.dialect.capitalize()}DDL") + @classmethod async def init(cls, config: dict, app: str, location: str): await Tortoise.init(config=config) @@ -72,18 +80,8 @@ class Migrate: connection = get_app_connection(config, app) cls.dialect = connection.schema_generator.DIALECT - if cls.dialect == "mysql": - from aerich.ddl.mysql import MysqlDDL - - cls.ddl = MysqlDDL(connection) - elif cls.dialect == "sqlite": - from aerich.ddl.sqlite import SqliteDDL - - cls.ddl = SqliteDDL(connection) - elif cls.dialect == "postgres": - from aerich.ddl.postgres import PostgresDDL - - cls.ddl = PostgresDDL(connection) + cls.ddl_class = await cls.load_ddl_class() + cls.ddl = cls.ddl_class(connection) await cls._get_db_version(connection) @classmethod @@ -157,6 +155,18 @@ class Migrate: else: cls.downgrade_operators.append(operator) + @classmethod + def _handle_indexes(cls, model: Type[Model], indexes: List[Union[Tuple[str], Index]]): + ret = [] + for index in indexes: + if isinstance(index, Index): + index.__hash__ = lambda self: md5( # nosec: B303 + self.index_name(cls.ddl.schema_generator, model).encode() + + self.__class__.__name__.encode() + ).hexdigest() + ret.append(index) + return ret + @classmethod def diff_models(cls, old_models: Dict[str, dict], new_models: Dict[str, dict], upgrade=True): """ @@ -192,8 +202,18 @@ class Migrate: new_unique_together = set( map(lambda x: tuple(x), new_model_describe.get("unique_together")) ) - old_indexes = set(map(lambda x: tuple(x), old_model_describe.get("indexes", []))) - new_indexes = set(map(lambda x: tuple(x), new_model_describe.get("indexes", []))) + old_indexes = set( + map( + lambda x: x if isinstance(x, Index) else tuple(x), + cls._handle_indexes(model, old_model_describe.get("indexes", [])), + ) + ) + new_indexes = set( + map( + lambda x: x if isinstance(x, Index) else tuple(x), + cls._handle_indexes(model, new_model_describe.get("indexes", [])), + ) + ) old_pk_field = old_model_describe.get("pk_field") new_pk_field = new_model_describe.get("pk_field") # pk field @@ -323,26 +343,44 @@ class Migrate: ), upgrade, ) + if new_data_field["indexed"]: + cls._add_operator( + cls._add_index( + model, {new_data_field["db_column"]}, new_data_field["unique"] + ), + upgrade, + True, + ) # remove fields for old_data_field_name in set(old_data_fields_name).difference( set(new_data_fields_name) ): - # don't remove field if is rename + # don't remove field if is renamed if (upgrade and old_data_field_name in cls._rename_old) or ( not upgrade and old_data_field_name in cls._rename_new ): continue + old_data_field = next( + filter(lambda x: x.get("name") == old_data_field_name, old_data_fields) + ) + db_column = old_data_field["db_column"] cls._add_operator( cls._remove_field( model, - next( - filter( - lambda x: x.get("name") == old_data_field_name, old_data_fields - ) - ).get("db_column"), + db_column, ), upgrade, ) + if old_data_field["indexed"]: + cls._add_operator( + cls._drop_index( + model, + {db_column}, + ), + upgrade, + True, + ) + old_fk_fields = old_model_describe.get("fk_fields") new_fk_fields = new_model_describe.get("fk_fields") @@ -402,8 +440,14 @@ class Migrate: cls._drop_index(model, (field_name,), unique), upgrade, True ) elif option == "db_field_types.": - # continue since repeated with others - continue + if new_data_field.get("field_type") == "DecimalField": + # modify column + cls._add_operator( + cls._modify_field(model, new_data_field), + upgrade, + ) + else: + continue elif option == "default": if not ( is_default_function(old_new[0]) or is_default_function(old_new[1]) @@ -463,12 +507,18 @@ class Migrate: return ret @classmethod - def _drop_index(cls, model: Type[Model], fields_name: Tuple[str], unique=False): + def _drop_index(cls, model: Type[Model], fields_name: Union[Tuple[str], Index], unique=False): + if isinstance(fields_name, Index): + return cls.ddl.drop_index_by_name( + model, fields_name.index_name(cls.ddl.schema_generator, model) + ) fields_name = cls._resolve_fk_fields_name(model, fields_name) return cls.ddl.drop_index(model, fields_name, unique) @classmethod - def _add_index(cls, model: Type[Model], fields_name: Tuple[str], unique=False): + def _add_index(cls, model: Type[Model], fields_name: Union[Tuple[str], Index], unique=False): + if isinstance(fields_name, Index): + return fields_name.get_sql(cls.ddl.schema_generator, model, False) fields_name = cls._resolve_fk_fields_name(model, fields_name) return cls.ddl.add_index(model, fields_name, unique) diff --git a/aerich/models.py b/aerich/models.py index a689f03..baba77f 100644 --- a/aerich/models.py +++ b/aerich/models.py @@ -1,12 +1,15 @@ from tortoise import Model, fields +from aerich.coder import decoder, encoder + MAX_VERSION_LENGTH = 255 +MAX_APP_LENGTH = 100 class Aerich(Model): version = fields.CharField(max_length=MAX_VERSION_LENGTH) - app = fields.CharField(max_length=20) - content = fields.JSONField() + app = fields.CharField(max_length=MAX_APP_LENGTH) + content = fields.JSONField(encoder=encoder, decoder=decoder) class Meta: ordering = ["-id"] diff --git a/aerich/utils.py b/aerich/utils.py index eb86108..b51264b 100644 --- a/aerich/utils.py +++ b/aerich/utils.py @@ -87,19 +87,19 @@ def get_version_content_from_file(version_file: Union[str, Path]) -> Dict: :param version_file: :return: """ - with open(version_file, "r", encoding="utf-8") as f: - content = f.read() - first = content.index(_UPGRADE) - try: - second = content.index(_DOWNGRADE) - except ValueError: - second = len(content) - 1 - upgrade_content = content[first + len(_UPGRADE) : second].strip() # noqa:E203 - downgrade_content = content[second + len(_DOWNGRADE) :].strip() # noqa:E203 - return { - "upgrade": [line for line in upgrade_content.split(";\n") if line], - "downgrade": [line for line in downgrade_content.split(";\n") if line], - } + content = Path(version_file).read_text(encoding="utf-8") + first = content.index(_UPGRADE) + try: + second = content.index(_DOWNGRADE) + except ValueError: + second = len(content) - 1 + upgrade_content = content[first + len(_UPGRADE) : second].strip() # noqa:E203 + downgrade_content = content[second + len(_DOWNGRADE) :].strip() # noqa:E203 + ret = { + "upgrade": list(filter(lambda x: x or False, upgrade_content.split(";\n"))), + "downgrade": list(filter(lambda x: x or False, downgrade_content.split(";\n"))), + } + return ret def write_version_file(version_file: Path, content: Dict): @@ -109,25 +109,25 @@ def write_version_file(version_file: Path, content: Dict): :param content: :return: """ - with open(version_file, "w", encoding="utf-8") as f: - f.write(_UPGRADE) - upgrade = content.get("upgrade") - if len(upgrade) > 1: - f.write(";\n".join(upgrade)) - if not upgrade[-1].endswith(";"): - f.write(";\n") + text = _UPGRADE + upgrade = content.get("upgrade") + if len(upgrade) > 1: + text += ";\n".join(upgrade) + if not upgrade[-1].endswith(";"): + text += ";\n" + else: + text += f"{upgrade[0]}" + if not upgrade[0].endswith(";"): + text += ";" + text += "\n" + downgrade = content.get("downgrade") + if downgrade: + text += _DOWNGRADE + if len(downgrade) > 1: + text += ";\n".join(downgrade) + ";\n" else: - f.write(f"{upgrade[0]}") - if not upgrade[0].endswith(";"): - f.write(";") - f.write("\n") - downgrade = content.get("downgrade") - if downgrade: - f.write(_DOWNGRADE) - if len(downgrade) > 1: - f.write(";\n".join(downgrade) + ";\n") - else: - f.write(f"{downgrade[0]};\n") + text += f"{downgrade[0]};\n" + version_file.write_text(text, encoding="utf-8") def get_models_describe(app: str) -> Dict: diff --git a/aerich/version.py b/aerich/version.py index 906d362..364e7ba 100644 --- a/aerich/version.py +++ b/aerich/version.py @@ -1 +1 @@ -__version__ = "0.6.0" +__version__ = "0.6.4" diff --git a/poetry.lock b/poetry.lock index 12800c1..c446091 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,17 +1,3 @@ -[[package]] -name = "aiomysql" -version = "0.0.21" -description = "MySQL driver for asyncio." -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -PyMySQL = ">=0.9,<=0.9.3" - -[package.extras] -sa = ["sqlalchemy (>=1.0)"] - [[package]] name = "aiosqlite" version = "0.17.0" @@ -23,9 +9,17 @@ python-versions = ">=3.6" [package.dependencies] typing_extensions = ">=3.7.2" +[[package]] +name = "asyncmy" +version = "0.2.5" +description = "A fast asyncio MySQL driver" +category = "main" +optional = true +python-versions = ">=3.7,<4.0" + [[package]] name = "asyncpg" -version = "0.24.0" +version = "0.26.0" description = "An asyncio PostgreSQL driver" category = "main" optional = true @@ -41,7 +35,7 @@ test = ["pycodestyle (>=2.7.0,<2.8.0)", "flake8 (>=3.9.2,<3.10.0)", "uvloop (>=0 [[package]] name = "atomicwrites" -version = "1.4.0" +version = "1.4.1" description = "Atomic file writes." category = "dev" optional = false @@ -49,64 +43,63 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "21.2.0" +version = "22.1.0" description = "Classes Without Boilerplate" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.5" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"] [[package]] name = "bandit" -version = "1.7.0" +version = "1.7.4" description = "Security oriented static analyser for python code." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [package.dependencies] colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} GitPython = ">=1.0.1" PyYAML = ">=5.3.1" -six = ">=1.10.0" stevedore = ">=1.20.0" +[package.extras] +test = ["coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml", "beautifulsoup4 (>=4.8.0)", "pylint (==1.9.4)"] +toml = ["toml"] +yaml = ["pyyaml"] + [[package]] name = "black" -version = "21.9b0" +version = "22.6.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] -click = ">=7.1.2" +click = ">=8.0.0" mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0,<1" +pathspec = ">=0.9.0" platformdirs = ">=2" -regex = ">=2020.1.8" -tomli = ">=0.2.6,<2.0.0" -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""} -typing-extensions = [ - {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, - {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, -] +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -python2 = ["typed-ast (>=1.4.2)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "cffi" -version = "1.14.6" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "dev" optional = false @@ -117,11 +110,11 @@ pycparser = "*" [[package]] name = "click" -version = "8.0.1" +version = "8.1.3" description = "Composable command line interface toolkit" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -129,7 +122,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" -version = "0.4.4" +version = "0.4.5" description = "Cross-platform colored terminal text." category = "main" optional = false @@ -137,7 +130,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "cryptography" -version = "35.0.0" +version = "37.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "dev" optional = false @@ -148,22 +141,11 @@ cffi = ">=1.12" [package.extras] docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] -docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] sdist = ["setuptools_rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] - -[[package]] -name = "ddlparse" -version = "1.10.0" -description = "DDL parase and Convert to BigQuery JSON schema" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -pyparsing = "*" +test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] name = "dictdiffer" @@ -174,10 +156,10 @@ optional = false python-versions = "*" [package.extras] -all = ["Sphinx (>=3)", "sphinx-rtd-theme (>=0.2)", "check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "sphinx (>=3)", "tox (>=3.7.0)", "numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "pytest (==5.4.3)", "pytest-pycodestyle (>=2)", "pytest-pydocstyle (>=2)", "pytest (>=6)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2.2.0)", "numpy (>=1.20.0)"] -docs = ["Sphinx (>=3)", "sphinx-rtd-theme (>=0.2)"] -numpy = ["numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)"] -tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "sphinx (>=3)", "tox (>=3.7.0)", "pytest (==5.4.3)", "pytest-pycodestyle (>=2)", "pytest-pydocstyle (>=2)", "pytest (>=6)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2.2.0)"] +tests = ["pytest-pydocstyle (>=2.2.0)", "pytest-pycodestyle (>=2.2.0)", "pytest (>=6)", "pytest-pydocstyle (>=2)", "pytest-pycodestyle (>=2)", "pytest (==5.4.3)", "tox (>=3.7.0)", "sphinx (>=3)", "pytest-isort (>=1.2.0)", "pytest-cov (>=2.10.1)", "mock (>=1.3.0)", "check-manifest (>=0.42)"] +numpy = ["numpy (>=1.20.0)", "numpy (>=1.18.0)", "numpy (>=1.15.0)", "numpy (>=1.13.0)"] +docs = ["sphinx-rtd-theme (>=0.2)", "Sphinx (>=3)"] +all = ["numpy (>=1.20.0)", "pytest-pydocstyle (>=2.2.0)", "pytest-pycodestyle (>=2.2.0)", "pytest (>=6)", "pytest-pydocstyle (>=2)", "pytest-pycodestyle (>=2)", "pytest (==5.4.3)", "numpy (>=1.18.0)", "numpy (>=1.15.0)", "numpy (>=1.13.0)", "tox (>=3.7.0)", "sphinx (>=3)", "pytest-isort (>=1.2.0)", "pytest-cov (>=2.10.1)", "mock (>=1.3.0)", "check-manifest (>=0.42)", "sphinx-rtd-theme (>=0.2)", "Sphinx (>=3)"] [[package]] name = "execnet" @@ -192,32 +174,32 @@ testing = ["pre-commit"] [[package]] name = "flake8" -version = "3.9.2" +version = "4.0.1" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" [package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.7.0,<2.8.0" -pyflakes = ">=2.3.0,<2.4.0" +pycodestyle = ">=2.8.0,<2.9.0" +pyflakes = ">=2.4.0,<2.5.0" [[package]] name = "gitdb" -version = "4.0.7" +version = "4.0.9" description = "Git Object Database" category = "dev" optional = false -python-versions = ">=3.4" +python-versions = ">=3.6" [package.dependencies] -smmap = ">=3.0.1,<5" +smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.24" +version = "3.1.27" description = "GitPython is a python library used to interact with Git repositories" category = "dev" optional = false @@ -225,11 +207,11 @@ python-versions = ">=3.7" [package.dependencies] gitdb = ">=4.0.1,<5" -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} [[package]] name = "importlib-metadata" -version = "4.8.1" +version = "4.2.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -241,8 +223,7 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -perf = ["ipython"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -254,15 +235,15 @@ python-versions = "*" [[package]] name = "iso8601" -version = "0.1.16" +version = "1.0.2" description = "Simple module to parse ISO 8601 dates" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6.2,<4.0" [[package]] name = "isort" -version = "5.9.3" +version = "5.10.1" description = "A Python utility / library to sort Python imports." category = "dev" optional = false @@ -292,14 +273,14 @@ python-versions = "*" [[package]] name = "packaging" -version = "21.0" +version = "21.3" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pathspec" @@ -311,7 +292,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "pbr" -version = "5.6.0" +version = "5.10.0" description = "Python Build Reasonableness" category = "dev" optional = false @@ -319,15 +300,15 @@ python-versions = ">=2.6" [[package]] name = "platformdirs" -version = "2.4.0" +version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] [[package]] name = "pluggy" @@ -341,75 +322,94 @@ python-versions = ">=3.6" importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["pytest-benchmark", "pytest"] +dev = ["tox", "pre-commit"] [[package]] name = "py" -version = "1.10.0" +version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" 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.*, !=3.4.*" [[package]] name = "pycodestyle" -version = "2.7.0" +version = "2.8.0" description = "Python style guide checker" category = "dev" 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.*, !=3.4.*" [[package]] name = "pycparser" -version = "2.20" +version = "2.21" description = "C parser in Python" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pydantic" +version = "1.9.2" +description = "Data validation and settings management using python type hints" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +typing-extensions = ">=3.7.4.3" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + [[package]] name = "pyflakes" -version = "2.3.1" +version = "2.4.0" description = "passive checker of Python programs" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] -name = "pymysql" -version = "0.9.3" -description = "Pure Python MySQL Driver" -category = "main" -optional = true -python-versions = "*" +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "dev" +optional = false +python-versions = ">=3.6.8" [package.extras] -rsa = ["cryptography"] - -[[package]] -name = "pyparsing" -version = "2.4.7" -description = "Python parsing module" -category = "main" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pypika-tortoise" -version = "0.1.1" +version = "0.1.6" description = "Forked from pypika and streamline just for tortoise-orm" category = "main" optional = false python-versions = ">=3.7,<4.0" +[[package]] +name = "pyproject-flake8" +version = "0.0.1a5" +description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +flake8 = "<5.0.0" +tomli = {version = "*", markers = "python_version < \"3.11\""} + [[package]] name = "pytest" -version = "6.2.5" +version = "7.1.2" description = "pytest: simple powerful testing with Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} @@ -420,32 +420,33 @@ iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" py = ">=1.8.2" -toml = "*" +tomli = ">=1.0.0" [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.15.1" -description = "Pytest support for asyncio." +version = "0.19.0" +description = "Pytest support for asyncio" category = "dev" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.7" [package.dependencies] -pytest = ">=5.4.0" +pytest = ">=6.1.0" +typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""} [package.extras] -testing = ["coverage", "hypothesis (>=5.7.1)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] [[package]] name = "pytest-forked" -version = "1.3.0" +version = "1.4.0" description = "run tests in isolated forked subprocesses" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" [package.dependencies] py = "*" @@ -453,11 +454,11 @@ pytest = ">=3.10" [[package]] name = "pytest-mock" -version = "3.6.1" +version = "3.8.2" description = "Thin-wrapper around the mock package for easier use with pytest" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] pytest = ">=5.0" @@ -467,7 +468,7 @@ dev = ["pre-commit", "tox", "pytest-asyncio"] [[package]] name = "pytest-xdist" -version = "2.4.0" +version = "2.5.0" description = "pytest xdist plugin for distributed testing and loop-on-failing modes" category = "dev" optional = false @@ -475,7 +476,7 @@ python-versions = ">=3.6" [package.dependencies] execnet = ">=1.1" -pytest = ">=6.0.0" +pytest = ">=6.2.0" pytest-forked = "*" [package.extras] @@ -485,7 +486,7 @@ testing = ["filelock"] [[package]] name = "pytz" -version = "2021.3" +version = "2022.2.1" description = "World timezone definitions, modern and historical" category = "main" optional = false @@ -493,39 +494,23 @@ python-versions = "*" [[package]] name = "pyyaml" -version = "5.4.1" +version = "6.0" description = "YAML parser and emitter for Python" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" - -[[package]] -name = "regex" -version = "2021.9.30" -description = "Alternative regular expression module, to replace re." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.6" [[package]] name = "smmap" -version = "4.0.0" +version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [[package]] name = "stevedore" -version = "3.4.0" +version = "3.5.0" description = "Manage dynamic plugins for Python applications" category = "dev" optional = false @@ -535,33 +520,25 @@ python-versions = ">=3.6" importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} pbr = ">=2.0.0,<2.1.0 || >2.1.0" -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" - [[package]] name = "tomli" -version = "1.2.1" +version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "tomlkit" -version = "0.7.2" +version = "0.11.4" description = "Style preserving TOML library" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6,<4.0" [[package]] name = "tortoise-orm" -version = "0.17.7" +version = "0.19.2" description = "Easy async ORM for python, built with relations in mind" category = "main" optional = false @@ -569,426 +546,276 @@ python-versions = ">=3.7,<4.0" [package.dependencies] aiosqlite = ">=0.16.0,<0.18.0" -iso8601 = ">=0.1.13,<0.2.0" -pypika-tortoise = ">=0.1.1,<0.2.0" +iso8601 = ">=1.0.2,<2.0.0" +pypika-tortoise = ">=0.1.6,<0.2.0" pytz = "*" [package.extras] aiomysql = ["aiomysql"] -asyncmy = ["asyncmy"] +asyncmy = ["asyncmy (>=0.2.5,<0.3.0)"] +asyncodbc = ["asyncodbc (>=0.1.1,<0.2.0)"] asyncpg = ["asyncpg"] -accel = ["ciso8601 (>=2.1.2,<3.0.0)", "python-rapidjson", "uvloop (>=0.14.0,<0.15.0)"] +accel = ["ciso8601", "orjson", "uvloop"] +psycopg = ["psycopg"] [[package]] name = "typed-ast" -version = "1.4.3" +version = "1.5.4" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "3.10.0.2" -description = "Backported and Experimental Type Hints for Python 3.5+" +version = "4.3.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" [[package]] name = "zipp" -version = "3.6.0" +version = "3.8.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [extras] -aiomysql = ["aiomysql"] -asyncmy = [] +asyncmy = ["asyncmy"] asyncpg = ["asyncpg"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "defcd972418acf7c65f1430531ead43f06d0c35df8d359da845ce6d45068f4da" +content-hash = "37c6a73133abae4ce337962636160ae207f38b301b34ecfb6cb2547c3a25be3e" [metadata.files] -aiomysql = [ - {file = "aiomysql-0.0.21-py3-none-any.whl", hash = "sha256:a81a97da3dd732635926a8ea6adbbf2d1345799680bf61b5f89e730bcec88cc5"}, - {file = "aiomysql-0.0.21.tar.gz", hash = "sha256:811569c0db118dd2685f0878f5cebf17a11e89a995fa14261d5fa0254113842c"}, -] -aiosqlite = [ - {file = "aiosqlite-0.17.0-py3-none-any.whl", hash = "sha256:6c49dc6d3405929b1d08eeccc72306d3677503cc5e5e43771efc1e00232e8231"}, - {file = "aiosqlite-0.17.0.tar.gz", hash = "sha256:f0e6acc24bc4864149267ac82fb46dfb3be4455f99fe21df82609cc6e6baee51"}, -] +aiosqlite = [] +asyncmy = [] asyncpg = [ - {file = "asyncpg-0.24.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c4fc0205fe4ddd5aeb3dfdc0f7bafd43411181e1f5650189608e5971cceacff1"}, - {file = "asyncpg-0.24.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a7095890c96ba36f9f668eb552bb020dddb44f8e73e932f8573efc613ee83843"}, - {file = "asyncpg-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:8ff5073d4b654e34bd5eaadc01dc4d68b8a9609084d835acd364cd934190a08d"}, - {file = "asyncpg-0.24.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e36c6806883786b19551bb70a4882561f31135dc8105a59662e0376cf5b2cbc5"}, - {file = "asyncpg-0.24.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ddffcb85227bf39cd1bedd4603e0082b243cf3b14ced64dce506a15b05232b83"}, - {file = "asyncpg-0.24.0-cp37-cp37m-win_amd64.whl", hash = "sha256:41704c561d354bef01353835a7846e5606faabbeb846214dfcf666cf53319f18"}, - {file = "asyncpg-0.24.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29ef6ae0a617fc13cc2ac5dc8e9b367bb83cba220614b437af9b67766f4b6b20"}, - {file = "asyncpg-0.24.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eed43abc6ccf1dc02e0d0efc06ce46a411362f3358847c6b0ec9a43426f91ece"}, - {file = "asyncpg-0.24.0-cp38-cp38-win_amd64.whl", hash = "sha256:129d501f3d30616afd51eb8d3142ef51ba05374256bd5834cec3ef4956a9b317"}, - {file = "asyncpg-0.24.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a458fc69051fbb67d995fdda46d75a012b5d6200f91e17d23d4751482640ed4c"}, - {file = "asyncpg-0.24.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:556b0e92e2b75dc028b3c4bc9bd5162ddf0053b856437cf1f04c97f9c6837d03"}, - {file = "asyncpg-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:a738f4807c853623d3f93f0fea11f61be6b0e5ca16ea8aeb42c2c7ee742aa853"}, - {file = "asyncpg-0.24.0.tar.gz", hash = "sha256:dd2fa063c3344823487d9ddccb40802f02622ddf8bf8a6cc53885ee7a2c1c0c6"}, -] -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 = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, + {file = "asyncpg-0.26.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ed3880b3aec8bda90548218fe0914d251d641f798382eda39a17abfc4910af0"}, + {file = "asyncpg-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5bd99ee7a00e87df97b804f178f31086e88c8106aca9703b1d7be5078999e68"}, + {file = "asyncpg-0.26.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:868a71704262834065ca7113d80b1f679609e2df77d837747e3d92150dd5a39b"}, + {file = "asyncpg-0.26.0-cp310-cp310-win32.whl", hash = "sha256:838e4acd72da370ad07243898e886e93d3c0c9413f4444d600ba60a5cc206014"}, + {file = "asyncpg-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:a254d09a3a989cc1839ba2c34448b879cdd017b528a0cda142c92fbb6c13d957"}, + {file = "asyncpg-0.26.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3ecbe8ed3af4c739addbfbd78f7752866cce2c4e9cc3f953556e4960349ae360"}, + {file = "asyncpg-0.26.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ce7d8c0ab4639bbf872439eba86ef62dd030b245ad0e17c8c675d93d7a6b2d"}, + {file = "asyncpg-0.26.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7129bd809990fd119e8b2b9982e80be7712bb6041cd082be3e415e60e5e2e98f"}, + {file = "asyncpg-0.26.0-cp36-cp36m-win32.whl", hash = "sha256:03f44926fa7ff7ccd59e98f05c7e227e9de15332a7da5bbcef3654bf468ee597"}, + {file = "asyncpg-0.26.0-cp36-cp36m-win_amd64.whl", hash = "sha256:b1f7b173af649b85126429e11a628d01a5b75973d2a55d64dba19ad8f0e9f904"}, + {file = "asyncpg-0.26.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe056fd22fc6ed5c1ab353b6510808409566daac4e6f105e2043797f17b8dad"}, + {file = "asyncpg-0.26.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d96cf93e01df9fb03cef5f62346587805e6c0ca6f654c23b8d35315bdc69af59"}, + {file = "asyncpg-0.26.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:235205b60d4d014921f7b1cdca0e19669a9a8978f7606b3eb8237ca95f8e716e"}, + {file = "asyncpg-0.26.0-cp37-cp37m-win32.whl", hash = "sha256:0de408626cfc811ef04f372debfcdd5e4ab5aeb358f2ff14d1bdc246ed6272b5"}, + {file = "asyncpg-0.26.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f92d501bf213b16fabad4fbb0061398d2bceae30ddc228e7314c28dcc6641b79"}, + {file = "asyncpg-0.26.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9acb22a7b6bcca0d80982dce3d67f267d43e960544fb5dd934fd3abe20c48014"}, + {file = "asyncpg-0.26.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e550d8185f2c4725c1e8d3c555fe668b41bd092143012ddcc5343889e1c2a13d"}, + {file = "asyncpg-0.26.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:050e339694f8c5d9aebcf326ca26f6622ef23963a6a3a4f97aeefc743954afd5"}, + {file = "asyncpg-0.26.0-cp38-cp38-win32.whl", hash = "sha256:b0c3f39ebfac06848ba3f1e280cb1fada7cc1229538e3dad3146e8d1f9deb92a"}, + {file = "asyncpg-0.26.0-cp38-cp38-win_amd64.whl", hash = "sha256:49fc7220334cc31d14866a0b77a575d6a5945c0fa3bb67f17304e8b838e2a02b"}, + {file = "asyncpg-0.26.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d156e53b329e187e2dbfca8c28c999210045c45ef22a200b50de9b9e520c2694"}, + {file = "asyncpg-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b4051012ca75defa9a1dc6b78185ca58cdc3a247187eb76a6bcf55dfaa2fad4"}, + {file = "asyncpg-0.26.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d60f15a0ac18c54a6ca6507c28599c06e2e87a0901e7b548f15243d71905b18"}, + {file = "asyncpg-0.26.0-cp39-cp39-win32.whl", hash = "sha256:ede1a3a2c377fe12a3930f4b4dd5340e8b32929541d5db027a21816852723438"}, + {file = "asyncpg-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:8e1e79f0253cbd51fc43c4d0ce8804e46ee71f6c173fdc75606662ad18756b52"}, + {file = "asyncpg-0.26.0.tar.gz", hash = "sha256:77e684a24fee17ba3e487ca982d0259ed17bae1af68006f4cf284b23ba20ea2c"}, ] +atomicwrites = [] +attrs = [] bandit = [ - {file = "bandit-1.7.0-py3-none-any.whl", hash = "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07"}, - {file = "bandit-1.7.0.tar.gz", hash = "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"}, -] -black = [ - {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, - {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, + {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"}, + {file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"}, ] +black = [] cffi = [ - {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, - {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, - {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, - {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, - {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, - {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, - {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, - {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, - {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, - {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, - {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, - {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, - {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, - {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, - {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, - {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, -] -click = [ - {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, - {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, -] -colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, ] +click = [] +colorama = [] cryptography = [ - {file = "cryptography-35.0.0-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:d57e0cdc1b44b6cdf8af1d01807db06886f10177469312fbde8f44ccbb284bc9"}, - {file = "cryptography-35.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:ced40344e811d6abba00295ced98c01aecf0c2de39481792d87af4fa58b7b4d6"}, - {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:54b2605e5475944e2213258e0ab8696f4f357a31371e538ef21e8d61c843c28d"}, - {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7b7ceeff114c31f285528ba8b390d3e9cfa2da17b56f11d366769a807f17cbaa"}, - {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d69645f535f4b2c722cfb07a8eab916265545b3475fdb34e0be2f4ee8b0b15e"}, - {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2d0e0acc20ede0f06ef7aa58546eee96d2592c00f450c9acb89c5879b61992"}, - {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:07bb7fbfb5de0980590ddfc7f13081520def06dc9ed214000ad4372fb4e3c7f6"}, - {file = "cryptography-35.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7eba2cebca600a7806b893cb1d541a6e910afa87e97acf2021a22b32da1df52d"}, - {file = "cryptography-35.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:18d90f4711bf63e2fb21e8c8e51ed8189438e6b35a6d996201ebd98a26abbbe6"}, - {file = "cryptography-35.0.0-cp36-abi3-win32.whl", hash = "sha256:c10c797ac89c746e488d2ee92bd4abd593615694ee17b2500578b63cad6b93a8"}, - {file = "cryptography-35.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:7075b304cd567694dc692ffc9747f3e9cb393cc4aa4fb7b9f3abd6f5c4e43588"}, - {file = "cryptography-35.0.0-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a688ebcd08250eab5bb5bca318cc05a8c66de5e4171a65ca51db6bd753ff8953"}, - {file = "cryptography-35.0.0-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99915d6ab265c22873f1b4d6ea5ef462ef797b4140be4c9d8b179915e0985c6"}, - {file = "cryptography-35.0.0-pp36-pypy36_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:928185a6d1ccdb816e883f56ebe92e975a262d31cc536429041921f8cb5a62fd"}, - {file = "cryptography-35.0.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ebeddd119f526bcf323a89f853afb12e225902a24d29b55fe18dd6fcb2838a76"}, - {file = "cryptography-35.0.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22a38e96118a4ce3b97509443feace1d1011d0571fae81fc3ad35f25ba3ea999"}, - {file = "cryptography-35.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb80e8a1f91e4b7ef8b33041591e6d89b2b8e122d787e87eeb2b08da71bb16ad"}, - {file = "cryptography-35.0.0-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:abb5a361d2585bb95012a19ed9b2c8f412c5d723a9836418fab7aaa0243e67d2"}, - {file = "cryptography-35.0.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1ed82abf16df40a60942a8c211251ae72858b25b7421ce2497c2eb7a1cee817c"}, - {file = "cryptography-35.0.0.tar.gz", hash = "sha256:9933f28f70d0517686bd7de36166dda42094eac49415459d9bdf5e7df3e0086d"}, -] -ddlparse = [ - {file = "ddlparse-1.10.0-py3-none-any.whl", hash = "sha256:71761b3457c8720853af3aeef266e2da1b6edef50936969492d586d7046a2ac2"}, - {file = "ddlparse-1.10.0.tar.gz", hash = "sha256:6418681baa848eb01251ab79eb3d0ad7e140e6ab1deaae5a019353ddb3a908da"}, -] -dictdiffer = [ - {file = "dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595"}, - {file = "dictdiffer-0.9.0.tar.gz", hash = "sha256:17bacf5fbfe613ccf1b6d512bd766e6b21fb798822a133aa86098b8ac9997578"}, + {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884"}, + {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280"}, + {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3"}, + {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59"}, + {file = "cryptography-37.0.4-cp36-abi3-win32.whl", hash = "sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157"}, + {file = "cryptography-37.0.4-cp36-abi3-win_amd64.whl", hash = "sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327"}, + {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b"}, + {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab"}, + {file = "cryptography-37.0.4.tar.gz", hash = "sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82"}, ] +dictdiffer = [] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, ] -flake8 = [ - {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, - {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, -] +flake8 = [] gitdb = [ - {file = "gitdb-4.0.7-py3-none-any.whl", hash = "sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0"}, - {file = "gitdb-4.0.7.tar.gz", hash = "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"}, + {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, + {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, ] gitpython = [ - {file = "GitPython-3.1.24-py3-none-any.whl", hash = "sha256:dc0a7f2f697657acc8d7f89033e8b1ea94dd90356b2983bca89dc8d2ab3cc647"}, - {file = "GitPython-3.1.24.tar.gz", hash = "sha256:df83fdf5e684fef7c6ee2c02fc68a5ceb7e7e759d08b694088d0cacb4eba59e5"}, + {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, + {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, - {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -iso8601 = [ - {file = "iso8601-0.1.16-py2.py3-none-any.whl", hash = "sha256:906714829fedbc89955d52806c903f2332e3948ed94e31e85037f9e0226b8376"}, - {file = "iso8601-0.1.16.tar.gz", hash = "sha256:36532f77cc800594e8f16641edae7f1baf7932f05d8e508545b95fc53c6dc85b"}, -] -isort = [ - {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, - {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -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-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, - {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, -] -pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, + {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, + {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, ] +iniconfig = [] +iso8601 = [] +isort = [] +mccabe = [] +mypy-extensions = [] +packaging = [] +pathspec = [] pbr = [ - {file = "pbr-5.6.0-py2.py3-none-any.whl", hash = "sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"}, - {file = "pbr-5.6.0.tar.gz", hash = "sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd"}, -] -platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -py = [ - {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, - {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, -] -pycodestyle = [ - {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, - {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, + {file = "pbr-5.10.0-py2.py3-none-any.whl", hash = "sha256:da3e18aac0a3c003e9eea1a81bd23e5a3a75d745670dcf736317b7d966887fdf"}, + {file = "pbr-5.10.0.tar.gz", hash = "sha256:cfcc4ff8e698256fc17ea3ff796478b050852585aa5bae79ecd05b2ab7b39b9a"}, ] +platformdirs = [] +pluggy = [] +py = [] +pycodestyle = [] pycparser = [ - {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, - {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, -] -pyflakes = [ - {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, - {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, -] -pymysql = [ - {file = "PyMySQL-0.9.3-py2.py3-none-any.whl", hash = "sha256:3943fbbbc1e902f41daf7f9165519f140c4451c179380677e6a848587042561a"}, - {file = "PyMySQL-0.9.3.tar.gz", hash = "sha256:d8c059dcd81dedb85a9f034d5e22dcb4442c0b201908bede99e306d65ea7c8e7"}, -] -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-tortoise = [ - {file = "pypika-tortoise-0.1.1.tar.gz", hash = "sha256:6831d0a56e5e0ecefac3307dd9bdb3e5073fdac5d617401601d3a6713e059f3c"}, - {file = "pypika_tortoise-0.1.1-py3-none-any.whl", hash = "sha256:860020094e01058ea80602c90d4a843d0a42cffefcf4f3cb1a7f2c18b880c638"}, -] -pytest = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, -] -pytest-asyncio = [ - {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"}, - {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"}, + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] +pydantic = [] +pyflakes = [] +pyparsing = [] +pypika-tortoise = [] +pyproject-flake8 = [] +pytest = [] +pytest-asyncio = [] pytest-forked = [ - {file = "pytest-forked-1.3.0.tar.gz", hash = "sha256:6aa9ac7e00ad1a539c41bec6d21011332de671e938c7637378ec9710204e37ca"}, - {file = "pytest_forked-1.3.0-py2.py3-none-any.whl", hash = "sha256:dc4147784048e70ef5d437951728825a131b81714b398d5d52f17c7c144d8815"}, -] -pytest-mock = [ - {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, - {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, + {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, + {file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"}, ] +pytest-mock = [] pytest-xdist = [ - {file = "pytest-xdist-2.4.0.tar.gz", hash = "sha256:89b330316f7fc475f999c81b577c2b926c9569f3d397ae432c0c2e2496d61ff9"}, - {file = "pytest_xdist-2.4.0-py3-none-any.whl", hash = "sha256:7b61ebb46997a0820a263553179d6d1e25a8c50d8a8620cd1aa1e20e3be99168"}, -] -pytz = [ - {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, - {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, -] -pyyaml = [ - {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, - {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, - {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, - {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, - {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, - {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, - {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, - {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, - {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, - {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, - {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, - {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, - {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, - {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, - {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, - {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, - {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, - {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, - {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, - {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, - {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, -] -regex = [ - {file = "regex-2021.9.30-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:66696c8336a1b5d1182464f3af3427cc760118f26d0b09a2ddc16a976a4d2637"}, - {file = "regex-2021.9.30-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d87459ad3ab40cd8493774f8a454b2e490d8e729e7e402a0625867a983e4e02"}, - {file = "regex-2021.9.30-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78cf6a1e023caf5e9a982f5377414e1aeac55198831b852835732cfd0a0ca5ff"}, - {file = "regex-2021.9.30-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:255791523f80ea8e48e79af7120b4697ef3b74f6886995dcdb08c41f8e516be0"}, - {file = "regex-2021.9.30-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e502f8d4e5ef714bcc2c94d499684890c94239526d61fdf1096547db91ca6aa6"}, - {file = "regex-2021.9.30-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4907fb0f9b9309a5bded72343e675a252c2589a41871874feace9a05a540241e"}, - {file = "regex-2021.9.30-cp310-cp310-win32.whl", hash = "sha256:3be40f720af170a6b20ddd2ad7904c58b13d2b56f6734ee5d09bbdeed2fa4816"}, - {file = "regex-2021.9.30-cp310-cp310-win_amd64.whl", hash = "sha256:c2b180ed30856dfa70cfe927b0fd38e6b68198a03039abdbeb1f2029758d87e7"}, - {file = "regex-2021.9.30-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6f2d2f93001801296fe3ca86515eb04915472b5380d4d8752f09f25f0b9b0ed"}, - {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fa7ba9ab2eba7284e0d7d94f61df7af86015b0398e123331362270d71fab0b9"}, - {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28040e89a04b60d579c69095c509a4f6a1a5379cd865258e3a186b7105de72c6"}, - {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f588209d3e4797882cd238195c175290dbc501973b10a581086b5c6bcd095ffb"}, - {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42952d325439ef223e4e9db7ee6d9087b5c68c5c15b1f9de68e990837682fc7b"}, - {file = "regex-2021.9.30-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cae4099031d80703954c39680323dabd87a69b21262303160776aa0e55970ca0"}, - {file = "regex-2021.9.30-cp36-cp36m-win32.whl", hash = "sha256:0de8ad66b08c3e673b61981b9e3626f8784d5564f8c3928e2ad408c0eb5ac38c"}, - {file = "regex-2021.9.30-cp36-cp36m-win_amd64.whl", hash = "sha256:b345ecde37c86dd7084c62954468a4a655fd2d24fd9b237949dd07a4d0dd6f4c"}, - {file = "regex-2021.9.30-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6f08187136f11e430638c2c66e1db091105d7c2e9902489f0dbc69b44c222b4"}, - {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b55442650f541d195a535ccec33078c78a9521973fb960923da7515e9ed78fa6"}, - {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87e9c489aa98f50f367fb26cc9c8908d668e9228d327644d7aa568d47e456f47"}, - {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2cb7d4909ed16ed35729d38af585673f1f0833e73dfdf0c18e5be0061107b99"}, - {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0861e7f6325e821d5c40514c551fd538b292f8cc3960086e73491b9c5d8291d"}, - {file = "regex-2021.9.30-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:81fdc90f999b2147fc62e303440c424c47e5573a9b615ed5d43a5b832efcca9e"}, - {file = "regex-2021.9.30-cp37-cp37m-win32.whl", hash = "sha256:8c1ad61fa024195136a6b7b89538030bd00df15f90ac177ca278df9b2386c96f"}, - {file = "regex-2021.9.30-cp37-cp37m-win_amd64.whl", hash = "sha256:e3770781353a4886b68ef10cec31c1f61e8e3a0be5f213c2bb15a86efd999bc4"}, - {file = "regex-2021.9.30-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9c065d95a514a06b92a5026766d72ac91bfabf581adb5b29bc5c91d4b3ee9b83"}, - {file = "regex-2021.9.30-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9925985be05d54b3d25fd6c1ea8e50ff1f7c2744c75bdc4d3b45c790afa2bcb3"}, - {file = "regex-2021.9.30-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470f2c882f2672d8eeda8ab27992aec277c067d280b52541357e1acd7e606dae"}, - {file = "regex-2021.9.30-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad0517df22a97f1da20d8f1c8cb71a5d1997fa383326b81f9cf22c9dadfbdf34"}, - {file = "regex-2021.9.30-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e30838df7bfd20db6466fd309d9b580d32855f8e2c2e6d74cf9da27dcd9b63"}, - {file = "regex-2021.9.30-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b34d2335d6aedec7dcadd3f8283b9682fadad8b9b008da8788d2fce76125ebe"}, - {file = "regex-2021.9.30-cp38-cp38-win32.whl", hash = "sha256:e07049cece3462c626d650e8bf42ddbca3abf4aa08155002c28cb6d9a5a281e2"}, - {file = "regex-2021.9.30-cp38-cp38-win_amd64.whl", hash = "sha256:37868075eda024470bd0feab872c692ac4ee29db1e14baec103257bf6cc64346"}, - {file = "regex-2021.9.30-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d331f238a7accfbbe1c4cd1ba610d4c087b206353539331e32a8f05345c74aec"}, - {file = "regex-2021.9.30-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6348a7ab2a502cbdd0b7fd0496d614007489adb7361956b38044d1d588e66e04"}, - {file = "regex-2021.9.30-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b1cca6c23f19bee8dc40228d9c314d86d1e51996b86f924aca302fc8f8bf9"}, - {file = "regex-2021.9.30-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1f1125bc5172ab3a049bc6f4b9c0aae95a2a2001a77e6d6e4239fa3653e202b5"}, - {file = "regex-2021.9.30-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:638e98d069b14113e8afba6a54d1ca123f712c0d105e67c1f9211b2a825ef926"}, - {file = "regex-2021.9.30-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a0b0db6b49da7fa37ca8eddf9f40a8dbc599bad43e64f452284f37b6c34d91c"}, - {file = "regex-2021.9.30-cp39-cp39-win32.whl", hash = "sha256:9910869c472e5a6728680ca357b5846546cbbd2ab3ad5bef986ef0bc438d0aa6"}, - {file = "regex-2021.9.30-cp39-cp39-win_amd64.whl", hash = "sha256:3b71213ec3bad9a5a02e049f2ec86b3d7c3e350129ae0f4e2f99c12b5da919ed"}, - {file = "regex-2021.9.30.tar.gz", hash = "sha256:81e125d9ba54c34579e4539a967e976a3c56150796674aec318b1b2f49251be7"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"}, + {file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"}, ] +pytz = [] +pyyaml = [] smmap = [ - {file = "smmap-4.0.0-py2.py3-none-any.whl", hash = "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"}, - {file = "smmap-4.0.0.tar.gz", hash = "sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182"}, + {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, + {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, ] stevedore = [ - {file = "stevedore-3.4.0-py3-none-any.whl", hash = "sha256:920ce6259f0b2498aaa4545989536a27e4e4607b8318802d7ddc3a533d3d069e"}, - {file = "stevedore-3.4.0.tar.gz", hash = "sha256:59b58edb7f57b11897f150475e7bc0c39c5381f0b8e3fa9f5c20ce6c89ec4aa1"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"}, - {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, -] -tomlkit = [ - {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, - {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, -] -tortoise-orm = [ - {file = "tortoise-orm-0.17.7.tar.gz", hash = "sha256:74d5c6341fc0e2d4ef7a321f460107715da2679a2b3e2a48e32e276ed7bd3fc0"}, - {file = "tortoise_orm-0.17.7-py3-none-any.whl", hash = "sha256:36bb0d1f9bd800d3b91d5490cfc13a598c0e0f570a638b185bc4976abfabd135"}, + {file = "stevedore-3.5.0-py3-none-any.whl", hash = "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c"}, + {file = "stevedore-3.5.0.tar.gz", hash = "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"}, ] +tomli = [] +tomlkit = [] +tortoise-orm = [] typed-ast = [ - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, - {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, - {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, - {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, - {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, - {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, - {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, - {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, - {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, - {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, - {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, - {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, - {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, - {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, - {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, - {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, - {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, - {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, -] -typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, -] -zipp = [ - {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, - {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, + {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, + {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, + {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, + {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, + {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, + {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, + {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, + {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, + {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, + {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, + {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, + {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, + {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, + {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, + {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, + {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, + {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, + {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, + {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, + {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, + {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, + {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, + {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, + {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] +typing-extensions = [] +zipp = [] diff --git a/pyproject.toml b/pyproject.toml index e4103b1..e4a059a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aerich" -version = "0.6.0" +version = "0.6.4" description = "A database migrations tool for Tortoise ORM." authors = ["long2ice "] license = "Apache-2.0" @@ -16,11 +16,11 @@ include = ["CHANGELOG.md", "LICENSE", "README.md"] [tool.poetry.dependencies] python = "^3.7" -tortoise-orm = "^0.17.7" +tortoise-orm = "*" click = "*" -aiomysql = { version = "*", optional = true } asyncpg = { version = "*", optional = true } -ddlparse = "*" +asyncmy = { version = "*", optional = true } +pydantic = "*" dictdiffer = "*" tomlkit = "*" @@ -34,11 +34,16 @@ pytest-asyncio = "*" bandit = "*" pytest-mock = "*" cryptography = "*" +pyproject-flake8 = "*" [tool.poetry.extras] asyncmy = ["asyncmy"] asyncpg = ["asyncpg"] -aiomysql = ["aiomysql"] + +[tool.aerich] +tortoise_orm = "conftest.tortoise_orm" +location = "./migrations" +src_folder = "./." [build-system] requires = ["poetry>=0.12"] @@ -46,3 +51,17 @@ build-backend = "poetry.masonry.api" [tool.poetry.scripts] aerich = "aerich.cli:main" + +[tool.black] +line-length = 100 +target-version = ['py36', 'py37', 'py38', 'py39'] + +[tool.pytest.ini_options] +asyncio_mode = 'auto' + +[tool.mypy] +pretty = true +ignore_missing_imports = true + +[tool.flake8] +ignore = 'E501,W503,E203' diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 28b9283..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -ignore = E501,W503 \ No newline at end of file diff --git a/tests/models.py b/tests/models.py index 07c141f..597ee59 100644 --- a/tests/models.py +++ b/tests/models.py @@ -29,6 +29,7 @@ class User(Model): is_active = fields.BooleanField(default=True, description="Is Active") is_superuser = fields.BooleanField(default=False, description="Is SuperUser") intro = fields.TextField(default="") + longitude = fields.DecimalField(max_digits=10, decimal_places=8) class Email(Model): diff --git a/tests/old_models.py b/tests/old_models.py index 70c2f23..b8ffc5d 100644 --- a/tests/old_models.py +++ b/tests/old_models.py @@ -29,6 +29,7 @@ class User(Model): is_superuser = fields.BooleanField(default=False, description="Is SuperUser") avatar = fields.CharField(max_length=200, default="") intro = fields.TextField(default="") + longitude = fields.DecimalField(max_digits=12, decimal_places=9) class Email(Model): diff --git a/tests/test_migrate.py b/tests/test_migrate.py index 76b7c3e..41d9dde 100644 --- a/tests/test_migrate.py +++ b/tests/test_migrate.py @@ -644,6 +644,21 @@ old_models_describe = { "constraints": {}, "db_field_types": {"": "TEXT", "mysql": "LONGTEXT"}, }, + { + "name": "longitude", + "unique": False, + "default": None, + "indexed": False, + "nullable": False, + "db_column": "longitude", + "docstring": None, + "generated": False, + "field_type": "DecimalField", + "constraints": {}, + "description": None, + "python_type": "decimal.Decimal", + "db_field_types": {"": "DECIMAL(12,9)", "sqlite": "VARCHAR(40)"}, + }, ], "fk_fields": [], "backward_fk_fields": [ @@ -787,15 +802,17 @@ def test_migrate(mocker: MockerFixture): Migrate.diff_models(models_describe, old_models_describe, False) Migrate._merge_operators() if isinstance(Migrate.ddl, MysqlDDL): - assert sorted(Migrate.upgrade_operators) == sorted( + expected_upgrade_operators = set( [ "ALTER TABLE `category` MODIFY COLUMN `name` VARCHAR(200)", "ALTER TABLE `category` MODIFY COLUMN `slug` VARCHAR(100) NOT NULL", "ALTER TABLE `config` ADD `user_id` INT NOT NULL COMMENT 'User'", "ALTER TABLE `config` ADD CONSTRAINT `fk_config_user_17daa970` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE", "ALTER TABLE `config` ALTER COLUMN `status` DROP DEFAULT", + "ALTER TABLE `config` MODIFY COLUMN `value` JSON NOT NULL", "ALTER TABLE `email` ADD `address` VARCHAR(200) NOT NULL", "ALTER TABLE `email` DROP COLUMN `user_id`", + "CREATE TABLE `email_user` (`email_id` INT NOT NULL REFERENCES `email` (`email_id`) ON DELETE CASCADE,`user_id` INT NOT NULL REFERENCES `user` (`id`) ON DELETE CASCADE) CHARACTER SET utf8mb4", "ALTER TABLE `configs` RENAME TO `config`", "ALTER TABLE `product` RENAME COLUMN `image` TO `pic`", "ALTER TABLE `email` RENAME COLUMN `id` TO `email_id`", @@ -803,15 +820,23 @@ def test_migrate(mocker: MockerFixture): "ALTER TABLE `email` ADD INDEX `idx_email_email_4a1a33` (`email`)", "ALTER TABLE `product` ADD UNIQUE INDEX `uid_product_name_869427` (`name`, `type_db_alias`)", "ALTER TABLE `product` ALTER COLUMN `view_num` SET DEFAULT 0", + "ALTER TABLE `product` MODIFY COLUMN `created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)", + "ALTER TABLE `product` MODIFY COLUMN `is_reviewed` BOOL NOT NULL COMMENT 'Is Reviewed'", "ALTER TABLE `user` DROP COLUMN `avatar`", "ALTER TABLE `user` MODIFY COLUMN `password` VARCHAR(100) NOT NULL", - "CREATE TABLE IF NOT EXISTS `newmodel` (\n `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,\n `name` VARCHAR(50) NOT NULL\n) CHARACTER SET utf8mb4;", + "ALTER TABLE `user` MODIFY COLUMN `intro` LONGTEXT NOT NULL", + "ALTER TABLE `user` MODIFY COLUMN `last_login` DATETIME(6) NOT NULL COMMENT 'Last Login'", + "ALTER TABLE `user` MODIFY COLUMN `is_active` BOOL NOT NULL COMMENT 'Is Active' DEFAULT 1", + "ALTER TABLE `user` MODIFY COLUMN `is_superuser` BOOL NOT NULL COMMENT 'Is SuperUser' DEFAULT 0", + "ALTER TABLE `user` MODIFY COLUMN `longitude` DECIMAL(10,8) NOT NULL", "ALTER TABLE `user` ADD UNIQUE INDEX `uid_user_usernam_9987ab` (`username`)", - "CREATE TABLE `email_user` (`email_id` INT NOT NULL REFERENCES `email` (`email_id`) ON DELETE CASCADE,`user_id` INT NOT NULL REFERENCES `user` (`id`) ON DELETE CASCADE) CHARACTER SET utf8mb4", + "CREATE TABLE IF NOT EXISTS `newmodel` (\n `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,\n `name` VARCHAR(50) NOT NULL\n) CHARACTER SET utf8mb4;", + "ALTER TABLE `category` MODIFY COLUMN `created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)", + "ALTER TABLE `product` MODIFY COLUMN `body` LONGTEXT NOT NULL", + "ALTER TABLE `email` MODIFY COLUMN `is_primary` BOOL NOT NULL DEFAULT 0", ] ) - - assert sorted(Migrate.downgrade_operators) == sorted( + expected_downgrade_operators = set( [ "ALTER TABLE `category` MODIFY COLUMN `name` VARCHAR(200) NOT NULL", "ALTER TABLE `category` MODIFY COLUMN `slug` VARCHAR(200) NOT NULL", @@ -832,25 +857,52 @@ def test_migrate(mocker: MockerFixture): "ALTER TABLE `user` MODIFY COLUMN `password` VARCHAR(200) NOT NULL", "DROP TABLE IF EXISTS `email_user`", "DROP TABLE IF EXISTS `newmodel`", + "ALTER TABLE `user` MODIFY COLUMN `intro` LONGTEXT NOT NULL", + "ALTER TABLE `config` MODIFY COLUMN `value` TEXT NOT NULL", + "ALTER TABLE `category` MODIFY COLUMN `created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)", + "ALTER TABLE `product` MODIFY COLUMN `created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)", + "ALTER TABLE `product` MODIFY COLUMN `is_reviewed` BOOL NOT NULL COMMENT 'Is Reviewed'", + "ALTER TABLE `user` MODIFY COLUMN `last_login` DATETIME(6) NOT NULL COMMENT 'Last Login'", + "ALTER TABLE `user` MODIFY COLUMN `is_active` BOOL NOT NULL COMMENT 'Is Active' DEFAULT 1", + "ALTER TABLE `user` MODIFY COLUMN `is_superuser` BOOL NOT NULL COMMENT 'Is SuperUser' DEFAULT 0", + "ALTER TABLE `user` MODIFY COLUMN `longitude` DECIMAL(12,9) NOT NULL", + "ALTER TABLE `product` MODIFY COLUMN `body` LONGTEXT NOT NULL", + "ALTER TABLE `email` MODIFY COLUMN `is_primary` BOOL NOT NULL DEFAULT 0", ] ) + assert not set(Migrate.upgrade_operators).symmetric_difference(expected_upgrade_operators) + + assert not set(Migrate.downgrade_operators).symmetric_difference( + expected_downgrade_operators + ) elif isinstance(Migrate.ddl, PostgresDDL): - assert sorted(Migrate.upgrade_operators) == sorted( + expected_upgrade_operators = set( [ 'ALTER TABLE "category" ALTER COLUMN "name" DROP NOT NULL', 'ALTER TABLE "category" ALTER COLUMN "slug" TYPE VARCHAR(100) USING "slug"::VARCHAR(100)', + 'ALTER TABLE "category" ALTER COLUMN "created_at" TYPE TIMESTAMPTZ USING "created_at"::TIMESTAMPTZ', 'ALTER TABLE "config" ADD "user_id" INT NOT NULL', 'ALTER TABLE "config" ADD CONSTRAINT "fk_config_user_17daa970" FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE', 'ALTER TABLE "config" ALTER COLUMN "status" DROP DEFAULT', + 'ALTER TABLE "config" ALTER COLUMN "value" TYPE JSONB USING "value"::JSONB', 'ALTER TABLE "configs" RENAME TO "config"', 'ALTER TABLE "email" ADD "address" VARCHAR(200) NOT NULL', 'ALTER TABLE "email" DROP COLUMN "user_id"', 'ALTER TABLE "email" RENAME COLUMN "id" TO "email_id"', + 'ALTER TABLE "email" ALTER COLUMN "is_primary" TYPE BOOL USING "is_primary"::BOOL', 'ALTER TABLE "product" ALTER COLUMN "view_num" SET DEFAULT 0', 'ALTER TABLE "product" RENAME COLUMN "image" TO "pic"', + 'ALTER TABLE "product" ALTER COLUMN "is_reviewed" TYPE BOOL USING "is_reviewed"::BOOL', + 'ALTER TABLE "product" ALTER COLUMN "body" TYPE TEXT USING "body"::TEXT', + 'ALTER TABLE "product" ALTER COLUMN "created_at" TYPE TIMESTAMPTZ USING "created_at"::TIMESTAMPTZ', 'ALTER TABLE "user" ALTER COLUMN "password" TYPE VARCHAR(100) USING "password"::VARCHAR(100)', 'ALTER TABLE "user" DROP COLUMN "avatar"', + 'ALTER TABLE "user" ALTER COLUMN "is_superuser" TYPE BOOL USING "is_superuser"::BOOL', + 'ALTER TABLE "user" ALTER COLUMN "last_login" TYPE TIMESTAMPTZ USING "last_login"::TIMESTAMPTZ', + 'ALTER TABLE "user" ALTER COLUMN "intro" TYPE TEXT USING "intro"::TEXT', + 'ALTER TABLE "user" ALTER COLUMN "is_active" TYPE BOOL USING "is_active"::BOOL', + 'ALTER TABLE "user" ALTER COLUMN "longitude" TYPE DECIMAL(10,8) USING "longitude"::DECIMAL(10,8)', 'CREATE INDEX "idx_product_name_869427" ON "product" ("name", "type_db_alias")', 'CREATE INDEX "idx_email_email_4a1a33" ON "email" ("email")', 'CREATE TABLE "email_user" ("email_id" INT NOT NULL REFERENCES "email" ("email_id") ON DELETE CASCADE,"user_id" INT NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE)', @@ -859,21 +911,32 @@ def test_migrate(mocker: MockerFixture): 'CREATE UNIQUE INDEX "uid_user_usernam_9987ab" ON "user" ("username")', ] ) - assert sorted(Migrate.downgrade_operators) == sorted( + expected_downgrade_operators = set( [ 'ALTER TABLE "category" ALTER COLUMN "name" SET NOT NULL', 'ALTER TABLE "category" ALTER COLUMN "slug" TYPE VARCHAR(200) USING "slug"::VARCHAR(200)', + 'ALTER TABLE "category" ALTER COLUMN "created_at" TYPE TIMESTAMPTZ USING "created_at"::TIMESTAMPTZ', 'ALTER TABLE "config" ALTER COLUMN "status" SET DEFAULT 1', 'ALTER TABLE "config" DROP COLUMN "user_id"', 'ALTER TABLE "config" DROP CONSTRAINT "fk_config_user_17daa970"', 'ALTER TABLE "config" RENAME TO "configs"', + 'ALTER TABLE "config" ALTER COLUMN "value" TYPE JSONB USING "value"::JSONB', 'ALTER TABLE "email" ADD "user_id" INT NOT NULL', 'ALTER TABLE "email" DROP COLUMN "address"', 'ALTER TABLE "email" RENAME COLUMN "email_id" TO "id"', + 'ALTER TABLE "email" ALTER COLUMN "is_primary" TYPE BOOL USING "is_primary"::BOOL', 'ALTER TABLE "product" ALTER COLUMN "view_num" DROP DEFAULT', 'ALTER TABLE "product" RENAME COLUMN "pic" TO "image"', 'ALTER TABLE "user" ADD "avatar" VARCHAR(200) NOT NULL DEFAULT \'\'', 'ALTER TABLE "user" ALTER COLUMN "password" TYPE VARCHAR(200) USING "password"::VARCHAR(200)', + 'ALTER TABLE "user" ALTER COLUMN "last_login" TYPE TIMESTAMPTZ USING "last_login"::TIMESTAMPTZ', + 'ALTER TABLE "user" ALTER COLUMN "is_superuser" TYPE BOOL USING "is_superuser"::BOOL', + 'ALTER TABLE "user" ALTER COLUMN "is_active" TYPE BOOL USING "is_active"::BOOL', + 'ALTER TABLE "user" ALTER COLUMN "intro" TYPE TEXT USING "intro"::TEXT', + 'ALTER TABLE "user" ALTER COLUMN "longitude" TYPE DECIMAL(12,9) USING "longitude"::DECIMAL(12,9)', + 'ALTER TABLE "product" ALTER COLUMN "created_at" TYPE TIMESTAMPTZ USING "created_at"::TIMESTAMPTZ', + 'ALTER TABLE "product" ALTER COLUMN "is_reviewed" TYPE BOOL USING "is_reviewed"::BOOL', + 'ALTER TABLE "product" ALTER COLUMN "body" TYPE TEXT USING "body"::TEXT', 'DROP INDEX "idx_product_name_869427"', 'DROP INDEX "idx_email_email_4a1a33"', 'DROP INDEX "idx_user_usernam_9987ab"', @@ -882,9 +945,13 @@ def test_migrate(mocker: MockerFixture): 'DROP TABLE IF EXISTS "newmodel"', ] ) + assert not set(Migrate.upgrade_operators).symmetric_difference(expected_upgrade_operators) + assert not set(Migrate.downgrade_operators).symmetric_difference( + expected_downgrade_operators + ) + elif isinstance(Migrate.ddl, SqliteDDL): assert Migrate.upgrade_operators == [] - assert Migrate.downgrade_operators == []