Compare commits
61 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
768747140a | ||
|
1fde3cd04e | ||
|
d0ce545ff5 | ||
|
09b89ed7d0 | ||
|
86c8382593 | ||
|
48e3ff48a3 | ||
|
1bf6d45bb0 | ||
|
342f4cdd3b | ||
|
8cace21fde | ||
|
9889d9492b | ||
|
823368aea8 | ||
|
6b1ad46cf1 | ||
|
ce8c0b1f06 | ||
|
43922d3734 | ||
|
48c5318737 | ||
|
002221e557 | ||
|
141d7205bf | ||
|
af4d4be19a | ||
|
3b4d9b47ce | ||
|
4b0c4ae7d0 | ||
|
dc821d8a02 | ||
|
d18a6b5be0 | ||
|
1e56a70f21 | ||
|
ab1e1aab75 | ||
|
00dd04f97d | ||
|
fc914acc80 | ||
|
ac03ecb002 | ||
|
235ef3f7ea | ||
|
e00eb7f3d9 | ||
|
d6c8941676 | ||
|
cf062c9310 | ||
|
309adec8c9 | ||
|
8674142ba8 | ||
|
cda9bd1c47 | ||
|
198e4e0032 | ||
|
1b440477a2 | ||
|
1263c6f735 | ||
|
6504384879 | ||
|
17ab0a1421 | ||
|
e1ffcb609b | ||
|
18cb75f555 | ||
|
dfe13ea250 | ||
|
b97ce0ff2f | ||
|
21001c0eda | ||
|
9bd96a9487 | ||
|
5bdaa32a9e | ||
|
d74e7b5630 | ||
|
119b15d597 | ||
|
f93ab6bbff | ||
|
bd8eb94a6e | ||
|
2fcb2626fd | ||
|
3728db4279 | ||
|
6ac1fb5332 | ||
|
87a17d443c | ||
|
55f18a69ed | ||
|
86a9c4cedd | ||
|
19c9c2c30f | ||
|
dc8b4c2263 | ||
|
2fc43cb0d8 | ||
|
cb5dffeeb8 | ||
|
615d9747dc |
102
CHANGELOG.md
Normal file
102
CHANGELOG.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# ChangeLog
|
||||||
|
|
||||||
|
## 0.3
|
||||||
|
|
||||||
|
### 0.3.1
|
||||||
|
|
||||||
|
- Fix first version error.
|
||||||
|
- Fix init error. (#61)
|
||||||
|
|
||||||
|
### 0.3.0
|
||||||
|
|
||||||
|
- Refactoring migrate logic, and this version is not compatible with previous version.
|
||||||
|
- Now there don't need `old_models.py` and it store in database.
|
||||||
|
- Upgrade steps:
|
||||||
|
1. Upgrade aerich version.
|
||||||
|
2. Drop aerich table in database.
|
||||||
|
3. Delete `migrations/{app}` folder and rerun `aerich init-db`.
|
||||||
|
4. Update model and `aerich migrate` normally.
|
||||||
|
|
||||||
|
## 0.2
|
||||||
|
|
||||||
|
### 0.2.5
|
||||||
|
|
||||||
|
- Fix windows support. (#46)
|
||||||
|
- Support `db_constraint` in fk, m2m should manual define table with fk. (#52)
|
||||||
|
|
||||||
|
### 0.2.4
|
||||||
|
|
||||||
|
- Raise error with SQLite unsupported features.
|
||||||
|
- Fix Postgres alter table. (#48)
|
||||||
|
- Add `Rename` support.
|
||||||
|
|
||||||
|
### 0.2.3
|
||||||
|
|
||||||
|
- Fix tortoise ssl config.
|
||||||
|
- PostgreSQL add/drop index/unique.
|
||||||
|
|
||||||
|
### 0.2.2
|
||||||
|
|
||||||
|
- Fix postgres drop fk.
|
||||||
|
- Fix version sort.
|
||||||
|
|
||||||
|
### 0.2.1
|
||||||
|
|
||||||
|
- Fix bug in windows.
|
||||||
|
- Enhance PostgreSQL support.
|
||||||
|
|
||||||
|
### 0.2.0
|
||||||
|
|
||||||
|
- Update model file find method.
|
||||||
|
- Set `--safe` bool.
|
||||||
|
|
||||||
|
## 0.1
|
||||||
|
|
||||||
|
### 0.1.9
|
||||||
|
|
||||||
|
- Fix default_connection when upgrade
|
||||||
|
- Find default app instead of default.
|
||||||
|
- Diff MySQL ddl.
|
||||||
|
- Check tortoise config.
|
||||||
|
|
||||||
|
### 0.1.8
|
||||||
|
|
||||||
|
- Fix upgrade error when migrate.
|
||||||
|
- Fix init db sql error.
|
||||||
|
- Support change column.
|
||||||
|
|
||||||
|
### 0.1.7
|
||||||
|
|
||||||
|
- Exclude models.Aerich.
|
||||||
|
- Add init record when init-db.
|
||||||
|
- Fix version num str.
|
||||||
|
|
||||||
|
### 0.1.6
|
||||||
|
|
||||||
|
- update dependency_links
|
||||||
|
|
||||||
|
### 0.1.5
|
||||||
|
|
||||||
|
- Add sqlite and postgres support.
|
||||||
|
- Fix dependency import.
|
||||||
|
- Store versions in db.
|
||||||
|
|
||||||
|
### 0.1.4
|
||||||
|
|
||||||
|
- Fix transaction and fields import.
|
||||||
|
- Make unique index worked.
|
||||||
|
- Add cli --version.
|
||||||
|
|
||||||
|
### 0.1.3
|
||||||
|
|
||||||
|
- Support indexes and unique_together.
|
||||||
|
|
||||||
|
### 0.1.2
|
||||||
|
|
||||||
|
- Now aerich support m2m.
|
||||||
|
- Add cli cmd init-db.
|
||||||
|
- Change cli options.
|
||||||
|
|
||||||
|
### 0.1.1
|
||||||
|
|
||||||
|
- Now aerich is basic worked.
|
@@ -1,66 +0,0 @@
|
|||||||
=========
|
|
||||||
ChangeLog
|
|
||||||
=========
|
|
||||||
0.2
|
|
||||||
===
|
|
||||||
|
|
||||||
0.2.1
|
|
||||||
-----
|
|
||||||
- Fix bug in windows.
|
|
||||||
- Enhance PostgreSQL support.
|
|
||||||
|
|
||||||
0.2.0
|
|
||||||
-----
|
|
||||||
- Update model file find method.
|
|
||||||
- Set ``--safe`` bool.
|
|
||||||
|
|
||||||
0.1
|
|
||||||
===
|
|
||||||
0.1.9
|
|
||||||
-----
|
|
||||||
- Fix default_connection when upgrade
|
|
||||||
- Find default app instead of default.
|
|
||||||
- Diff MySQL ddl.
|
|
||||||
- Check tortoise config.
|
|
||||||
|
|
||||||
0.1.8
|
|
||||||
-----
|
|
||||||
- Fix upgrade error when migrate.
|
|
||||||
- Fix init db sql error.
|
|
||||||
- Support change column.
|
|
||||||
|
|
||||||
0.1.7
|
|
||||||
-----
|
|
||||||
- Exclude models.Aerich.
|
|
||||||
- Add init record when init-db.
|
|
||||||
- Fix version num str.
|
|
||||||
|
|
||||||
0.1.6
|
|
||||||
-----
|
|
||||||
- update dependency_links
|
|
||||||
|
|
||||||
0.1.5
|
|
||||||
-----
|
|
||||||
- Add sqlite and postgres support.
|
|
||||||
- Fix dependency import.
|
|
||||||
- Store versions in db.
|
|
||||||
|
|
||||||
0.1.4
|
|
||||||
-----
|
|
||||||
- Fix transaction and fields import.
|
|
||||||
- Make unique index worked.
|
|
||||||
- Add cli --version.
|
|
||||||
|
|
||||||
0.1.3
|
|
||||||
-----
|
|
||||||
- Support indexes and unique_together.
|
|
||||||
|
|
||||||
0.1.2
|
|
||||||
-----
|
|
||||||
- Now aerich support m2m.
|
|
||||||
- Add cli cmd init-db.
|
|
||||||
- Change cli options.
|
|
||||||
|
|
||||||
0.1.1
|
|
||||||
-----
|
|
||||||
- Now aerich is basic worked.
|
|
9
Makefile
9
Makefile
@@ -40,17 +40,14 @@ test_sqlite:
|
|||||||
$(py_warn) TEST_DB=sqlite://:memory: py.test
|
$(py_warn) TEST_DB=sqlite://:memory: py.test
|
||||||
|
|
||||||
test_mysql:
|
test_mysql:
|
||||||
$(py_warn) TEST_DB="mysql://root:$(MYSQL_PASS)@$(MYSQL_HOST):$(MYSQL_PORT)/test_\{\}" py.test
|
$(py_warn) TEST_DB="mysql://root:$(MYSQL_PASS)@$(MYSQL_HOST):$(MYSQL_PORT)/test_\{\}" pytest -vv -s
|
||||||
|
|
||||||
test_postgres:
|
test_postgres:
|
||||||
$(py_warn) TEST_DB="postgres://postgres:$(POSTGRES_PASS)@$(POSTGRES_HOST):$(POSTGRES_PORT)/test_\{\}" py.test
|
$(py_warn) TEST_DB="postgres://postgres:$(POSTGRES_PASS)@$(POSTGRES_HOST):$(POSTGRES_PORT)/test_\{\}" pytest
|
||||||
|
|
||||||
testall: deps test_sqlite test_postgres test_mysql
|
testall: deps test_sqlite test_postgres test_mysql
|
||||||
|
|
||||||
build: deps
|
build: deps
|
||||||
@poetry build
|
@poetry build
|
||||||
|
|
||||||
publish: deps
|
ci: check testall
|
||||||
@poetry publish --build
|
|
||||||
|
|
||||||
ci: check testall
|
|
||||||
|
76
README.md
76
README.md
@@ -7,12 +7,10 @@
|
|||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
Tortoise-ORM is the best asyncio ORM now, but it lacks a database
|
Aerich is a database migrations tool for Tortoise-ORM, which like alembic for SQLAlchemy, or Django ORM with it\'s
|
||||||
migrations tool like alembic for SQLAlchemy, or Django ORM with it\'s
|
own migrations solution.
|
||||||
own migrations tool.
|
|
||||||
|
|
||||||
This project aim to be a best migrations tool for Tortoise-ORM and which
|
**If you upgrade aerich from <= 0.2.5 to >= 0.3.0, see [changelog](https://github.com/tortoise/aerich/blob/dev/CHANGELOG.md) for upgrade steps.**
|
||||||
written by one of contributors of Tortoise-ORM.
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
@@ -25,7 +23,7 @@ Just install from pypi:
|
|||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich -h
|
> aerich -h
|
||||||
|
|
||||||
Usage: aerich [OPTIONS] COMMAND [ARGS]...
|
Usage: aerich [OPTIONS] COMMAND [ARGS]...
|
||||||
|
|
||||||
@@ -37,7 +35,7 @@ Options:
|
|||||||
-h, --help Show this message and exit.
|
-h, --help Show this message and exit.
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
downgrade Downgrade to previous version.
|
downgrade Downgrade to specified version.
|
||||||
heads Show current available heads in migrate location.
|
heads Show current available heads in migrate location.
|
||||||
history List all migrate items.
|
history List all migrate items.
|
||||||
init Init config file and generate root migrate location.
|
init Init config file and generate root migrate location.
|
||||||
@@ -66,7 +64,7 @@ TORTOISE_ORM = {
|
|||||||
### Initialization
|
### Initialization
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich init -h
|
> aerich init -h
|
||||||
|
|
||||||
Usage: aerich init [OPTIONS]
|
Usage: aerich init [OPTIONS]
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ Options:
|
|||||||
Init config file and location:
|
Init config file and location:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich init -t tests.backends.mysql.TORTOISE_ORM
|
> aerich init -t tests.backends.mysql.TORTOISE_ORM
|
||||||
|
|
||||||
Success create migrate location ./migrations
|
Success create migrate location ./migrations
|
||||||
Success generate config file aerich.ini
|
Success generate config file aerich.ini
|
||||||
@@ -91,56 +89,66 @@ Success generate config file aerich.ini
|
|||||||
### Init db
|
### Init db
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich init-db
|
> aerich init-db
|
||||||
|
|
||||||
Success create app migrate location ./migrations/models
|
Success create app migrate location ./migrations/models
|
||||||
Success generate schema for app "models"
|
Success generate schema for app "models"
|
||||||
```
|
```
|
||||||
|
|
||||||
::: {.note}
|
|
||||||
::: {.title}
|
|
||||||
Note
|
|
||||||
:::
|
|
||||||
|
|
||||||
If your Tortoise-ORM app is not default `models`, you must specify
|
If your Tortoise-ORM app is not default `models`, you must specify
|
||||||
`--app` like `aerich --app other_models init-db`.
|
`--app` like `aerich --app other_models init-db`.
|
||||||
:::
|
|
||||||
|
|
||||||
### Update models and make migrate
|
### Update models and make migrate
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich migrate --name drop_column
|
> aerich migrate --name drop_column
|
||||||
|
|
||||||
Success migrate 1_202029051520102929_drop_column.json
|
Success migrate 1_202029051520102929_drop_column.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Format of migrate filename is
|
Format of migrate filename is
|
||||||
`{version_num}_{datetime}_{name|update}.json`
|
`{version_num}_{datetime}_{name|update}.json`.
|
||||||
|
|
||||||
|
And if `aerich` guess you are renaming a column, it will ask `Rename {old_column} to {new_column} [True]`, you can choice `True` to rename column without column drop, or choice `False` to drop column then create.
|
||||||
|
|
||||||
|
If you use `MySQL`, only MySQL8.0+ support `rename..to` syntax.
|
||||||
|
|
||||||
### Upgrade to latest version
|
### Upgrade to latest version
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich upgrade
|
> aerich upgrade
|
||||||
|
|
||||||
Success upgrade 1_202029051520102929_drop_column.json
|
Success upgrade 1_202029051520102929_drop_column.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Now your db is migrated to latest.
|
Now your db is migrated to latest.
|
||||||
|
|
||||||
### Downgrade to previous version
|
### Downgrade to specified version
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich downgrade
|
> aerich init -h
|
||||||
|
|
||||||
|
Usage: aerich downgrade [OPTIONS]
|
||||||
|
|
||||||
|
Downgrade to specified version.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-v, --version INTEGER Specified version, default to last. [default: -1]
|
||||||
|
-h, --help Show this message and exit.
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
> aerich downgrade
|
||||||
|
|
||||||
Success downgrade 1_202029051520102929_drop_column.json
|
Success downgrade 1_202029051520102929_drop_column.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Now your db rollback to previous version.
|
Now your db rollback to specified version.
|
||||||
|
|
||||||
### Show history
|
### Show history
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich history
|
> aerich history
|
||||||
|
|
||||||
1_202029051520102929_drop_column.json
|
1_202029051520102929_drop_column.json
|
||||||
```
|
```
|
||||||
@@ -148,33 +156,19 @@ $ aerich history
|
|||||||
### Show heads to be migrated
|
### Show heads to be migrated
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ aerich heads
|
> aerich heads
|
||||||
|
|
||||||
1_202029051520102929_drop_column.json
|
1_202029051520102929_drop_column.json
|
||||||
```
|
```
|
||||||
|
|
||||||
## Limitations
|
|
||||||
|
|
||||||
- Not support `rename column` now.
|
|
||||||
- `Sqlite` and `Postgres` may not work as expected because I don\'t
|
|
||||||
use those in my work.
|
|
||||||
|
|
||||||
## Support this project
|
## Support this project
|
||||||
|
|
||||||
- Just give a star!
|
- Just give a star!
|
||||||
- Donation.
|
- Donation.
|
||||||
|
|
||||||
### AliPay
|
| AliPay | WeChatPay | PayPal |
|
||||||
|
| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
||||||
<img width="200" src="https://github.com/long2ice/aerich/raw/dev/images/alipay.jpeg"/>
|
| <img width="200" src="https://github.com/long2ice/aerich/raw/dev/images/alipay.jpeg"/> | <img width="200" src="https://github.com/long2ice/aerich/raw/dev/images/wechatpay.jpeg"/> | [PayPal](https://www.paypal.me/long2ice) to my account long2ice. |
|
||||||
|
|
||||||
### WeChat Pay
|
|
||||||
|
|
||||||
<img width="200" src="https://github.com/long2ice/aerich/raw/dev/images/wechatpay.jpeg"/>
|
|
||||||
|
|
||||||
### PayPal
|
|
||||||
|
|
||||||
Donate money by [paypal](https://www.paypal.me/long2ice) to my account long2ice.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
@@ -1 +1 @@
|
|||||||
__version__ = "0.2.1"
|
__version__ = "0.3.1"
|
||||||
|
123
aerich/cli.py
123
aerich/cli.py
@@ -1,11 +1,12 @@
|
|||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from enum import Enum
|
from functools import wraps
|
||||||
|
|
||||||
import asyncclick as click
|
import click
|
||||||
from asyncclick import Context, UsageError
|
from click import Context, UsageError
|
||||||
from tortoise import Tortoise, generate_schema_for_client
|
from tortoise import Tortoise, generate_schema_for_client
|
||||||
from tortoise.exceptions import OperationalError
|
from tortoise.exceptions import OperationalError
|
||||||
from tortoise.transactions import in_transaction
|
from tortoise.transactions import in_transaction
|
||||||
@@ -15,18 +16,25 @@ from aerich.migrate import Migrate
|
|||||||
from aerich.utils import get_app_connection, get_app_connection_name, get_tortoise_config
|
from aerich.utils import get_app_connection, get_app_connection_name, get_tortoise_config
|
||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
|
from .enums import Color
|
||||||
from .models import Aerich
|
from .models import Aerich
|
||||||
|
|
||||||
|
|
||||||
class Color(str, Enum):
|
|
||||||
green = "green"
|
|
||||||
red = "red"
|
|
||||||
yellow = "yellow"
|
|
||||||
|
|
||||||
|
|
||||||
parser = ConfigParser()
|
parser = ConfigParser()
|
||||||
|
|
||||||
|
|
||||||
|
def coro(f):
|
||||||
|
@wraps(f)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
ctx = args[0]
|
||||||
|
loop.run_until_complete(f(*args, **kwargs))
|
||||||
|
app = ctx.obj.get("app")
|
||||||
|
if app:
|
||||||
|
Migrate.remove_old_model_file(app, ctx.obj["location"])
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
||||||
@click.version_option(__version__, "-V", "--version")
|
@click.version_option(__version__, "-V", "--version")
|
||||||
@click.option(
|
@click.option(
|
||||||
@@ -41,6 +49,7 @@ parser = ConfigParser()
|
|||||||
help="Name of section in .ini file to use for aerich config.",
|
help="Name of section in .ini file to use for aerich config.",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
|
@coro
|
||||||
async def cli(ctx: Context, config, app, name):
|
async def cli(ctx: Context, config, app, name):
|
||||||
ctx.ensure_object(dict)
|
ctx.ensure_object(dict)
|
||||||
ctx.obj["config_file"] = config
|
ctx.obj["config_file"] = config
|
||||||
@@ -62,7 +71,7 @@ async def cli(ctx: Context, config, app, name):
|
|||||||
ctx.obj["config"] = tortoise_config
|
ctx.obj["config"] = tortoise_config
|
||||||
ctx.obj["location"] = location
|
ctx.obj["location"] = location
|
||||||
ctx.obj["app"] = app
|
ctx.obj["app"] = app
|
||||||
|
Migrate.app = app
|
||||||
if invoked_subcommand != "init-db":
|
if invoked_subcommand != "init-db":
|
||||||
await Migrate.init_with_old_models(tortoise_config, app, location)
|
await Migrate.init_with_old_models(tortoise_config, app, location)
|
||||||
|
|
||||||
@@ -70,68 +79,89 @@ async def cli(ctx: Context, config, app, name):
|
|||||||
@cli.command(help="Generate migrate changes file.")
|
@cli.command(help="Generate migrate changes file.")
|
||||||
@click.option("--name", default="update", show_default=True, help="Migrate name.")
|
@click.option("--name", default="update", show_default=True, help="Migrate name.")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
|
@coro
|
||||||
async def migrate(ctx: Context, name):
|
async def migrate(ctx: Context, name):
|
||||||
config = ctx.obj["config"]
|
|
||||||
location = ctx.obj["location"]
|
|
||||||
app = ctx.obj["app"]
|
|
||||||
|
|
||||||
ret = await Migrate.migrate(name)
|
ret = await Migrate.migrate(name)
|
||||||
if not ret:
|
if not ret:
|
||||||
return click.secho("No changes detected", fg=Color.yellow)
|
return click.secho("No changes detected", fg=Color.yellow)
|
||||||
Migrate.write_old_models(config, app, location)
|
|
||||||
click.secho(f"Success migrate {ret}", fg=Color.green)
|
click.secho(f"Success migrate {ret}", fg=Color.green)
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help="Upgrade to latest version.")
|
@cli.command(help="Upgrade to specified version.")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
|
@coro
|
||||||
async def upgrade(ctx: Context):
|
async def upgrade(ctx: Context):
|
||||||
config = ctx.obj["config"]
|
config = ctx.obj["config"]
|
||||||
app = ctx.obj["app"]
|
app = ctx.obj["app"]
|
||||||
|
location = ctx.obj["location"]
|
||||||
migrated = False
|
migrated = False
|
||||||
for version in Migrate.get_all_version_files():
|
for version_file in Migrate.get_all_version_files():
|
||||||
try:
|
try:
|
||||||
exists = await Aerich.exists(version=version, app=app)
|
exists = await Aerich.exists(version=version_file, app=app)
|
||||||
except OperationalError:
|
except OperationalError:
|
||||||
exists = False
|
exists = False
|
||||||
if not exists:
|
if not exists:
|
||||||
async with in_transaction(get_app_connection_name(config, app)) as conn:
|
async with in_transaction(get_app_connection_name(config, app)) as conn:
|
||||||
file_path = os.path.join(Migrate.migrate_location, version)
|
file_path = os.path.join(Migrate.migrate_location, version_file)
|
||||||
with open(file_path, "r", encoding="utf-8") as f:
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
content = json.load(f)
|
content = json.load(f)
|
||||||
upgrade_query_list = content.get("upgrade")
|
upgrade_query_list = content.get("upgrade")
|
||||||
for upgrade_query in upgrade_query_list:
|
for upgrade_query in upgrade_query_list:
|
||||||
await conn.execute_script(upgrade_query)
|
await conn.execute_script(upgrade_query)
|
||||||
await Aerich.create(version=version, app=app)
|
await Aerich.create(
|
||||||
click.secho(f"Success upgrade {version}", fg=Color.green)
|
version=version_file,
|
||||||
|
app=app,
|
||||||
|
content=Migrate.get_models_content(config, app, location),
|
||||||
|
)
|
||||||
|
click.secho(f"Success upgrade {version_file}", fg=Color.green)
|
||||||
migrated = True
|
migrated = True
|
||||||
if not migrated:
|
if not migrated:
|
||||||
click.secho("No migrate items", fg=Color.yellow)
|
click.secho("No migrate items", fg=Color.yellow)
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help="Downgrade to previous version.")
|
@cli.command(help="Downgrade to specified version.")
|
||||||
|
@click.option(
|
||||||
|
"-v",
|
||||||
|
"--version",
|
||||||
|
default=-1,
|
||||||
|
type=int,
|
||||||
|
show_default=True,
|
||||||
|
help="Specified version, default to last.",
|
||||||
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
async def downgrade(ctx: Context):
|
@coro
|
||||||
|
async def downgrade(ctx: Context, version: int):
|
||||||
app = ctx.obj["app"]
|
app = ctx.obj["app"]
|
||||||
config = ctx.obj["config"]
|
config = ctx.obj["config"]
|
||||||
last_version = await Migrate.get_last_version()
|
if version == -1:
|
||||||
if not last_version:
|
specified_version = await Migrate.get_last_version()
|
||||||
return click.secho("No last version found", fg=Color.yellow)
|
else:
|
||||||
file = last_version.version
|
specified_version = await Aerich.filter(app=app, version__startswith=f"{version}_").first()
|
||||||
async with in_transaction(get_app_connection_name(config, app)) as conn:
|
if not specified_version:
|
||||||
file_path = os.path.join(Migrate.migrate_location, file)
|
return click.secho("No specified version found", fg=Color.yellow)
|
||||||
with open(file_path, "r", encoding="utf-8") as f:
|
if version == -1:
|
||||||
content = json.load(f)
|
versions = [specified_version]
|
||||||
downgrade_query_list = content.get("downgrade")
|
else:
|
||||||
if not downgrade_query_list:
|
versions = await Aerich.filter(app=app, pk__gte=specified_version.pk)
|
||||||
return click.secho("No downgrade item found", fg=Color.yellow)
|
for version in versions:
|
||||||
for downgrade_query in downgrade_query_list:
|
file = version.version
|
||||||
await conn.execute_query(downgrade_query)
|
async with in_transaction(get_app_connection_name(config, app)) as conn:
|
||||||
await last_version.delete()
|
file_path = os.path.join(Migrate.migrate_location, file)
|
||||||
return click.secho(f"Success downgrade {file}", fg=Color.green)
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
content = json.load(f)
|
||||||
|
downgrade_query_list = content.get("downgrade")
|
||||||
|
if not downgrade_query_list:
|
||||||
|
return click.secho("No downgrade item found", fg=Color.yellow)
|
||||||
|
for downgrade_query in downgrade_query_list:
|
||||||
|
await conn.execute_query(downgrade_query)
|
||||||
|
await version.delete()
|
||||||
|
os.unlink(file_path)
|
||||||
|
click.secho(f"Success downgrade {file}", fg=Color.green)
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help="Show current available heads in migrate location.")
|
@cli.command(help="Show current available heads in migrate location.")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
|
@coro
|
||||||
async def heads(ctx: Context):
|
async def heads(ctx: Context):
|
||||||
app = ctx.obj["app"]
|
app = ctx.obj["app"]
|
||||||
versions = Migrate.get_all_version_files()
|
versions = Migrate.get_all_version_files()
|
||||||
@@ -141,12 +171,13 @@ async def heads(ctx: Context):
|
|||||||
click.secho(version, fg=Color.green)
|
click.secho(version, fg=Color.green)
|
||||||
is_heads = True
|
is_heads = True
|
||||||
if not is_heads:
|
if not is_heads:
|
||||||
click.secho("No available heads,try migrate", fg=Color.green)
|
click.secho("No available heads,try migrate first", fg=Color.green)
|
||||||
|
|
||||||
|
|
||||||
@cli.command(help="List all migrate items.")
|
@cli.command(help="List all migrate items.")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def history(ctx):
|
@coro
|
||||||
|
async def history(ctx: Context):
|
||||||
versions = Migrate.get_all_version_files()
|
versions = Migrate.get_all_version_files()
|
||||||
for version in versions:
|
for version in versions:
|
||||||
click.secho(version, fg=Color.green)
|
click.secho(version, fg=Color.green)
|
||||||
@@ -165,6 +196,7 @@ def history(ctx):
|
|||||||
"--location", default="./migrations", show_default=True, help="Migrate store location."
|
"--location", default="./migrations", show_default=True, help="Migrate store location."
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
|
@coro
|
||||||
async def init(
|
async def init(
|
||||||
ctx: Context, tortoise_orm, location,
|
ctx: Context, tortoise_orm, location,
|
||||||
):
|
):
|
||||||
@@ -196,6 +228,7 @@ async def init(
|
|||||||
show_default=True,
|
show_default=True,
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
|
@coro
|
||||||
async def init_db(ctx: Context, safe):
|
async def init_db(ctx: Context, safe):
|
||||||
config = ctx.obj["config"]
|
config = ctx.obj["config"]
|
||||||
location = ctx.obj["location"]
|
location = ctx.obj["location"]
|
||||||
@@ -208,8 +241,6 @@ async def init_db(ctx: Context, safe):
|
|||||||
else:
|
else:
|
||||||
return click.secho(f"Inited {app} already", fg=Color.yellow)
|
return click.secho(f"Inited {app} already", fg=Color.yellow)
|
||||||
|
|
||||||
Migrate.write_old_models(config, app, location)
|
|
||||||
|
|
||||||
await Tortoise.init(config=config)
|
await Tortoise.init(config=config)
|
||||||
connection = get_app_connection(config, app)
|
connection = get_app_connection(config, app)
|
||||||
await generate_schema_for_client(connection, safe)
|
await generate_schema_for_client(connection, safe)
|
||||||
@@ -217,7 +248,9 @@ async def init_db(ctx: Context, safe):
|
|||||||
schema = get_schema_sql(connection, safe)
|
schema = get_schema_sql(connection, safe)
|
||||||
|
|
||||||
version = await Migrate.generate_version()
|
version = await Migrate.generate_version()
|
||||||
await Aerich.create(version=version, app=app)
|
await Aerich.create(
|
||||||
|
version=version, app=app, content=Migrate.get_models_content(config, app, location)
|
||||||
|
)
|
||||||
with open(os.path.join(dirname, version), "w", encoding="utf-8") as f:
|
with open(os.path.join(dirname, version), "w", encoding="utf-8") as f:
|
||||||
content = {
|
content = {
|
||||||
"upgrade": [schema],
|
"upgrade": [schema],
|
||||||
@@ -228,4 +261,4 @@ async def init_db(ctx: Context, safe):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.path.insert(0, ".")
|
sys.path.insert(0, ".")
|
||||||
cli(_anyio_backend="asyncio")
|
cli()
|
||||||
|
@@ -2,7 +2,7 @@ from typing import List, Type
|
|||||||
|
|
||||||
from tortoise import BaseDBAsyncClient, ForeignKeyFieldInstance, ManyToManyFieldInstance, Model
|
from tortoise import BaseDBAsyncClient, ForeignKeyFieldInstance, ManyToManyFieldInstance, Model
|
||||||
from tortoise.backends.base.schema_generator import BaseSchemaGenerator
|
from tortoise.backends.base.schema_generator import BaseSchemaGenerator
|
||||||
from tortoise.fields import Field, JSONField, TextField, UUIDField
|
from tortoise.fields import CASCADE, Field, JSONField, TextField, UUIDField
|
||||||
|
|
||||||
|
|
||||||
class BaseDDL:
|
class BaseDDL:
|
||||||
@@ -11,13 +11,16 @@ class BaseDDL:
|
|||||||
_DROP_TABLE_TEMPLATE = 'DROP TABLE IF EXISTS "{table_name}"'
|
_DROP_TABLE_TEMPLATE = 'DROP TABLE IF EXISTS "{table_name}"'
|
||||||
_ADD_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" ADD {column}'
|
_ADD_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" ADD {column}'
|
||||||
_DROP_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" DROP COLUMN "{column_name}"'
|
_DROP_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" DROP COLUMN "{column_name}"'
|
||||||
|
_RENAME_COLUMN_TEMPLATE = (
|
||||||
|
'ALTER TABLE "{table_name}" RENAME COLUMN "{old_column_name}" TO "{new_column_name}"'
|
||||||
|
)
|
||||||
_ADD_INDEX_TEMPLATE = (
|
_ADD_INDEX_TEMPLATE = (
|
||||||
'ALTER TABLE "{table_name}" ADD {unique} INDEX "{index_name}" ({column_names})'
|
'ALTER TABLE "{table_name}" ADD {unique} INDEX "{index_name}" ({column_names})'
|
||||||
)
|
)
|
||||||
_DROP_INDEX_TEMPLATE = 'ALTER TABLE "{table_name}" DROP INDEX "{index_name}"'
|
_DROP_INDEX_TEMPLATE = 'ALTER TABLE "{table_name}" DROP INDEX "{index_name}"'
|
||||||
_ADD_FK_TEMPLATE = 'ALTER TABLE "{table_name}" ADD CONSTRAINT "{fk_name}" FOREIGN KEY ("{db_column}") REFERENCES "{table}" ("{field}") ON DELETE {on_delete}'
|
_ADD_FK_TEMPLATE = 'ALTER TABLE "{table_name}" ADD CONSTRAINT "{fk_name}" FOREIGN KEY ("{db_column}") REFERENCES "{table}" ("{field}") ON DELETE {on_delete}'
|
||||||
_DROP_FK_TEMPLATE = 'ALTER TABLE "{table_name}" DROP FOREIGN KEY "{fk_name}"'
|
_DROP_FK_TEMPLATE = 'ALTER TABLE "{table_name}" DROP FOREIGN KEY "{fk_name}"'
|
||||||
_M2M_TABLE_TEMPLATE = 'CREATE TABLE "{table_name}" ("{backward_key}" {backward_type} NOT NULL REFERENCES "{backward_table}" ("{backward_field}") ON DELETE CASCADE,"{forward_key}" {forward_type} NOT NULL REFERENCES "{forward_table}" ("{forward_field}") ON DELETE CASCADE){extra}{comment};'
|
_M2M_TABLE_TEMPLATE = 'CREATE TABLE "{table_name}" ("{backward_key}" {backward_type} NOT NULL REFERENCES "{backward_table}" ("{backward_field}") ON DELETE CASCADE,"{forward_key}" {forward_type} NOT NULL REFERENCES "{forward_table}" ("{forward_field}") ON DELETE {on_delete}){extra}{comment};'
|
||||||
_MODIFY_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" MODIFY COLUMN {column}'
|
_MODIFY_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" MODIFY COLUMN {column}'
|
||||||
|
|
||||||
def __init__(self, client: "BaseDBAsyncClient"):
|
def __init__(self, client: "BaseDBAsyncClient"):
|
||||||
@@ -41,6 +44,7 @@ class BaseDDL:
|
|||||||
backward_type=model._meta.pk.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
backward_type=model._meta.pk.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
||||||
forward_key=field.forward_key,
|
forward_key=field.forward_key,
|
||||||
forward_type=field.related_model._meta.pk.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
forward_type=field.related_model._meta.pk.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
||||||
|
on_delete=CASCADE,
|
||||||
extra=self.schema_generator._table_generate_extra(table=field.through),
|
extra=self.schema_generator._table_generate_extra(table=field.through),
|
||||||
comment=self.schema_generator._table_comment_generator(
|
comment=self.schema_generator._table_comment_generator(
|
||||||
table=field.through, comment=field.description
|
table=field.through, comment=field.description
|
||||||
@@ -125,6 +129,13 @@ class BaseDDL:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def rename_column(self, model: "Type[Model]", old_column_name: str, new_column_name: str):
|
||||||
|
return self._RENAME_COLUMN_TEMPLATE.format(
|
||||||
|
table_name=model._meta.db_table,
|
||||||
|
old_column_name=old_column_name,
|
||||||
|
new_column_name=new_column_name,
|
||||||
|
)
|
||||||
|
|
||||||
def add_index(self, model: "Type[Model]", field_names: List[str], unique=False):
|
def add_index(self, model: "Type[Model]", field_names: List[str], unique=False):
|
||||||
return self._ADD_INDEX_TEMPLATE.format(
|
return self._ADD_INDEX_TEMPLATE.format(
|
||||||
unique="UNIQUE" if unique else "",
|
unique="UNIQUE" if unique else "",
|
||||||
|
@@ -9,6 +9,9 @@ class MysqlDDL(BaseDDL):
|
|||||||
_DROP_TABLE_TEMPLATE = "DROP TABLE IF EXISTS `{table_name}`"
|
_DROP_TABLE_TEMPLATE = "DROP TABLE IF EXISTS `{table_name}`"
|
||||||
_ADD_COLUMN_TEMPLATE = "ALTER TABLE `{table_name}` ADD {column}"
|
_ADD_COLUMN_TEMPLATE = "ALTER TABLE `{table_name}` ADD {column}"
|
||||||
_DROP_COLUMN_TEMPLATE = "ALTER TABLE `{table_name}` DROP COLUMN `{column_name}`"
|
_DROP_COLUMN_TEMPLATE = "ALTER TABLE `{table_name}` DROP COLUMN `{column_name}`"
|
||||||
|
_RENAME_COLUMN_TEMPLATE = (
|
||||||
|
"ALTER TABLE `{table_name}` RENAME COLUMN `{old_column_name}` TO `{new_column_name}`"
|
||||||
|
)
|
||||||
_ADD_INDEX_TEMPLATE = (
|
_ADD_INDEX_TEMPLATE = (
|
||||||
"ALTER TABLE `{table_name}` ADD {unique} INDEX `{index_name}` ({column_names})"
|
"ALTER TABLE `{table_name}` ADD {unique} INDEX `{index_name}` ({column_names})"
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
from typing import Type
|
from typing import List, Type
|
||||||
|
|
||||||
from tortoise import Model
|
from tortoise import Model
|
||||||
from tortoise.backends.asyncpg.schema_generator import AsyncpgSchemaGenerator
|
from tortoise.backends.asyncpg.schema_generator import AsyncpgSchemaGenerator
|
||||||
@@ -10,10 +10,17 @@ from aerich.ddl import BaseDDL
|
|||||||
class PostgresDDL(BaseDDL):
|
class PostgresDDL(BaseDDL):
|
||||||
schema_generator_cls = AsyncpgSchemaGenerator
|
schema_generator_cls = AsyncpgSchemaGenerator
|
||||||
DIALECT = AsyncpgSchemaGenerator.DIALECT
|
DIALECT = AsyncpgSchemaGenerator.DIALECT
|
||||||
|
_ADD_INDEX_TEMPLATE = 'CREATE INDEX "{index_name}" ON "{table_name}" ({column_names})'
|
||||||
|
_ADD_UNIQUE_TEMPLATE = (
|
||||||
|
'ALTER TABLE "{table_name}" ADD CONSTRAINT "{index_name}" UNIQUE ({column_names})'
|
||||||
|
)
|
||||||
|
_DROP_INDEX_TEMPLATE = 'DROP INDEX "{index_name}"'
|
||||||
|
_DROP_UNIQUE_TEMPLATE = 'ALTER TABLE "{table_name}" DROP CONSTRAINT "{index_name}"'
|
||||||
_ALTER_DEFAULT_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" {default}'
|
_ALTER_DEFAULT_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" {default}'
|
||||||
_ALTER_NULL_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" {set_drop} NOT NULL'
|
_ALTER_NULL_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" {set_drop} NOT NULL'
|
||||||
_MODIFY_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" TYPE {datatype}'
|
_MODIFY_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" ALTER COLUMN "{column}" TYPE {datatype}'
|
||||||
_SET_COMMENT_TEMPLATE = 'COMMENT ON COLUMN "{table_name}"."{column}" IS {comment}'
|
_SET_COMMENT_TEMPLATE = 'COMMENT ON COLUMN "{table_name}"."{column}" IS {comment}'
|
||||||
|
_DROP_FK_TEMPLATE = 'ALTER TABLE "{table_name}" DROP CONSTRAINT "{fk_name}"'
|
||||||
|
|
||||||
def alter_column_default(self, model: "Type[Model]", field_object: Field):
|
def alter_column_default(self, model: "Type[Model]", field_object: Field):
|
||||||
db_table = model._meta.db_table
|
db_table = model._meta.db_table
|
||||||
@@ -40,6 +47,25 @@ class PostgresDDL(BaseDDL):
|
|||||||
datatype=field_object.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
datatype=field_object.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def add_index(self, model: "Type[Model]", field_names: List[str], unique=False):
|
||||||
|
template = self._ADD_UNIQUE_TEMPLATE if unique else self._ADD_INDEX_TEMPLATE
|
||||||
|
return template.format(
|
||||||
|
index_name=self.schema_generator._generate_index_name(
|
||||||
|
"uid" if unique else "idx", model, field_names
|
||||||
|
),
|
||||||
|
table_name=model._meta.db_table,
|
||||||
|
column_names=", ".join([self.schema_generator.quote(f) for f in field_names]),
|
||||||
|
)
|
||||||
|
|
||||||
|
def drop_index(self, model: "Type[Model]", field_names: List[str], unique=False):
|
||||||
|
template = self._DROP_UNIQUE_TEMPLATE if unique else self._DROP_INDEX_TEMPLATE
|
||||||
|
return template.format(
|
||||||
|
index_name=self.schema_generator._generate_index_name(
|
||||||
|
"uid" if unique else "idx", model, field_names
|
||||||
|
),
|
||||||
|
table_name=model._meta.db_table,
|
||||||
|
)
|
||||||
|
|
||||||
def set_comment(self, model: "Type[Model]", field_object: Field):
|
def set_comment(self, model: "Type[Model]", field_object: Field):
|
||||||
db_table = model._meta.db_table
|
db_table = model._meta.db_table
|
||||||
return self._SET_COMMENT_TEMPLATE.format(
|
return self._SET_COMMENT_TEMPLATE.format(
|
||||||
|
@@ -1,8 +1,19 @@
|
|||||||
|
from typing import Type
|
||||||
|
|
||||||
|
from tortoise import Model
|
||||||
from tortoise.backends.sqlite.schema_generator import SqliteSchemaGenerator
|
from tortoise.backends.sqlite.schema_generator import SqliteSchemaGenerator
|
||||||
|
from tortoise.fields import Field
|
||||||
|
|
||||||
from aerich.ddl import BaseDDL
|
from aerich.ddl import BaseDDL
|
||||||
|
from aerich.exceptions import NotSupportError
|
||||||
|
|
||||||
|
|
||||||
class SqliteDDL(BaseDDL):
|
class SqliteDDL(BaseDDL):
|
||||||
schema_generator_cls = SqliteSchemaGenerator
|
schema_generator_cls = SqliteSchemaGenerator
|
||||||
DIALECT = SqliteSchemaGenerator.DIALECT
|
DIALECT = SqliteSchemaGenerator.DIALECT
|
||||||
|
|
||||||
|
def drop_column(self, model: "Type[Model]", column_name: str):
|
||||||
|
raise NotSupportError("Drop column is unsupported in SQLite.")
|
||||||
|
|
||||||
|
def modify_column(self, model: "Type[Model]", field_object: Field):
|
||||||
|
raise NotSupportError("Modify column is unsupported in SQLite.")
|
||||||
|
7
aerich/enums.py
Normal file
7
aerich/enums.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class Color(str, Enum):
|
||||||
|
green = "green"
|
||||||
|
red = "red"
|
||||||
|
yellow = "yellow"
|
@@ -1,6 +1,4 @@
|
|||||||
class ConfigurationError(Exception):
|
class NotSupportError(Exception):
|
||||||
"""
|
"""
|
||||||
config error
|
raise when features not support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from copy import deepcopy
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
from io import StringIO
|
||||||
from typing import Dict, List, Tuple, Type
|
from typing import Dict, List, Tuple, Type
|
||||||
|
|
||||||
|
import click
|
||||||
from tortoise import (
|
from tortoise import (
|
||||||
BackwardFKRelation,
|
BackwardFKRelation,
|
||||||
BackwardOneToOneRelation,
|
BackwardOneToOneRelation,
|
||||||
@@ -17,7 +18,7 @@ from tortoise import (
|
|||||||
from tortoise.fields import Field
|
from tortoise.fields import Field
|
||||||
|
|
||||||
from aerich.ddl import BaseDDL
|
from aerich.ddl import BaseDDL
|
||||||
from aerich.models import Aerich
|
from aerich.models import MAX_VERSION_LENGTH, Aerich
|
||||||
from aerich.utils import get_app_connection
|
from aerich.utils import get_app_connection
|
||||||
|
|
||||||
|
|
||||||
@@ -29,6 +30,8 @@ class Migrate:
|
|||||||
_upgrade_m2m: List[str] = []
|
_upgrade_m2m: List[str] = []
|
||||||
_downgrade_m2m: List[str] = []
|
_downgrade_m2m: List[str] = []
|
||||||
_aerich = Aerich.__name__
|
_aerich = Aerich.__name__
|
||||||
|
_rename_old = []
|
||||||
|
_rename_new = []
|
||||||
|
|
||||||
ddl: BaseDDL
|
ddl: BaseDDL
|
||||||
migrate_config: dict
|
migrate_config: dict
|
||||||
@@ -39,21 +42,37 @@ class Migrate:
|
|||||||
dialect: str
|
dialect: str
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_old_model_file(cls):
|
def get_old_model_file(cls, app: str, location: str):
|
||||||
return cls.old_models + ".py"
|
return os.path.join(location, app, cls.old_models + ".py")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all_version_files(cls) -> List[str]:
|
def get_all_version_files(cls) -> List[str]:
|
||||||
return sorted(filter(lambda x: x.endswith("json"), os.listdir(cls.migrate_location)))
|
return sorted(
|
||||||
|
filter(lambda x: x.endswith("json"), os.listdir(cls.migrate_location)),
|
||||||
|
key=lambda x: int(x.split("_")[0]),
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_last_version(cls) -> Aerich:
|
async def get_last_version(cls) -> Aerich:
|
||||||
return await Aerich.filter(app=cls.app).first()
|
return await Aerich.filter(app=cls.app).first()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def init_with_old_models(cls, config: dict, app: str, location: str):
|
def remove_old_model_file(cls, app: str, location: str):
|
||||||
migrate_config = cls._get_migrate_config(config, app, location)
|
try:
|
||||||
|
os.unlink(cls.get_old_model_file(app, location))
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def init_with_old_models(cls, config: dict, app: str, location: str):
|
||||||
|
await Tortoise.init(config=config)
|
||||||
|
last_version = await cls.get_last_version()
|
||||||
|
if last_version:
|
||||||
|
content = last_version.content
|
||||||
|
with open(cls.get_old_model_file(app, location), "w") as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
migrate_config = cls._get_migrate_config(config, app, location)
|
||||||
cls.app = app
|
cls.app = app
|
||||||
cls.migrate_config = migrate_config
|
cls.migrate_config = migrate_config
|
||||||
cls.migrate_location = os.path.join(location, app)
|
cls.migrate_location = os.path.join(location, app)
|
||||||
@@ -85,15 +104,22 @@ class Migrate:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def generate_version(cls, name=None):
|
async def generate_version(cls, name=None):
|
||||||
now = datetime.now().strftime("%Y%M%D%H%M%S").replace("/", "")
|
now = datetime.now().strftime("%Y%m%d%H%M%S").replace("/", "")
|
||||||
last_version_num = await cls._get_last_version_num()
|
last_version_num = await cls._get_last_version_num()
|
||||||
if last_version_num is None:
|
if last_version_num is None:
|
||||||
return f"0_{now}_init.json"
|
return f"0_{now}_init.json"
|
||||||
return f"{last_version_num + 1}_{now}_{name}.json"
|
version = f"{last_version_num + 1}_{now}_{name}.json"
|
||||||
|
if len(version) > MAX_VERSION_LENGTH:
|
||||||
|
raise ValueError(f"Version name exceeds maximum length ({MAX_VERSION_LENGTH})")
|
||||||
|
return version
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def _generate_diff_sql(cls, name):
|
async def _generate_diff_sql(cls, name):
|
||||||
version = await cls.generate_version(name)
|
version = await cls.generate_version(name)
|
||||||
|
# delete if same version exists
|
||||||
|
for version_file in cls.get_all_version_files():
|
||||||
|
if version_file.startswith(version.split("_")[0]):
|
||||||
|
os.unlink(os.path.join(cls.migrate_location, version_file))
|
||||||
content = {
|
content = {
|
||||||
"upgrade": cls.upgrade_operators,
|
"upgrade": cls.upgrade_operators,
|
||||||
"downgrade": cls.downgrade_operators,
|
"downgrade": cls.downgrade_operators,
|
||||||
@@ -124,7 +150,7 @@ class Migrate:
|
|||||||
return await cls._generate_diff_sql(name)
|
return await cls._generate_diff_sql(name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _add_operator(cls, operator: str, upgrade=True, fk=False):
|
def _add_operator(cls, operator: str, upgrade=True, fk_m2m=False):
|
||||||
"""
|
"""
|
||||||
add operator,differentiate fk because fk is order limit
|
add operator,differentiate fk because fk is order limit
|
||||||
:param operator:
|
:param operator:
|
||||||
@@ -133,36 +159,16 @@ class Migrate:
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if upgrade:
|
if upgrade:
|
||||||
if fk:
|
if fk_m2m:
|
||||||
cls._upgrade_fk_m2m_index_operators.append(operator)
|
cls._upgrade_fk_m2m_index_operators.append(operator)
|
||||||
else:
|
else:
|
||||||
cls.upgrade_operators.append(operator)
|
cls.upgrade_operators.append(operator)
|
||||||
else:
|
else:
|
||||||
if fk:
|
if fk_m2m:
|
||||||
cls._downgrade_fk_m2m_index_operators.append(operator)
|
cls._downgrade_fk_m2m_index_operators.append(operator)
|
||||||
else:
|
else:
|
||||||
cls.downgrade_operators.append(operator)
|
cls.downgrade_operators.append(operator)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def cp_models(
|
|
||||||
cls, app: str, model_files: List[str], old_model_file,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
cp currents models to old_model_files
|
|
||||||
:param app:
|
|
||||||
:param model_files:
|
|
||||||
:param old_model_file:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
pattern = rf"(\n)?('|\")({app})(.\w+)('|\")"
|
|
||||||
for i, model_file in enumerate(model_files):
|
|
||||||
with open(model_file, "r", encoding="utf-8") as f:
|
|
||||||
content = f.read()
|
|
||||||
ret = re.sub(pattern, rf"\2{cls.diff_app}\4\5", content)
|
|
||||||
mode = "w" if i == 0 else "a"
|
|
||||||
with open(old_model_file, mode, encoding="utf-8") as f:
|
|
||||||
f.write(ret)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_migrate_config(cls, config: dict, app: str, location: str):
|
def _get_migrate_config(cls, config: dict, app: str, location: str):
|
||||||
"""
|
"""
|
||||||
@@ -172,17 +178,16 @@ class Migrate:
|
|||||||
:param location:
|
:param location:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
temp_config = deepcopy(config)
|
|
||||||
path = os.path.join(location, app, cls.old_models)
|
path = os.path.join(location, app, cls.old_models)
|
||||||
path = path.replace(os.sep, ".").lstrip(".")
|
path = path.replace(os.sep, ".").lstrip(".")
|
||||||
temp_config["apps"][cls.diff_app] = {
|
config["apps"][cls.diff_app] = {
|
||||||
"models": [path],
|
"models": [path],
|
||||||
"default_connection": config.get("apps").get(app).get("default_connection", "default"),
|
"default_connection": config.get("apps").get(app).get("default_connection", "default"),
|
||||||
}
|
}
|
||||||
return temp_config
|
return config
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def write_old_models(cls, config: dict, app: str, location: str):
|
def get_models_content(cls, config: dict, app: str, location: str):
|
||||||
"""
|
"""
|
||||||
write new models to old models
|
write new models to old models
|
||||||
:param config:
|
:param config:
|
||||||
@@ -190,14 +195,18 @@ class Migrate:
|
|||||||
:param location:
|
:param location:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
cls.app = app
|
|
||||||
|
|
||||||
old_model_files = []
|
old_model_files = []
|
||||||
models = config.get("apps").get(app).get("models")
|
models = config.get("apps").get(app).get("models")
|
||||||
for model in models:
|
for model in models:
|
||||||
old_model_files.append(import_module(model).__file__)
|
old_model_files.append(import_module(model).__file__)
|
||||||
|
pattern = rf"(\n)?('|\")({app})(.\w+)('|\")"
|
||||||
cls.cp_models(app, old_model_files, os.path.join(location, app, cls.get_old_model_file()))
|
str_io = StringIO()
|
||||||
|
for i, model_file in enumerate(old_model_files):
|
||||||
|
with open(model_file, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
ret = re.sub(pattern, rf"\2{cls.diff_app}\4\5", content)
|
||||||
|
str_io.write(f"{ret}\n")
|
||||||
|
return str_io.getvalue()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def diff_models(
|
def diff_models(
|
||||||
@@ -260,11 +269,35 @@ class Migrate:
|
|||||||
if cls._exclude_field(new_field, upgrade):
|
if cls._exclude_field(new_field, upgrade):
|
||||||
continue
|
continue
|
||||||
if new_key not in old_keys:
|
if new_key not in old_keys:
|
||||||
cls._add_operator(
|
new_field_dict = new_field.describe(serializable=True)
|
||||||
cls._add_field(new_model, new_field),
|
new_field_dict.pop("name", None)
|
||||||
upgrade,
|
new_field_dict.pop("db_column", None)
|
||||||
isinstance(new_field, (ForeignKeyFieldInstance, ManyToManyFieldInstance)),
|
for diff_key in old_keys - new_keys:
|
||||||
)
|
old_field = old_fields_map.get(diff_key)
|
||||||
|
old_field_dict = old_field.describe(serializable=True)
|
||||||
|
old_field_dict.pop("name", None)
|
||||||
|
old_field_dict.pop("db_column", None)
|
||||||
|
if old_field_dict == new_field_dict:
|
||||||
|
if upgrade:
|
||||||
|
is_rename = click.prompt(
|
||||||
|
f"Rename {diff_key} to {new_key}?",
|
||||||
|
default=True,
|
||||||
|
type=bool,
|
||||||
|
show_choices=True,
|
||||||
|
)
|
||||||
|
cls._rename_new.append(new_key)
|
||||||
|
cls._rename_old.append(diff_key)
|
||||||
|
else:
|
||||||
|
is_rename = diff_key in cls._rename_new
|
||||||
|
if is_rename:
|
||||||
|
cls._add_operator(
|
||||||
|
cls._rename_field(new_model, old_field, new_field), upgrade,
|
||||||
|
)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
cls._add_operator(
|
||||||
|
cls._add_field(new_model, new_field), upgrade, cls._is_fk_m2m(new_field),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
old_field = old_fields_map.get(new_key)
|
old_field = old_fields_map.get(new_key)
|
||||||
new_field_dict = new_field.describe(serializable=True)
|
new_field_dict = new_field.describe(serializable=True)
|
||||||
@@ -287,7 +320,12 @@ class Migrate:
|
|||||||
cls._add_operator(
|
cls._add_operator(
|
||||||
cls._set_comment(new_model, new_field), upgrade=upgrade
|
cls._set_comment(new_model, new_field), upgrade=upgrade
|
||||||
)
|
)
|
||||||
cls._add_operator(cls._modify_field(new_model, new_field), upgrade=upgrade)
|
if new_field.field_type != old_field.field_type:
|
||||||
|
cls._add_operator(
|
||||||
|
cls._modify_field(new_model, new_field), upgrade=upgrade
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cls._add_operator(cls._modify_field(new_model, new_field), upgrade=upgrade)
|
||||||
if (old_field.index and not new_field.index) or (
|
if (old_field.index and not new_field.index) or (
|
||||||
old_field.unique and not new_field.unique
|
old_field.unique and not new_field.unique
|
||||||
):
|
):
|
||||||
@@ -306,13 +344,25 @@ class Migrate:
|
|||||||
upgrade,
|
upgrade,
|
||||||
cls._is_fk_m2m(new_field),
|
cls._is_fk_m2m(new_field),
|
||||||
)
|
)
|
||||||
|
if isinstance(new_field, ForeignKeyFieldInstance):
|
||||||
|
if old_field.db_constraint and not new_field.db_constraint:
|
||||||
|
cls._add_operator(
|
||||||
|
cls._drop_fk(new_model, new_field), upgrade, True,
|
||||||
|
)
|
||||||
|
if new_field.db_constraint and not old_field.db_constraint:
|
||||||
|
cls._add_operator(
|
||||||
|
cls._add_fk(new_model, new_field), upgrade, True,
|
||||||
|
)
|
||||||
|
|
||||||
for old_key in old_keys:
|
for old_key in old_keys:
|
||||||
field = old_fields_map.get(old_key)
|
field = old_fields_map.get(old_key)
|
||||||
if old_key not in new_keys and not cls._exclude_field(field, upgrade):
|
if old_key not in new_keys and not cls._exclude_field(field, upgrade):
|
||||||
cls._add_operator(
|
if (upgrade and old_key not in cls._rename_old) or (
|
||||||
cls._remove_field(old_model, field), upgrade, cls._is_fk_m2m(field),
|
not upgrade and old_key not in cls._rename_new
|
||||||
)
|
):
|
||||||
|
cls._add_operator(
|
||||||
|
cls._remove_field(old_model, field), upgrade, cls._is_fk_m2m(field),
|
||||||
|
)
|
||||||
|
|
||||||
for new_index in new_indexes:
|
for new_index in new_indexes:
|
||||||
if new_index not in old_indexes:
|
if new_index not in old_indexes:
|
||||||
@@ -396,6 +446,10 @@ class Migrate:
|
|||||||
def _modify_field(cls, model: Type[Model], field: Field):
|
def _modify_field(cls, model: Type[Model], field: Field):
|
||||||
return cls.ddl.modify_column(model, field)
|
return cls.ddl.modify_column(model, field)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _drop_fk(cls, model: Type[Model], field: ForeignKeyFieldInstance):
|
||||||
|
return cls.ddl.drop_fk(model, field)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _remove_field(cls, model: Type[Model], field: Field):
|
def _remove_field(cls, model: Type[Model], field: Field):
|
||||||
if isinstance(field, ForeignKeyFieldInstance):
|
if isinstance(field, ForeignKeyFieldInstance):
|
||||||
@@ -404,6 +458,10 @@ class Migrate:
|
|||||||
return cls.ddl.drop_m2m(field)
|
return cls.ddl.drop_m2m(field)
|
||||||
return cls.ddl.drop_column(model, field.model_field_name)
|
return cls.ddl.drop_column(model, field.model_field_name)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _rename_field(cls, model: Type[Model], old_field: Field, new_field: Field):
|
||||||
|
return cls.ddl.rename_column(model, old_field.model_field_name, new_field.model_field_name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _add_fk(cls, model: Type[Model], field: ForeignKeyFieldInstance):
|
def _add_fk(cls, model: Type[Model], field: ForeignKeyFieldInstance):
|
||||||
"""
|
"""
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
from tortoise import Model, fields
|
from tortoise import Model, fields
|
||||||
|
|
||||||
|
MAX_VERSION_LENGTH = 255
|
||||||
|
|
||||||
|
|
||||||
class Aerich(Model):
|
class Aerich(Model):
|
||||||
version = fields.CharField(max_length=50)
|
version = fields.CharField(max_length=MAX_VERSION_LENGTH)
|
||||||
app = fields.CharField(max_length=20)
|
app = fields.CharField(max_length=20)
|
||||||
|
content = fields.TextField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ["-id"]
|
ordering = ["-id"]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
from asyncclick import BadOptionUsage, Context
|
from click import BadOptionUsage, Context
|
||||||
from tortoise import BaseDBAsyncClient, Tortoise
|
from tortoise import BaseDBAsyncClient, Tortoise
|
||||||
|
|
||||||
|
|
||||||
|
25
conftest.py
25
conftest.py
@@ -31,24 +31,29 @@ def reset_migrate():
|
|||||||
Migrate._downgrade_m2m = []
|
Migrate._downgrade_m2m = []
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.yield_fixture(scope="session")
|
||||||
def loop():
|
def event_loop():
|
||||||
loop = asyncio.get_event_loop()
|
policy = asyncio.get_event_loop_policy()
|
||||||
return loop
|
res = policy.new_event_loop()
|
||||||
|
asyncio.set_event_loop(res)
|
||||||
|
res._close = res.close
|
||||||
|
res.close = lambda: None
|
||||||
|
|
||||||
|
yield res
|
||||||
|
|
||||||
|
res._close()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session", autouse=True)
|
@pytest.fixture(scope="session", autouse=True)
|
||||||
def initialize_tests(loop, request):
|
async def initialize_tests(event_loop, request):
|
||||||
tortoise_orm["connections"]["diff_models"] = "sqlite://:memory:"
|
tortoise_orm["connections"]["diff_models"] = "sqlite://:memory:"
|
||||||
tortoise_orm["apps"]["diff_models"] = {
|
tortoise_orm["apps"]["diff_models"] = {
|
||||||
"models": ["tests.diff_models"],
|
"models": ["tests.diff_models"],
|
||||||
"default_connection": "diff_models",
|
"default_connection": "diff_models",
|
||||||
}
|
}
|
||||||
|
|
||||||
loop.run_until_complete(Tortoise.init(config=tortoise_orm, _create_db=True))
|
await Tortoise.init(config=tortoise_orm, _create_db=True)
|
||||||
loop.run_until_complete(
|
await generate_schema_for_client(Tortoise.get_connection("default"), safe=True)
|
||||||
generate_schema_for_client(Tortoise.get_connection("default"), safe=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
client = Tortoise.get_connection("default")
|
client = Tortoise.get_connection("default")
|
||||||
if client.schema_generator is MySQLSchemaGenerator:
|
if client.schema_generator is MySQLSchemaGenerator:
|
||||||
@@ -58,4 +63,4 @@ def initialize_tests(loop, request):
|
|||||||
elif client.schema_generator is AsyncpgSchemaGenerator:
|
elif client.schema_generator is AsyncpgSchemaGenerator:
|
||||||
Migrate.ddl = PostgresDDL(client)
|
Migrate.ddl = PostgresDDL(client)
|
||||||
|
|
||||||
request.addfinalizer(lambda: loop.run_until_complete(Tortoise._drop_databases()))
|
request.addfinalizer(lambda: event_loop.run_until_complete(Tortoise._drop_databases()))
|
||||||
|
534
poetry.lock
generated
534
poetry.lock
generated
@@ -18,25 +18,10 @@ description = "asyncio bridge to the standard sqlite3 module"
|
|||||||
name = "aiosqlite"
|
name = "aiosqlite"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
version = "0.13.0"
|
version = "0.15.0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
|
||||||
name = "anyio"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5.3"
|
|
||||||
version = "1.3.1"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
async-generator = "*"
|
typing_extensions = "*"
|
||||||
sniffio = ">=1.1"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
curio = ["curio (>=0.9)"]
|
|
||||||
doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
|
|
||||||
test = ["coverage (>=4.5)", "hypothesis (>=4.0)", "pytest (>=3.7.2)", "uvloop"]
|
|
||||||
trio = ["trio (>=0.12)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
@@ -54,39 +39,16 @@ optional = false
|
|||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "1.4.4"
|
version = "1.4.4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Async generators and context managers for Python 3.5+"
|
|
||||||
name = "async-generator"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "1.10"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A simple anyio-compatible fork of Click, for powerful command line utilities."
|
|
||||||
name = "asyncclick"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
version = "7.0.9"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
anyio = "*"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dev = ["coverage", "pytest-runner", "pytest-trio", "pytest (>=3)", "sphinx", "tox"]
|
|
||||||
docs = ["sphinx"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "main"
|
category = "main"
|
||||||
description = "An asyncio PostgreSQL driver"
|
description = "An asyncio PostgreSQL driver"
|
||||||
name = "asyncpg"
|
name = "asyncpg"
|
||||||
optional = true
|
optional = true
|
||||||
python-versions = ">=3.5.0"
|
python-versions = ">=3.5.0"
|
||||||
version = "0.20.1"
|
version = "0.21.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["Cython (0.29.14)", "pytest (>=3.6.0)", "Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)", "pycodestyle (>=2.5.0,<2.6.0)", "flake8 (>=3.7.9,<3.8.0)", "uvloop (>=0.14.0,<0.15.0)"]
|
dev = ["Cython (0.29.20)", "pytest (>=3.6.0)", "Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)", "pycodestyle (>=2.5.0,<2.6.0)", "flake8 (>=3.7.9,<3.8.0)", "uvloop (>=0.14.0,<0.15.0)"]
|
||||||
docs = ["Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)"]
|
docs = ["Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)"]
|
||||||
test = ["pycodestyle (>=2.5.0,<2.6.0)", "flake8 (>=3.7.9,<3.8.0)", "uvloop (>=0.14.0,<0.15.0)"]
|
test = ["pycodestyle (>=2.5.0,<2.6.0)", "flake8 (>=3.7.9,<3.8.0)", "uvloop (>=0.14.0,<0.15.0)"]
|
||||||
|
|
||||||
@@ -105,13 +67,13 @@ description = "Classes Without Boilerplate"
|
|||||||
name = "attrs"
|
name = "attrs"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
version = "19.3.0"
|
version = "20.2.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
|
dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"]
|
||||||
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
|
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||||
docs = ["sphinx", "zope.interface"]
|
tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
||||||
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
@@ -154,13 +116,13 @@ description = "Foreign Function Interface for Python calling C code."
|
|||||||
name = "cffi"
|
name = "cffi"
|
||||||
optional = true
|
optional = true
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "1.14.0"
|
version = "1.14.3"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pycparser = "*"
|
pycparser = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "main"
|
||||||
description = "Composable command line interface toolkit"
|
description = "Composable command line interface toolkit"
|
||||||
name = "click"
|
name = "click"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -182,17 +144,17 @@ description = "cryptography is a package which provides cryptographic recipes an
|
|||||||
name = "cryptography"
|
name = "cryptography"
|
||||||
optional = true
|
optional = true
|
||||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
|
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
|
||||||
version = "2.9.2"
|
version = "3.1.1"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
cffi = ">=1.8,<1.11.3 || >1.11.3"
|
cffi = ">=1.8,<1.11.3 || >1.11.3"
|
||||||
six = ">=1.4.1"
|
six = ">=1.4.1"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"]
|
docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0,<3.1.0 || >3.1.0,<3.1.1 || >3.1.1)", "sphinx-rtd-theme"]
|
||||||
docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
|
docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||||
idna = ["idna (>=2.1)"]
|
pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
|
||||||
pep8test = ["flake8", "flake8-import-order", "pep8-naming"]
|
ssh = ["bcrypt (>=3.1.5)"]
|
||||||
test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"]
|
test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -215,13 +177,17 @@ description = "the modular source code checker: pep8 pyflakes and co"
|
|||||||
name = "flake8"
|
name = "flake8"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||||
version = "3.8.3"
|
version = "3.8.4"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
mccabe = ">=0.6.0,<0.7.0"
|
mccabe = ">=0.6.0,<0.7.0"
|
||||||
pycodestyle = ">=2.6.0a1,<2.7.0"
|
pycodestyle = ">=2.6.0a1,<2.7.0"
|
||||||
pyflakes = ">=2.2.0,<2.3.0"
|
pyflakes = ">=2.2.0,<2.3.0"
|
||||||
|
|
||||||
|
[package.dependencies.importlib-metadata]
|
||||||
|
python = "<3.8"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Git Object Database"
|
description = "Git Object Database"
|
||||||
@@ -239,18 +205,42 @@ description = "Python Git Library"
|
|||||||
name = "gitpython"
|
name = "gitpython"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.4"
|
python-versions = ">=3.4"
|
||||||
version = "3.1.3"
|
version = "3.1.9"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
gitdb = ">=4.0.1,<5"
|
gitdb = ">=4.0.1,<5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Read metadata from Python packages"
|
||||||
|
marker = "python_version < \"3.8\""
|
||||||
|
name = "importlib-metadata"
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||||
|
version = "2.0.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
zipp = ">=0.5"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx", "rst.linker"]
|
||||||
|
testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||||
|
name = "iniconfig"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "1.0.1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "main"
|
category = "main"
|
||||||
description = "Simple module to parse ISO 8601 dates"
|
description = "Simple module to parse ISO 8601 dates"
|
||||||
name = "iso8601"
|
name = "iso8601"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "0.1.12"
|
version = "0.1.13"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
@@ -258,10 +248,11 @@ description = "A Python utility / library to sort Python imports."
|
|||||||
name = "isort"
|
name = "isort"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6,<4.0"
|
python-versions = ">=3.6,<4.0"
|
||||||
version = "5.0.3"
|
version = "5.6.1"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
pipfile_deprecated_finder = ["pipreqs", "requirementslib", "tomlkit (>=0.5.3)"]
|
colors = ["colorama (>=0.4.3,<0.5.0)"]
|
||||||
|
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
|
||||||
requirements_deprecated_finder = ["pipreqs", "pip-api"]
|
requirements_deprecated_finder = ["pipreqs", "pip-api"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -272,14 +263,6 @@ optional = false
|
|||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "More routines for operating on iterables, beyond itertools"
|
|
||||||
name = "more-itertools"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "8.4.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Core utilities for Python packages"
|
description = "Core utilities for Python packages"
|
||||||
@@ -305,8 +288,8 @@ category = "dev"
|
|||||||
description = "Python Build Reasonableness"
|
description = "Python Build Reasonableness"
|
||||||
name = "pbr"
|
name = "pbr"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=2.6"
|
||||||
version = "5.4.5"
|
version = "5.5.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
@@ -316,6 +299,11 @@ optional = false
|
|||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
[package.dependencies.importlib-metadata]
|
||||||
|
python = "<3.8"
|
||||||
|
version = ">=0.12"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["pre-commit", "tox"]
|
dev = ["pre-commit", "tox"]
|
||||||
|
|
||||||
@@ -349,7 +337,7 @@ description = "Data validation and settings management using python 3.6 type hin
|
|||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
version = "1.5.1"
|
version = "1.6.1"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||||
@@ -389,7 +377,7 @@ description = "A SQL query builder API for Python"
|
|||||||
name = "pypika"
|
name = "pypika"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "0.37.15"
|
version = "0.42.1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
@@ -397,20 +385,24 @@ description = "pytest: simple powerful testing with Python"
|
|||||||
name = "pytest"
|
name = "pytest"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
version = "5.4.3"
|
version = "6.1.1"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
atomicwrites = ">=1.0"
|
atomicwrites = ">=1.0"
|
||||||
attrs = ">=17.4.0"
|
attrs = ">=17.4.0"
|
||||||
colorama = "*"
|
colorama = "*"
|
||||||
more-itertools = ">=4.0.0"
|
iniconfig = "*"
|
||||||
packaging = "*"
|
packaging = "*"
|
||||||
pluggy = ">=0.12,<1.0"
|
pluggy = ">=0.12,<1.0"
|
||||||
py = ">=1.5.0"
|
py = ">=1.8.2"
|
||||||
wcwidth = "*"
|
toml = "*"
|
||||||
|
|
||||||
|
[package.dependencies.importlib-metadata]
|
||||||
|
python = "<3.8"
|
||||||
|
version = ">=0.12"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
checkqa-mypy = ["mypy (v0.761)"]
|
checkqa_mypy = ["mypy (0.780)"]
|
||||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -433,26 +425,41 @@ description = "run tests in isolated forked subprocesses"
|
|||||||
name = "pytest-forked"
|
name = "pytest-forked"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pytest = ">=3.1.0"
|
py = "*"
|
||||||
|
pytest = ">=3.10"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Thin-wrapper around the mock package for easier use with pytest"
|
||||||
|
name = "pytest-mock"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
version = "3.3.1"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pytest = ">=5.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pre-commit", "tox", "pytest-asyncio"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "pytest xdist plugin for distributed testing and loop-on-failing modes"
|
description = "pytest xdist plugin for distributed testing and loop-on-failing modes"
|
||||||
name = "pytest-xdist"
|
name = "pytest-xdist"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=3.5"
|
||||||
version = "1.32.0"
|
version = "2.1.0"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
execnet = ">=1.1"
|
execnet = ">=1.1"
|
||||||
pytest = ">=4.4.0"
|
pytest = ">=6.0.0"
|
||||||
pytest-forked = "*"
|
pytest-forked = "*"
|
||||||
six = "*"
|
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
|
psutil = ["psutil (>=3.0)"]
|
||||||
testing = ["filelock"]
|
testing = ["filelock"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -469,7 +476,7 @@ description = "Alternative regular expression module, to replace re."
|
|||||||
name = "regex"
|
name = "regex"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "2020.6.8"
|
version = "2020.9.27"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "main"
|
category = "main"
|
||||||
@@ -487,25 +494,21 @@ optional = false
|
|||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
version = "3.0.4"
|
version = "3.0.4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Sniff out which async library your code is running under"
|
|
||||||
name = "sniffio"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "1.1.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Manage dynamic plugins for Python applications"
|
description = "Manage dynamic plugins for Python applications"
|
||||||
name = "stevedore"
|
name = "stevedore"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
version = "2.0.1"
|
version = "3.2.2"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
||||||
|
|
||||||
|
[package.dependencies.importlib-metadata]
|
||||||
|
python = "<3.8"
|
||||||
|
version = ">=1.7.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||||
@@ -520,12 +523,12 @@ description = "Easy async ORM for python, built with relations in mind"
|
|||||||
name = "tortoise-orm"
|
name = "tortoise-orm"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "0.16.13"
|
version = "0.16.16"
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
aiosqlite = ">=0.11.0"
|
aiosqlite = ">=0.11.0"
|
||||||
iso8601 = ">=0.1.12"
|
iso8601 = ">=0.1.12"
|
||||||
pypika = ">=0.36.5"
|
pypika = ">=0.39.0"
|
||||||
typing-extensions = ">=3.7"
|
typing-extensions = ">=3.7"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@@ -545,22 +548,27 @@ description = "Backported and Experimental Type Hints for Python 3.5+"
|
|||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "3.7.4.2"
|
version = "3.7.4.3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Measures the displayed width of unicode strings in a terminal"
|
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||||
name = "wcwidth"
|
marker = "python_version < \"3.8\""
|
||||||
|
name = "zipp"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.6"
|
||||||
version = "0.2.5"
|
version = "3.3.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||||
|
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||||
|
|
||||||
[extras]
|
[extras]
|
||||||
dbdrivers = ["aiomysql", "asyncpg"]
|
dbdrivers = ["aiomysql", "asyncpg"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "485702557f7b65db14e44d459fb1c985f56caf4b14857006ef96304d6516d976"
|
content-hash = "43fe9c0036f4d55d38f82c263887d8a7d9a35a597e02036b70a631955ff73149"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.7"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
aiomysql = [
|
aiomysql = [
|
||||||
@@ -568,12 +576,8 @@ aiomysql = [
|
|||||||
{file = "aiomysql-0.0.20.tar.gz", hash = "sha256:d89ce25d44dadb43cf2d9e4603bd67b7a0ad12d5e67208de013629ba648df2ba"},
|
{file = "aiomysql-0.0.20.tar.gz", hash = "sha256:d89ce25d44dadb43cf2d9e4603bd67b7a0ad12d5e67208de013629ba648df2ba"},
|
||||||
]
|
]
|
||||||
aiosqlite = [
|
aiosqlite = [
|
||||||
{file = "aiosqlite-0.13.0-py3-none-any.whl", hash = "sha256:50688c40632ae249f986ab3ae2c66a45c0535b84a5d4aae0e0be572b5fed6909"},
|
{file = "aiosqlite-0.15.0-py3-none-any.whl", hash = "sha256:19b984b6702aed9f1c85c023f37296954547fc4030dae8e9d027b2a930bed78b"},
|
||||||
{file = "aiosqlite-0.13.0.tar.gz", hash = "sha256:6e92961ae9e606b43b05e29b129e346b29e400fcbd63e3c0c564d89230257645"},
|
{file = "aiosqlite-0.15.0.tar.gz", hash = "sha256:a2884793f4dc8f2798d90e1dfecb2b56a6d479cf039f7ec52356a7fd5f3bdc57"},
|
||||||
]
|
|
||||||
anyio = [
|
|
||||||
{file = "anyio-1.3.1-py3-none-any.whl", hash = "sha256:f21b4fafeec1b7db81e09a907e44e374a1e39718d782a488fdfcdcf949c8950c"},
|
|
||||||
{file = "anyio-1.3.1.tar.gz", hash = "sha256:a46bb2b7743455434afd9adea848a3c4e0b7321aee3e9d08844b11d348d3b5a0"},
|
|
||||||
]
|
]
|
||||||
apipkg = [
|
apipkg = [
|
||||||
{file = "apipkg-1.5-py2.py3-none-any.whl", hash = "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"},
|
{file = "apipkg-1.5-py2.py3-none-any.whl", hash = "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"},
|
||||||
@@ -583,43 +587,40 @@ appdirs = [
|
|||||||
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||||
]
|
]
|
||||||
async-generator = [
|
|
||||||
{file = "async_generator-1.10-py3-none-any.whl", hash = "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b"},
|
|
||||||
{file = "async_generator-1.10.tar.gz", hash = "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"},
|
|
||||||
]
|
|
||||||
asyncclick = [
|
|
||||||
{file = "asyncclick-7.0.9.tar.gz", hash = "sha256:62cebf3eca36d973802e2dd521ca1db11c5bf4544e9795e093d1a53cb688a8c2"},
|
|
||||||
]
|
|
||||||
asyncpg = [
|
asyncpg = [
|
||||||
{file = "asyncpg-0.20.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:f7184689177eeb5a11fa1b2baf3f6f2e26bfd7a85acf4de1a3adbd0867d7c0e2"},
|
{file = "asyncpg-0.21.0-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:09badce47a4645cfe523cc8a182bd047d5d62af0caaea77935e6a3c9e77dc364"},
|
||||||
{file = "asyncpg-0.20.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:f0c9719ac00615f097fe91082b785bce36dbf02a5ec4115ede0ebfd2cd9500cb"},
|
{file = "asyncpg-0.21.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6b7807bfedd24dd15cfb2c17c60977ce01410615ecc285268b5144a944ec97ff"},
|
||||||
{file = "asyncpg-0.20.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1388caa456070dab102be874205e3ae8fd1de2577d5de9fa22e65ba5c0f8b110"},
|
{file = "asyncpg-0.21.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dfd491e9865e64a3e91f1587b1d88d71dde1cfb850429253a73d4d44b98c3a0f"},
|
||||||
{file = "asyncpg-0.20.1-cp35-cp35m-win32.whl", hash = "sha256:ec6e7046c98730cb2ba4df41387e10cb8963a3ac2918f69ae416f8aab9ca7b1b"},
|
{file = "asyncpg-0.21.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:8587e206d78e739ca83a40c9982e03b28f8904c95a54dc782da99e86cf768f73"},
|
||||||
{file = "asyncpg-0.20.1-cp35-cp35m-win_amd64.whl", hash = "sha256:25edb0b947eb632b6b53e5a4b36cba5677297bb34cbaba270019714d0a5fed76"},
|
{file = "asyncpg-0.21.0-cp35-cp35m-win32.whl", hash = "sha256:b1b10916c006e5c2c0dcd5dadeb38cbf61ecd20d66c50164e82f31c22c7e329d"},
|
||||||
{file = "asyncpg-0.20.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:95cd2df61ee00b789bdcd04a080e6d9188693b841db2bf9a87ebaed9e53147e0"},
|
{file = "asyncpg-0.21.0-cp35-cp35m-win_amd64.whl", hash = "sha256:22d161618b59e4b56fb2a5cc956aa9eeb336d07cae924a5b90c9aa1c2d137f15"},
|
||||||
{file = "asyncpg-0.20.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:058baec9d6b75612412baa872a1aa47317d0ff88c318a49f9c4a2389043d5a8d"},
|
{file = "asyncpg-0.21.0-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:f2d1aa890ffd1ad062a38b7ff7488764b3da4b0a24e0c83d7bbb1d1a6609df15"},
|
||||||
{file = "asyncpg-0.20.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c773c7dbe2f4d3ebc9e3030e94303e45d6742e6c2fc25da0c46a56ea3d83caeb"},
|
{file = "asyncpg-0.21.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:e7bfb9269aeb11d78d50accf1be46823683ced99209b7199e307cdf7da849522"},
|
||||||
{file = "asyncpg-0.20.1-cp36-cp36m-win32.whl", hash = "sha256:5664d1bd8abe64fc60a0e701eb85fa1d8c9a4a8018a5a59164d27238f2caf395"},
|
{file = "asyncpg-0.21.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:68f7981f65317a5d5f497ec76919b488dbe0e838f8b924e7517a680bdca0f308"},
|
||||||
{file = "asyncpg-0.20.1-cp36-cp36m-win_amd64.whl", hash = "sha256:57666dfae38f4dbf84ffbf0c5c0f78733fef0e8e083230275dcb9ccad1d5ee09"},
|
{file = "asyncpg-0.21.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:a4c1feb285ec3807ecd5b54ab718a3d065bb55c93ebaf800670eadde31484be8"},
|
||||||
{file = "asyncpg-0.20.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:0c336903c3b08e970f8af2f606332f1738dba156bca83ed0467dc2f5c70da796"},
|
{file = "asyncpg-0.21.0-cp36-cp36m-win32.whl", hash = "sha256:dddf4d4c5e781310a36529c3c87c1746837c2d2c7ec0f2ec4e4f06450d83c50a"},
|
||||||
{file = "asyncpg-0.20.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ad5ba062e09673b1a4b8d0facaf5a6d9719bf7b337440d10b07fe994d90a9552"},
|
{file = "asyncpg-0.21.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ee29c4707eb8fb3d3a0348ac4495e06f4afaca3ee38c3bebedc9c8b239125ff"},
|
||||||
{file = "asyncpg-0.20.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba90d3578bc6dddcbce461875672fd9bdb34f0b8215b68612dd3b65a956ff51c"},
|
{file = "asyncpg-0.21.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:4421407b07b4e22291a226d9de0bf6f3ea8158aa1c12d83bfedbf5c22e13cd55"},
|
||||||
{file = "asyncpg-0.20.1-cp37-cp37m-win32.whl", hash = "sha256:da238592235717419a6a7b5edc8564da410ebfd056ca4ecc41e70b1b5df86fba"},
|
{file = "asyncpg-0.21.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:aa2e0cb14c01a2f58caeeca7196681b30aa22dd22c82845560b401df5e98e171"},
|
||||||
{file = "asyncpg-0.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:74510234c294c6a6767089ba9c938f09a491426c24405634eb357bd91dffd734"},
|
{file = "asyncpg-0.21.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:28584783dd0d21b2a0db3bfe54fb12f21425a4cc015e4419083ea99e6de0de9b"},
|
||||||
{file = "asyncpg-0.20.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:391aea89871df8c1560750af6c7170f2772c2d133b34772acf3637e3cf4db93e"},
|
{file = "asyncpg-0.21.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:915cebc8a7693c8a5e89804fa106678dbedcc50d0270ebab0b75f16e668bd59b"},
|
||||||
{file = "asyncpg-0.20.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a981500bf6947926e53c48f4d60ae080af1b4ad7fa78e363465a5b5ad4f2b65e"},
|
{file = "asyncpg-0.21.0-cp37-cp37m-win32.whl", hash = "sha256:308b8ba32c42ea1ed84c034320678ec307296bb4faf3fbbeb9f9e20b46db99a5"},
|
||||||
{file = "asyncpg-0.20.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a9e6fd6f0f9e8bd77e9a4e1ef9a4f83a80674d9136a754ae3603e915da96b627"},
|
{file = "asyncpg-0.21.0-cp37-cp37m-win_amd64.whl", hash = "sha256:888593b6688faa7ec1c97ff7f2ca3b5a5b8abb15478fe2a13c5012b607a28737"},
|
||||||
{file = "asyncpg-0.20.1-cp38-cp38-win32.whl", hash = "sha256:e39aac2b3a2f839ce65aa255ce416de899c58b7d38d601d24ca35558e13b48e3"},
|
{file = "asyncpg-0.21.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:ecd5232cf64f58caac3b85103f1223fdf20e9eb43bfa053c56ef9e5dd76ab099"},
|
||||||
{file = "asyncpg-0.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:2af6a5a705accd36e13292ea43d08c20b15e52d684beb522cb3a7d3c9c8f3f48"},
|
{file = "asyncpg-0.21.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3ade59cef35bffae6dbc6f5f3ef56e1d53c67f0a7adc3cc4c714f07568d2d717"},
|
||||||
{file = "asyncpg-0.20.1.tar.gz", hash = "sha256:394bf19bdddbba07a38cd6fb526ebf66e120444d6b3097332b78efd5b26495b0"},
|
{file = "asyncpg-0.21.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ea26604932719b3612541e606508d9d604211f56a65806ccf8c92c64104f4f8a"},
|
||||||
|
{file = "asyncpg-0.21.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7e51d1a012b779e0ebf0195f80d004f65d3c60cc06f0fa1cef9d3e536262abbd"},
|
||||||
|
{file = "asyncpg-0.21.0-cp38-cp38-win32.whl", hash = "sha256:615c7e3adb46e1f2e3aff45e4ee9401b4f24f9f7153e5530a0753369be72a5c6"},
|
||||||
|
{file = "asyncpg-0.21.0-cp38-cp38-win_amd64.whl", hash = "sha256:823eca36108bd64a8600efe7bbf1230aa00f2defa3be42852f3b61ab40cf1226"},
|
||||||
|
{file = "asyncpg-0.21.0.tar.gz", hash = "sha256:53cb2a0eb326f61e34ef4da2db01d87ce9c0ebe396f65a295829df334e31863f"},
|
||||||
]
|
]
|
||||||
atomicwrites = [
|
atomicwrites = [
|
||||||
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
||||||
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
||||||
]
|
]
|
||||||
attrs = [
|
attrs = [
|
||||||
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
|
{file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"},
|
||||||
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
|
{file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"},
|
||||||
]
|
]
|
||||||
bandit = [
|
bandit = [
|
||||||
{file = "bandit-1.6.2-py2.py3-none-any.whl", hash = "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952"},
|
{file = "bandit-1.6.2-py2.py3-none-any.whl", hash = "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952"},
|
||||||
@@ -630,34 +631,42 @@ black = [
|
|||||||
{file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
|
{file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
|
||||||
]
|
]
|
||||||
cffi = [
|
cffi = [
|
||||||
{file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"},
|
{file = "cffi-1.14.3-2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc"},
|
||||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"},
|
{file = "cffi-1.14.3-2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768"},
|
||||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"},
|
{file = "cffi-1.14.3-2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d"},
|
||||||
{file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"},
|
{file = "cffi-1.14.3-2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1"},
|
||||||
{file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"},
|
{file = "cffi-1.14.3-2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca"},
|
||||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"},
|
{file = "cffi-1.14.3-2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a"},
|
||||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"},
|
{file = "cffi-1.14.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c"},
|
||||||
{file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"},
|
{file = "cffi-1.14.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730"},
|
||||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"},
|
{file = "cffi-1.14.3-cp27-cp27m-win32.whl", hash = "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d"},
|
||||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"},
|
{file = "cffi-1.14.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05"},
|
||||||
{file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"},
|
{file = "cffi-1.14.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b"},
|
||||||
{file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"},
|
{file = "cffi-1.14.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171"},
|
||||||
{file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"},
|
{file = "cffi-1.14.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f"},
|
||||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"},
|
{file = "cffi-1.14.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4"},
|
||||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"},
|
{file = "cffi-1.14.3-cp35-cp35m-win32.whl", hash = "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d"},
|
||||||
{file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"},
|
{file = "cffi-1.14.3-cp35-cp35m-win_amd64.whl", hash = "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d"},
|
||||||
{file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"},
|
{file = "cffi-1.14.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3"},
|
||||||
{file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"},
|
{file = "cffi-1.14.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808"},
|
||||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"},
|
{file = "cffi-1.14.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537"},
|
||||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"},
|
{file = "cffi-1.14.3-cp36-cp36m-win32.whl", hash = "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0"},
|
||||||
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"},
|
{file = "cffi-1.14.3-cp36-cp36m-win_amd64.whl", hash = "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e"},
|
||||||
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"},
|
{file = "cffi-1.14.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1"},
|
||||||
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"},
|
{file = "cffi-1.14.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579"},
|
||||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"},
|
{file = "cffi-1.14.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394"},
|
||||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"},
|
{file = "cffi-1.14.3-cp37-cp37m-win32.whl", hash = "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc"},
|
||||||
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"},
|
{file = "cffi-1.14.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869"},
|
||||||
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"},
|
{file = "cffi-1.14.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e"},
|
||||||
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
|
{file = "cffi-1.14.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828"},
|
||||||
|
{file = "cffi-1.14.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9"},
|
||||||
|
{file = "cffi-1.14.3-cp38-cp38-win32.whl", hash = "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522"},
|
||||||
|
{file = "cffi-1.14.3-cp38-cp38-win_amd64.whl", hash = "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15"},
|
||||||
|
{file = "cffi-1.14.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d"},
|
||||||
|
{file = "cffi-1.14.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c"},
|
||||||
|
{file = "cffi-1.14.3-cp39-cp39-win32.whl", hash = "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b"},
|
||||||
|
{file = "cffi-1.14.3-cp39-cp39-win_amd64.whl", hash = "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3"},
|
||||||
|
{file = "cffi-1.14.3.tar.gz", hash = "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591"},
|
||||||
]
|
]
|
||||||
click = [
|
click = [
|
||||||
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
|
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
|
||||||
@@ -668,59 +677,66 @@ colorama = [
|
|||||||
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
|
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
|
||||||
]
|
]
|
||||||
cryptography = [
|
cryptography = [
|
||||||
{file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"},
|
{file = "cryptography-3.1.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:65beb15e7f9c16e15934569d29fb4def74ea1469d8781f6b3507ab896d6d8719"},
|
||||||
{file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"},
|
{file = "cryptography-3.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:983c0c3de4cb9fcba68fd3f45ed846eb86a2a8b8d8bc5bb18364c4d00b3c61fe"},
|
||||||
{file = "cryptography-2.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365"},
|
{file = "cryptography-3.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:e97a3b627e3cb63c415a16245d6cef2139cca18bb1183d1b9375a1c14e83f3b3"},
|
||||||
{file = "cryptography-2.9.2-cp27-cp27m-win32.whl", hash = "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0"},
|
{file = "cryptography-3.1.1-cp27-cp27m-win32.whl", hash = "sha256:cb179acdd4ae1e4a5a160d80b87841b3d0e0be84af46c7bb2cd7ece57a39c4ba"},
|
||||||
{file = "cryptography-2.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55"},
|
{file = "cryptography-3.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:b372026ebf32fe2523159f27d9f0e9f485092e43b00a5adacf732192a70ba118"},
|
||||||
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270"},
|
{file = "cryptography-3.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:680da076cad81cdf5ffcac50c477b6790be81768d30f9da9e01960c4b18a66db"},
|
||||||
{file = "cryptography-2.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf"},
|
{file = "cryptography-3.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5d52c72449bb02dd45a773a203196e6d4fae34e158769c896012401f33064396"},
|
||||||
{file = "cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d"},
|
{file = "cryptography-3.1.1-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:f0e099fc4cc697450c3dd4031791559692dd941a95254cb9aeded66a7aa8b9bc"},
|
||||||
{file = "cryptography-2.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785"},
|
{file = "cryptography-3.1.1-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:a7597ffc67987b37b12e09c029bd1dc43965f75d328076ae85721b84046e9ca7"},
|
||||||
{file = "cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b"},
|
{file = "cryptography-3.1.1-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4549b137d8cbe3c2eadfa56c0c858b78acbeff956bd461e40000b2164d9167c6"},
|
||||||
{file = "cryptography-2.9.2-cp35-cp35m-win32.whl", hash = "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae"},
|
{file = "cryptography-3.1.1-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:89aceb31cd5f9fc2449fe8cf3810797ca52b65f1489002d58fe190bfb265c536"},
|
||||||
{file = "cryptography-2.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b"},
|
{file = "cryptography-3.1.1-cp35-cp35m-win32.whl", hash = "sha256:559d622aef2a2dff98a892eef321433ba5bc55b2485220a8ca289c1ecc2bd54f"},
|
||||||
{file = "cryptography-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6"},
|
{file = "cryptography-3.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:451cdf60be4dafb6a3b78802006a020e6cd709c22d240f94f7a0696240a17154"},
|
||||||
{file = "cryptography-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3"},
|
{file = "cryptography-3.1.1-cp36-abi3-win32.whl", hash = "sha256:762bc5a0df03c51ee3f09c621e1cee64e3a079a2b5020de82f1613873d79ee70"},
|
||||||
{file = "cryptography-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b"},
|
{file = "cryptography-3.1.1-cp36-abi3-win_amd64.whl", hash = "sha256:b12e715c10a13ca1bd27fbceed9adc8c5ff640f8e1f7ea76416352de703523c8"},
|
||||||
{file = "cryptography-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e"},
|
{file = "cryptography-3.1.1-cp36-cp36m-win32.whl", hash = "sha256:21b47c59fcb1c36f1113f3709d37935368e34815ea1d7073862e92f810dc7499"},
|
||||||
{file = "cryptography-2.9.2-cp38-cp38-win32.whl", hash = "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0"},
|
{file = "cryptography-3.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:48ee615a779ffa749d7d50c291761dc921d93d7cf203dca2db663b4f193f0e49"},
|
||||||
{file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"},
|
{file = "cryptography-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:b2bded09c578d19e08bd2c5bb8fed7f103e089752c9cf7ca7ca7de522326e921"},
|
||||||
{file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"},
|
{file = "cryptography-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f99317a0fa2e49917689b8cf977510addcfaaab769b3f899b9c481bbd76730c2"},
|
||||||
|
{file = "cryptography-3.1.1-cp38-cp38-win32.whl", hash = "sha256:ab010e461bb6b444eaf7f8c813bb716be2d78ab786103f9608ffd37a4bd7d490"},
|
||||||
|
{file = "cryptography-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:99d4984aabd4c7182050bca76176ce2dbc9fa9748afe583a7865c12954d714ba"},
|
||||||
|
{file = "cryptography-3.1.1.tar.gz", hash = "sha256:9d9fc6a16357965d282dd4ab6531013935425d0dc4950df2e0cf2a1b1ac1017d"},
|
||||||
]
|
]
|
||||||
execnet = [
|
execnet = [
|
||||||
{file = "execnet-1.7.1-py2.py3-none-any.whl", hash = "sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"},
|
{file = "execnet-1.7.1-py2.py3-none-any.whl", hash = "sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"},
|
||||||
{file = "execnet-1.7.1.tar.gz", hash = "sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50"},
|
{file = "execnet-1.7.1.tar.gz", hash = "sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50"},
|
||||||
]
|
]
|
||||||
flake8 = [
|
flake8 = [
|
||||||
{file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"},
|
{file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
|
||||||
{file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"},
|
{file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
|
||||||
]
|
]
|
||||||
gitdb = [
|
gitdb = [
|
||||||
{file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"},
|
{file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"},
|
||||||
{file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"},
|
{file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"},
|
||||||
]
|
]
|
||||||
gitpython = [
|
gitpython = [
|
||||||
{file = "GitPython-3.1.3-py3-none-any.whl", hash = "sha256:ef1d60b01b5ce0040ad3ec20bc64f783362d41fa0822a2742d3586e1f49bb8ac"},
|
{file = "GitPython-3.1.9-py3-none-any.whl", hash = "sha256:138016d519bf4dd55b22c682c904ed2fd0235c3612b2f8f65ce218ff358deed8"},
|
||||||
{file = "GitPython-3.1.3.tar.gz", hash = "sha256:e107af4d873daed64648b4f4beb89f89f0cfbe3ef558fc7821ed2331c2f8da1a"},
|
{file = "GitPython-3.1.9.tar.gz", hash = "sha256:a03f728b49ce9597a6655793207c6ab0da55519368ff5961e4a74ae475b9fa8e"},
|
||||||
|
]
|
||||||
|
importlib-metadata = [
|
||||||
|
{file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"},
|
||||||
|
{file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"},
|
||||||
|
]
|
||||||
|
iniconfig = [
|
||||||
|
{file = "iniconfig-1.0.1-py3-none-any.whl", hash = "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437"},
|
||||||
|
{file = "iniconfig-1.0.1.tar.gz", hash = "sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69"},
|
||||||
]
|
]
|
||||||
iso8601 = [
|
iso8601 = [
|
||||||
{file = "iso8601-0.1.12-py2.py3-none-any.whl", hash = "sha256:210e0134677cc0d02f6028087fee1df1e1d76d372ee1db0bf30bf66c5c1c89a3"},
|
{file = "iso8601-0.1.13-py2.py3-none-any.whl", hash = "sha256:694be0743e9f1535ea873bfc7bd6fb62380c62b75822761859428073a17fd39c"},
|
||||||
{file = "iso8601-0.1.12-py3-none-any.whl", hash = "sha256:bbbae5fb4a7abfe71d4688fd64bff70b91bbd74ef6a99d964bab18f7fdf286dd"},
|
{file = "iso8601-0.1.13-py3-none-any.whl", hash = "sha256:6f02f01dd13320a7f280e58516dc8d1950dfaf77527cc365a398cd9de4d3c692"},
|
||||||
{file = "iso8601-0.1.12.tar.gz", hash = "sha256:49c4b20e1f38aa5cf109ddcd39647ac419f928512c869dc01d5c7098eddede82"},
|
{file = "iso8601-0.1.13.tar.gz", hash = "sha256:f7dec22af52025d4526be94cc1303c7d8f5379b746a3f54a8c8446384392eeb1"},
|
||||||
]
|
]
|
||||||
isort = [
|
isort = [
|
||||||
{file = "isort-5.0.3-py3-none-any.whl", hash = "sha256:3fbfad425b0a08a2969c5e1821d88785c210a08656c029c28931a1620f2d0f12"},
|
{file = "isort-5.6.1-py3-none-any.whl", hash = "sha256:dd3211f513f4a92ec1ec1876fc1dc3c686649c349d49523f5b5adbb0814e5960"},
|
||||||
{file = "isort-5.0.3.tar.gz", hash = "sha256:4c48d4cd773a6226baaaa176839e6f7ff82ef7c7842f6c54374fe2b14df4024b"},
|
{file = "isort-5.6.1.tar.gz", hash = "sha256:2f510f34ae18a8d0958c53eec51ef84fd099f07c4c639676525acbcd7b5bd3ff"},
|
||||||
]
|
]
|
||||||
mccabe = [
|
mccabe = [
|
||||||
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
||||||
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
||||||
]
|
]
|
||||||
more-itertools = [
|
|
||||||
{file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"},
|
|
||||||
{file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"},
|
|
||||||
]
|
|
||||||
packaging = [
|
packaging = [
|
||||||
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
|
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
|
||||||
{file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
|
{file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
|
||||||
@@ -730,8 +746,8 @@ pathspec = [
|
|||||||
{file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
|
{file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
|
||||||
]
|
]
|
||||||
pbr = [
|
pbr = [
|
||||||
{file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"},
|
{file = "pbr-5.5.0-py2.py3-none-any.whl", hash = "sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"},
|
||||||
{file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"},
|
{file = "pbr-5.5.0.tar.gz", hash = "sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea"},
|
||||||
]
|
]
|
||||||
pluggy = [
|
pluggy = [
|
||||||
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
||||||
@@ -750,23 +766,23 @@ pycparser = [
|
|||||||
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
|
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
|
||||||
]
|
]
|
||||||
pydantic = [
|
pydantic = [
|
||||||
{file = "pydantic-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2a6904e9f18dea58f76f16b95cba6a2f20b72d787abd84ecd67ebc526e61dce6"},
|
{file = "pydantic-1.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:418b84654b60e44c0cdd5384294b0e4bc1ebf42d6e873819424f3b78b8690614"},
|
||||||
{file = "pydantic-1.5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da8099fca5ee339d5572cfa8af12cf0856ae993406f0b1eb9bb38c8a660e7416"},
|
{file = "pydantic-1.6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4900b8820b687c9a3ed753684337979574df20e6ebe4227381d04b3c3c628f99"},
|
||||||
{file = "pydantic-1.5.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:68dece67bff2b3a5cc188258e46b49f676a722304f1c6148ae08e9291e284d98"},
|
{file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b49c86aecde15cde33835d5d6360e55f5e0067bb7143a8303bf03b872935c75b"},
|
||||||
{file = "pydantic-1.5.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ab863853cb502480b118187d670f753be65ec144e1654924bec33d63bc8b3ce2"},
|
{file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2de562a456c4ecdc80cf1a8c3e70c666625f7d02d89a6174ecf63754c734592e"},
|
||||||
{file = "pydantic-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:2007eb062ed0e57875ce8ead12760a6e44bf5836e6a1a7ea81d71eeecf3ede0f"},
|
{file = "pydantic-1.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f769141ab0abfadf3305d4fcf36660e5cf568a666dd3efab7c3d4782f70946b1"},
|
||||||
{file = "pydantic-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:20a15a303ce1e4d831b4e79c17a4a29cb6740b12524f5bba3ea363bff65732bc"},
|
{file = "pydantic-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2dc946b07cf24bee4737ced0ae77e2ea6bc97489ba5a035b603bd1b40ad81f7e"},
|
||||||
{file = "pydantic-1.5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:473101121b1bd454c8effc9fe66d54812fdc128184d9015c5aaa0d4e58a6d338"},
|
{file = "pydantic-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:36dbf6f1be212ab37b5fda07667461a9219c956181aa5570a00edfb0acdfe4a1"},
|
||||||
{file = "pydantic-1.5.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:9be755919258d5d168aeffbe913ed6e8bd562e018df7724b68cabdee3371e331"},
|
{file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1783c1d927f9e1366e0e0609ae324039b2479a1a282a98ed6a6836c9ed02002c"},
|
||||||
{file = "pydantic-1.5.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:b96ce81c4b5ca62ab81181212edfd057beaa41411cd9700fbcb48a6ba6564b4e"},
|
{file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cf3933c98cb5e808b62fae509f74f209730b180b1e3c3954ee3f7949e083a7df"},
|
||||||
{file = "pydantic-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:93b9f265329d9827f39f0fca68f5d72cc8321881cdc519a1304fa73b9f8a75bd"},
|
{file = "pydantic-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f8af9b840a9074e08c0e6dc93101de84ba95df89b267bf7151d74c553d66833b"},
|
||||||
{file = "pydantic-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2c753d355126ddd1eefeb167fa61c7037ecd30b98e7ebecdc0d1da463b4ea09"},
|
{file = "pydantic-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:40d765fa2d31d5be8e29c1794657ad46f5ee583a565c83cea56630d3ae5878b9"},
|
||||||
{file = "pydantic-1.5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8433dbb87246c0f562af75d00fa80155b74e4f6924b0db6a2078a3cd2f11c6c4"},
|
{file = "pydantic-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3fa799f3cfff3e5f536cbd389368fc96a44bb30308f258c94ee76b73bd60531d"},
|
||||||
{file = "pydantic-1.5.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0a1cdf24e567d42dc762d3fed399bd211a13db2e8462af9dfa93b34c41648efb"},
|
{file = "pydantic-1.6.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6c3f162ba175678218629f446a947e3356415b6b09122dcb364e58c442c645a7"},
|
||||||
{file = "pydantic-1.5.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:8be325fc9da897029ee48d1b5e40df817d97fe969f3ac3fd2434ba7e198c55d5"},
|
{file = "pydantic-1.6.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:eb75dc1809875d5738df14b6566ccf9fd9c0bcde4f36b72870f318f16b9f5c20"},
|
||||||
{file = "pydantic-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:3714a4056f5bdbecf3a41e0706ec9b228c9513eee2ad884dc2c568c4dfa540e9"},
|
{file = "pydantic-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:530d7222a2786a97bc59ee0e0ebbe23728f82974b1f1ad9a11cd966143410633"},
|
||||||
{file = "pydantic-1.5.1-py36.py37.py38-none-any.whl", hash = "sha256:70f27d2f0268f490fe3de0a9b6fca7b7492b8fd6623f9fecd25b221ebee385e3"},
|
{file = "pydantic-1.6.1-py36.py37.py38-none-any.whl", hash = "sha256:b5b3489cb303d0f41ad4a7390cf606a5f2c7a94dcba20c051cd1c653694cb14d"},
|
||||||
{file = "pydantic-1.5.1.tar.gz", hash = "sha256:f0018613c7a0d19df3240c2a913849786f21b6539b9f23d85ce4067489dfacfa"},
|
{file = "pydantic-1.6.1.tar.gz", hash = "sha256:54122a8ed6b75fe1dd80797f8251ad2063ea348a03b77218d73ea9fe19bd4e73"},
|
||||||
]
|
]
|
||||||
pyflakes = [
|
pyflakes = [
|
||||||
{file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
|
{file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
|
||||||
@@ -781,23 +797,27 @@ pyparsing = [
|
|||||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
||||||
]
|
]
|
||||||
pypika = [
|
pypika = [
|
||||||
{file = "PyPika-0.37.15.tar.gz", hash = "sha256:f00c217330d91bbb5bc26c4cb54a8016b899fb8d5a8f7cb25b30861260fa4239"},
|
{file = "PyPika-0.42.1.tar.gz", hash = "sha256:f9466259179d5cb12d6cf3d453f4370a511039a6dd88fcb5089f22ba8824b408"},
|
||||||
]
|
]
|
||||||
pytest = [
|
pytest = [
|
||||||
{file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
|
{file = "pytest-6.1.1-py3-none-any.whl", hash = "sha256:7a8190790c17d79a11f847fba0b004ee9a8122582ebff4729a082c109e81a4c9"},
|
||||||
{file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
|
{file = "pytest-6.1.1.tar.gz", hash = "sha256:8f593023c1a0f916110285b6efd7f99db07d59546e3d8c36fc60e2ab05d3be92"},
|
||||||
]
|
]
|
||||||
pytest-asyncio = [
|
pytest-asyncio = [
|
||||||
{file = "pytest-asyncio-0.14.0.tar.gz", hash = "sha256:9882c0c6b24429449f5f969a5158b528f39bde47dc32e85b9f0403965017e700"},
|
{file = "pytest-asyncio-0.14.0.tar.gz", hash = "sha256:9882c0c6b24429449f5f969a5158b528f39bde47dc32e85b9f0403965017e700"},
|
||||||
{file = "pytest_asyncio-0.14.0-py3-none-any.whl", hash = "sha256:2eae1e34f6c68fc0a9dc12d4bea190483843ff4708d24277c41568d6b6044f1d"},
|
{file = "pytest_asyncio-0.14.0-py3-none-any.whl", hash = "sha256:2eae1e34f6c68fc0a9dc12d4bea190483843ff4708d24277c41568d6b6044f1d"},
|
||||||
]
|
]
|
||||||
pytest-forked = [
|
pytest-forked = [
|
||||||
{file = "pytest-forked-1.2.0.tar.gz", hash = "sha256:65f96334863d9cbe53d21f73e8febc4dd61b8d1fdcac7b487d9af07a5d02a938"},
|
{file = "pytest-forked-1.3.0.tar.gz", hash = "sha256:6aa9ac7e00ad1a539c41bec6d21011332de671e938c7637378ec9710204e37ca"},
|
||||||
{file = "pytest_forked-1.2.0-py2.py3-none-any.whl", hash = "sha256:42a438336731465c5bd76ab38e1645647ac55914a08b507efbabe8783a08aa6c"},
|
{file = "pytest_forked-1.3.0-py2.py3-none-any.whl", hash = "sha256:dc4147784048e70ef5d437951728825a131b81714b398d5d52f17c7c144d8815"},
|
||||||
|
]
|
||||||
|
pytest-mock = [
|
||||||
|
{file = "pytest-mock-3.3.1.tar.gz", hash = "sha256:a4d6d37329e4a893e77d9ffa89e838dd2b45d5dc099984cf03c703ac8411bb82"},
|
||||||
|
{file = "pytest_mock-3.3.1-py3-none-any.whl", hash = "sha256:024e405ad382646318c4281948aadf6fe1135632bea9cc67366ea0c4098ef5f2"},
|
||||||
]
|
]
|
||||||
pytest-xdist = [
|
pytest-xdist = [
|
||||||
{file = "pytest-xdist-1.32.0.tar.gz", hash = "sha256:1d4166dcac69adb38eeaedb88c8fada8588348258a3492ab49ba9161f2971129"},
|
{file = "pytest-xdist-2.1.0.tar.gz", hash = "sha256:82d938f1a24186520e2d9d3a64ef7d9ac7ecdf1a0659e095d18e596b8cbd0672"},
|
||||||
{file = "pytest_xdist-1.32.0-py2.py3-none-any.whl", hash = "sha256:ba5ec9fde3410bd9a116ff7e4f26c92e02fa3d27975ef3ad03f330b3d4b54e91"},
|
{file = "pytest_xdist-2.1.0-py3-none-any.whl", hash = "sha256:7c629016b3bb006b88ac68e2b31551e7becf173c76b977768848e2bbed594d90"},
|
||||||
]
|
]
|
||||||
pyyaml = [
|
pyyaml = [
|
||||||
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
|
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
|
||||||
@@ -813,27 +833,33 @@ pyyaml = [
|
|||||||
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"},
|
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"},
|
||||||
]
|
]
|
||||||
regex = [
|
regex = [
|
||||||
{file = "regex-2020.6.8-cp27-cp27m-win32.whl", hash = "sha256:fbff901c54c22425a5b809b914a3bfaf4b9570eee0e5ce8186ac71eb2025191c"},
|
{file = "regex-2020.9.27-cp27-cp27m-win32.whl", hash = "sha256:d23a18037313714fb3bb5a94434d3151ee4300bae631894b1ac08111abeaa4a3"},
|
||||||
{file = "regex-2020.6.8-cp27-cp27m-win_amd64.whl", hash = "sha256:112e34adf95e45158c597feea65d06a8124898bdeac975c9087fe71b572bd938"},
|
{file = "regex-2020.9.27-cp27-cp27m-win_amd64.whl", hash = "sha256:84e9407db1b2eb368b7ecc283121b5e592c9aaedbe8c78b1a2f1102eb2e21d19"},
|
||||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:92d8a043a4241a710c1cf7593f5577fbb832cf6c3a00ff3fc1ff2052aff5dd89"},
|
{file = "regex-2020.9.27-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5f18875ac23d9aa2f060838e8b79093e8bb2313dbaaa9f54c6d8e52a5df097be"},
|
||||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bae83f2a56ab30d5353b47f9b2a33e4aac4de9401fb582b55c42b132a8ac3868"},
|
{file = "regex-2020.9.27-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ae91972f8ac958039920ef6e8769277c084971a142ce2b660691793ae44aae6b"},
|
||||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b2ba0f78b3ef375114856cbdaa30559914d081c416b431f2437f83ce4f8b7f2f"},
|
{file = "regex-2020.9.27-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9a02d0ae31d35e1ec12a4ea4d4cca990800f66a917d0fb997b20fbc13f5321fc"},
|
||||||
{file = "regex-2020.6.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:95fa7726d073c87141f7bbfb04c284901f8328e2d430eeb71b8ffdd5742a5ded"},
|
{file = "regex-2020.9.27-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ebbe29186a3d9b0c591e71b7393f1ae08c83cb2d8e517d2a822b8f7ec99dfd8b"},
|
||||||
{file = "regex-2020.6.8-cp36-cp36m-win32.whl", hash = "sha256:e3cdc9423808f7e1bb9c2e0bdb1c9dc37b0607b30d646ff6faf0d4e41ee8fee3"},
|
{file = "regex-2020.9.27-cp36-cp36m-win32.whl", hash = "sha256:4707f3695b34335afdfb09be3802c87fa0bc27030471dbc082f815f23688bc63"},
|
||||||
{file = "regex-2020.6.8-cp36-cp36m-win_amd64.whl", hash = "sha256:c78e66a922de1c95a208e4ec02e2e5cf0bb83a36ceececc10a72841e53fbf2bd"},
|
{file = "regex-2020.9.27-cp36-cp36m-win_amd64.whl", hash = "sha256:9bc13e0d20b97ffb07821aa3e113f9998e84994fe4d159ffa3d3a9d1b805043b"},
|
||||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:08997a37b221a3e27d68ffb601e45abfb0093d39ee770e4257bd2f5115e8cb0a"},
|
{file = "regex-2020.9.27-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f1b3afc574a3db3b25c89161059d857bd4909a1269b0b3cb3c904677c8c4a3f7"},
|
||||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2f6f211633ee8d3f7706953e9d3edc7ce63a1d6aad0be5dcee1ece127eea13ae"},
|
{file = "regex-2020.9.27-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5533a959a1748a5c042a6da71fe9267a908e21eded7a4f373efd23a2cbdb0ecc"},
|
||||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:55b4c25cbb3b29f8d5e63aeed27b49fa0f8476b0d4e1b3171d85db891938cc3a"},
|
{file = "regex-2020.9.27-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:1fe0a41437bbd06063aa184c34804efa886bcc128222e9916310c92cd54c3b4c"},
|
||||||
{file = "regex-2020.6.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:89cda1a5d3e33ec9e231ece7307afc101b5217523d55ef4dc7fb2abd6de71ba3"},
|
{file = "regex-2020.9.27-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:c570f6fa14b9c4c8a4924aaad354652366577b4f98213cf76305067144f7b100"},
|
||||||
{file = "regex-2020.6.8-cp37-cp37m-win32.whl", hash = "sha256:690f858d9a94d903cf5cada62ce069b5d93b313d7d05456dbcd99420856562d9"},
|
{file = "regex-2020.9.27-cp37-cp37m-win32.whl", hash = "sha256:eda4771e0ace7f67f58bc5b560e27fb20f32a148cbc993b0c3835970935c2707"},
|
||||||
{file = "regex-2020.6.8-cp37-cp37m-win_amd64.whl", hash = "sha256:1700419d8a18c26ff396b3b06ace315b5f2a6e780dad387e4c48717a12a22c29"},
|
{file = "regex-2020.9.27-cp37-cp37m-win_amd64.whl", hash = "sha256:60b0e9e6dc45683e569ec37c55ac20c582973841927a85f2d8a7d20ee80216ab"},
|
||||||
{file = "regex-2020.6.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:654cb773b2792e50151f0e22be0f2b6e1c3a04c5328ff1d9d59c0398d37ef610"},
|
{file = "regex-2020.9.27-cp38-cp38-manylinux1_i686.whl", hash = "sha256:088afc8c63e7bd187a3c70a94b9e50ab3f17e1d3f52a32750b5b77dbe99ef5ef"},
|
||||||
{file = "regex-2020.6.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:52e1b4bef02f4040b2fd547357a170fc1146e60ab310cdbdd098db86e929b387"},
|
{file = "regex-2020.9.27-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eaf548d117b6737df379fdd53bdde4f08870e66d7ea653e230477f071f861121"},
|
||||||
{file = "regex-2020.6.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:cf59bbf282b627130f5ba68b7fa3abdb96372b24b66bdf72a4920e8153fc7910"},
|
{file = "regex-2020.9.27-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:41bb65f54bba392643557e617316d0d899ed5b4946dccee1cb6696152b29844b"},
|
||||||
{file = "regex-2020.6.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5aaa5928b039ae440d775acea11d01e42ff26e1561c0ffcd3d805750973c6baf"},
|
{file = "regex-2020.9.27-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:8d69cef61fa50c8133382e61fd97439de1ae623fe943578e477e76a9d9471637"},
|
||||||
{file = "regex-2020.6.8-cp38-cp38-win32.whl", hash = "sha256:97712e0d0af05febd8ab63d2ef0ab2d0cd9deddf4476f7aa153f76feef4b2754"},
|
{file = "regex-2020.9.27-cp38-cp38-win32.whl", hash = "sha256:f2388013e68e750eaa16ccbea62d4130180c26abb1d8e5d584b9baf69672b30f"},
|
||||||
{file = "regex-2020.6.8-cp38-cp38-win_amd64.whl", hash = "sha256:6ad8663c17db4c5ef438141f99e291c4d4edfeaacc0ce28b5bba2b0bf273d9b5"},
|
{file = "regex-2020.9.27-cp38-cp38-win_amd64.whl", hash = "sha256:4318d56bccfe7d43e5addb272406ade7a2274da4b70eb15922a071c58ab0108c"},
|
||||||
{file = "regex-2020.6.8.tar.gz", hash = "sha256:e9b64e609d37438f7d6e68c2546d2cb8062f3adb27e6336bc129b51be20773ac"},
|
{file = "regex-2020.9.27-cp39-cp39-manylinux1_i686.whl", hash = "sha256:84cada8effefe9a9f53f9b0d2ba9b7b6f5edf8d2155f9fdbe34616e06ececf81"},
|
||||||
|
{file = "regex-2020.9.27-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:816064fc915796ea1f26966163f6845de5af78923dfcecf6551e095f00983650"},
|
||||||
|
{file = "regex-2020.9.27-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:5d892a4f1c999834eaa3c32bc9e8b976c5825116cde553928c4c8e7e48ebda67"},
|
||||||
|
{file = "regex-2020.9.27-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c9443124c67b1515e4fe0bb0aa18df640965e1030f468a2a5dc2589b26d130ad"},
|
||||||
|
{file = "regex-2020.9.27-cp39-cp39-win32.whl", hash = "sha256:49f23ebd5ac073765ecbcf046edc10d63dcab2f4ae2bce160982cb30df0c0302"},
|
||||||
|
{file = "regex-2020.9.27-cp39-cp39-win_amd64.whl", hash = "sha256:3d20024a70b97b4f9546696cbf2fd30bae5f42229fbddf8661261b1eaff0deb7"},
|
||||||
|
{file = "regex-2020.9.27.tar.gz", hash = "sha256:a6f32aea4260dfe0e55dc9733ea162ea38f0ea86aa7d0f77b15beac5bf7b369d"},
|
||||||
]
|
]
|
||||||
six = [
|
six = [
|
||||||
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
|
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
|
||||||
@@ -843,20 +869,16 @@ smmap = [
|
|||||||
{file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"},
|
{file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"},
|
||||||
{file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"},
|
{file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"},
|
||||||
]
|
]
|
||||||
sniffio = [
|
|
||||||
{file = "sniffio-1.1.0-py3-none-any.whl", hash = "sha256:20ed6d5b46f8ae136d00b9dcb807615d83ed82ceea6b2058cecb696765246da5"},
|
|
||||||
{file = "sniffio-1.1.0.tar.gz", hash = "sha256:8e3810100f69fe0edd463d02ad407112542a11ffdc29f67db2bf3771afb87a21"},
|
|
||||||
]
|
|
||||||
stevedore = [
|
stevedore = [
|
||||||
{file = "stevedore-2.0.1-py3-none-any.whl", hash = "sha256:c4724f8d7b8f6be42130663855d01a9c2414d6046055b5a65ab58a0e38637688"},
|
{file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"},
|
||||||
{file = "stevedore-2.0.1.tar.gz", hash = "sha256:609912b87df5ad338ff8e44d13eaad4f4170a65b79ae9cb0aa5632598994a1b7"},
|
{file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"},
|
||||||
]
|
]
|
||||||
toml = [
|
toml = [
|
||||||
{file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"},
|
{file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"},
|
||||||
{file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
|
{file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
|
||||||
]
|
]
|
||||||
tortoise-orm = [
|
tortoise-orm = [
|
||||||
{file = "tortoise-orm-0.16.13.tar.gz", hash = "sha256:5f6fa4430a570172cb49517a97d45338dbfb1a690ed707030467efd154e67855"},
|
{file = "tortoise-orm-0.16.16.tar.gz", hash = "sha256:dc0c7909324a6c224076936adb3b1b154a8d2b13ff51e4232f0bdc3d65841185"},
|
||||||
]
|
]
|
||||||
typed-ast = [
|
typed-ast = [
|
||||||
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
|
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
|
||||||
@@ -882,11 +904,11 @@ typed-ast = [
|
|||||||
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
|
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
|
||||||
]
|
]
|
||||||
typing-extensions = [
|
typing-extensions = [
|
||||||
{file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"},
|
{file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
|
||||||
{file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"},
|
{file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
|
||||||
{file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"},
|
{file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
|
||||||
]
|
]
|
||||||
wcwidth = [
|
zipp = [
|
||||||
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
|
{file = "zipp-3.3.0-py3-none-any.whl", hash = "sha256:eed8ec0b8d1416b2ca33516a37a08892442f3954dee131e92cfd92d8fe3e7066"},
|
||||||
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
{file = "zipp-3.3.0.tar.gz", hash = "sha256:64ad89efee774d1897a58607895d80789c59778ea02185dd846ac38394a8642b"},
|
||||||
]
|
]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "aerich"
|
name = "aerich"
|
||||||
version = "0.2.1"
|
version = "0.3.1"
|
||||||
description = "A database migrations tool for Tortoise ORM."
|
description = "A database migrations tool for Tortoise ORM."
|
||||||
authors = ["long2ice <long2ice@gmail.com>"]
|
authors = ["long2ice <long2ice@gmail.com>"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@@ -12,12 +12,12 @@ keywords = ["migrate", "Tortoise-ORM", "mysql"]
|
|||||||
packages = [
|
packages = [
|
||||||
{ include = "aerich" }
|
{ include = "aerich" }
|
||||||
]
|
]
|
||||||
include = ["CHANGELOG.rst", "LICENSE", "README.md"]
|
include = ["CHANGELOG.md", "LICENSE", "README.md"]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.8"
|
python = "^3.7"
|
||||||
tortoise-orm = "*"
|
tortoise-orm = "*"
|
||||||
asyncclick = "*"
|
click = "*"
|
||||||
pydantic = "*"
|
pydantic = "*"
|
||||||
aiomysql = {version = "*", optional = true}
|
aiomysql = {version = "*", optional = true}
|
||||||
asyncpg = {version = "*", optional = true}
|
asyncpg = {version = "*", optional = true}
|
||||||
@@ -30,6 +30,7 @@ pytest = "*"
|
|||||||
pytest-xdist = "*"
|
pytest-xdist = "*"
|
||||||
pytest-asyncio = "*"
|
pytest-asyncio = "*"
|
||||||
bandit = "*"
|
bandit = "*"
|
||||||
|
pytest-mock = "*"
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
dbdrivers = ["aiomysql", "asyncpg"]
|
dbdrivers = ["aiomysql", "asyncpg"]
|
||||||
@@ -39,4 +40,4 @@ requires = ["poetry>=0.12"]
|
|||||||
build-backend = "poetry.masonry.api"
|
build-backend = "poetry.masonry.api"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
aerich = "aerich.cli:main"
|
aerich = "aerich.cli:main"
|
||||||
|
@@ -22,15 +22,21 @@ class Status(IntEnum):
|
|||||||
|
|
||||||
|
|
||||||
class User(Model):
|
class User(Model):
|
||||||
username = fields.CharField(max_length=20,)
|
username = fields.CharField(max_length=20)
|
||||||
password = fields.CharField(max_length=200)
|
password = fields.CharField(max_length=200)
|
||||||
last_login = fields.DatetimeField(description="Last Login", default=datetime.datetime.now)
|
last_login_at = fields.DatetimeField(description="Last Login", default=datetime.datetime.now)
|
||||||
is_active = fields.BooleanField(default=True, description="Is Active")
|
is_active = fields.BooleanField(default=True, description="Is Active")
|
||||||
is_superuser = fields.BooleanField(default=False, description="Is SuperUser")
|
is_superuser = fields.BooleanField(default=False, description="Is SuperUser")
|
||||||
avatar = fields.CharField(max_length=200, default="")
|
avatar = fields.CharField(max_length=200, default="")
|
||||||
intro = fields.TextField(default="")
|
intro = fields.TextField(default="")
|
||||||
|
|
||||||
|
|
||||||
|
class Email(Model):
|
||||||
|
email = fields.CharField(max_length=200)
|
||||||
|
is_primary = fields.BooleanField(default=False)
|
||||||
|
user = fields.ForeignKeyField("diff_models.User", db_constraint=True)
|
||||||
|
|
||||||
|
|
||||||
class Category(Model):
|
class Category(Model):
|
||||||
slug = fields.CharField(max_length=200)
|
slug = fields.CharField(max_length=200)
|
||||||
user = fields.ForeignKeyField("diff_models.User", description="User")
|
user = fields.ForeignKeyField("diff_models.User", description="User")
|
||||||
|
@@ -31,6 +31,12 @@ class User(Model):
|
|||||||
intro = fields.TextField(default="")
|
intro = fields.TextField(default="")
|
||||||
|
|
||||||
|
|
||||||
|
class Email(Model):
|
||||||
|
email = fields.CharField(max_length=200)
|
||||||
|
is_primary = fields.BooleanField(default=False)
|
||||||
|
user = fields.ForeignKeyField("models.User", db_constraint=False)
|
||||||
|
|
||||||
|
|
||||||
class Category(Model):
|
class Category(Model):
|
||||||
slug = fields.CharField(max_length=200)
|
slug = fields.CharField(max_length=200)
|
||||||
name = fields.CharField(max_length=200)
|
name = fields.CharField(max_length=200)
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
from aerich.ddl.mysql import MysqlDDL
|
from aerich.ddl.mysql import MysqlDDL
|
||||||
from aerich.ddl.postgres import PostgresDDL
|
from aerich.ddl.postgres import PostgresDDL
|
||||||
from aerich.ddl.sqlite import SqliteDDL
|
from aerich.ddl.sqlite import SqliteDDL
|
||||||
|
from aerich.exceptions import NotSupportError
|
||||||
from aerich.migrate import Migrate
|
from aerich.migrate import Migrate
|
||||||
from tests.models import Category, User
|
from tests.models import Category, User
|
||||||
|
|
||||||
@@ -63,27 +66,26 @@ def test_add_column():
|
|||||||
|
|
||||||
|
|
||||||
def test_modify_column():
|
def test_modify_column():
|
||||||
ret = Migrate.ddl.modify_column(Category, Category._meta.fields_map.get("name"))
|
if isinstance(Migrate.ddl, SqliteDDL):
|
||||||
if isinstance(Migrate.ddl, MysqlDDL):
|
with pytest.raises(NotSupportError):
|
||||||
assert ret == "ALTER TABLE `category` MODIFY COLUMN `name` VARCHAR(200) NOT NULL"
|
ret0 = Migrate.ddl.modify_column(Category, Category._meta.fields_map.get("name"))
|
||||||
elif isinstance(Migrate.ddl, PostgresDDL):
|
ret1 = Migrate.ddl.modify_column(User, User._meta.fields_map.get("is_active"))
|
||||||
assert ret == 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200)'
|
|
||||||
else:
|
else:
|
||||||
assert ret == 'ALTER TABLE "category" MODIFY COLUMN "name" VARCHAR(200) NOT NULL'
|
ret0 = Migrate.ddl.modify_column(Category, Category._meta.fields_map.get("name"))
|
||||||
|
ret1 = Migrate.ddl.modify_column(User, User._meta.fields_map.get("is_active"))
|
||||||
|
if isinstance(Migrate.ddl, MysqlDDL):
|
||||||
|
assert ret0 == "ALTER TABLE `category` MODIFY COLUMN `name` VARCHAR(200) NOT NULL"
|
||||||
|
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||||
|
assert ret0 == 'ALTER TABLE "category" ALTER COLUMN "name" TYPE VARCHAR(200)'
|
||||||
|
|
||||||
ret = Migrate.ddl.modify_column(User, User._meta.fields_map.get("is_active"))
|
|
||||||
if isinstance(Migrate.ddl, MysqlDDL):
|
if isinstance(Migrate.ddl, MysqlDDL):
|
||||||
assert (
|
assert (
|
||||||
ret
|
ret1
|
||||||
== "ALTER TABLE `user` MODIFY COLUMN `is_active` BOOL NOT NULL COMMENT 'Is Active' DEFAULT 1"
|
== "ALTER TABLE `user` MODIFY COLUMN `is_active` BOOL NOT NULL COMMENT 'Is Active' DEFAULT 1"
|
||||||
)
|
)
|
||||||
elif isinstance(Migrate.ddl, PostgresDDL):
|
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||||
assert ret == 'ALTER TABLE "user" ALTER COLUMN "is_active" TYPE BOOL'
|
assert ret1 == 'ALTER TABLE "user" ALTER COLUMN "is_active" TYPE BOOL'
|
||||||
else:
|
|
||||||
assert (
|
|
||||||
ret
|
|
||||||
== 'ALTER TABLE "user" MODIFY COLUMN "is_active" INT NOT NULL DEFAULT 1 /* Is Active */'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_alter_column_default():
|
def test_alter_column_default():
|
||||||
@@ -131,10 +133,14 @@ def test_set_comment():
|
|||||||
|
|
||||||
|
|
||||||
def test_drop_column():
|
def test_drop_column():
|
||||||
ret = Migrate.ddl.drop_column(Category, "name")
|
if isinstance(Migrate.ddl, SqliteDDL):
|
||||||
|
with pytest.raises(NotSupportError):
|
||||||
|
ret = Migrate.ddl.drop_column(Category, "name")
|
||||||
|
else:
|
||||||
|
ret = Migrate.ddl.drop_column(Category, "name")
|
||||||
if isinstance(Migrate.ddl, MysqlDDL):
|
if isinstance(Migrate.ddl, MysqlDDL):
|
||||||
assert ret == "ALTER TABLE `category` DROP COLUMN `name`"
|
assert ret == "ALTER TABLE `category` DROP COLUMN `name`"
|
||||||
else:
|
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||||
assert ret == 'ALTER TABLE "category" DROP COLUMN "name"'
|
assert ret == 'ALTER TABLE "category" DROP COLUMN "name"'
|
||||||
|
|
||||||
|
|
||||||
@@ -146,6 +152,12 @@ def test_add_index():
|
|||||||
assert (
|
assert (
|
||||||
index_u == "ALTER TABLE `category` ADD UNIQUE INDEX `uid_category_name_8b0cb9` (`name`)"
|
index_u == "ALTER TABLE `category` ADD UNIQUE INDEX `uid_category_name_8b0cb9` (`name`)"
|
||||||
)
|
)
|
||||||
|
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||||
|
assert index == 'CREATE INDEX "idx_category_name_8b0cb9" ON "category" ("name")'
|
||||||
|
assert (
|
||||||
|
index_u
|
||||||
|
== 'ALTER TABLE "category" ADD CONSTRAINT "uid_category_name_8b0cb9" UNIQUE ("name")'
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
assert index == 'ALTER TABLE "category" ADD INDEX "idx_category_name_8b0cb9" ("name")'
|
assert index == 'ALTER TABLE "category" ADD INDEX "idx_category_name_8b0cb9" ("name")'
|
||||||
assert (
|
assert (
|
||||||
@@ -155,10 +167,16 @@ def test_add_index():
|
|||||||
|
|
||||||
def test_drop_index():
|
def test_drop_index():
|
||||||
ret = Migrate.ddl.drop_index(Category, ["name"])
|
ret = Migrate.ddl.drop_index(Category, ["name"])
|
||||||
|
ret_u = Migrate.ddl.drop_index(Category, ["name"], True)
|
||||||
if isinstance(Migrate.ddl, MysqlDDL):
|
if isinstance(Migrate.ddl, MysqlDDL):
|
||||||
assert ret == "ALTER TABLE `category` DROP INDEX `idx_category_name_8b0cb9`"
|
assert ret == "ALTER TABLE `category` DROP INDEX `idx_category_name_8b0cb9`"
|
||||||
|
assert ret_u == "ALTER TABLE `category` DROP INDEX `uid_category_name_8b0cb9`"
|
||||||
|
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||||
|
assert ret == 'DROP INDEX "idx_category_name_8b0cb9"'
|
||||||
|
assert ret_u == 'ALTER TABLE "category" DROP CONSTRAINT "uid_category_name_8b0cb9"'
|
||||||
else:
|
else:
|
||||||
assert ret == 'ALTER TABLE "category" DROP INDEX "idx_category_name_8b0cb9"'
|
assert ret == 'ALTER TABLE "category" DROP INDEX "idx_category_name_8b0cb9"'
|
||||||
|
assert ret_u == 'ALTER TABLE "category" DROP INDEX "uid_category_name_8b0cb9"'
|
||||||
|
|
||||||
|
|
||||||
def test_add_fk():
|
def test_add_fk():
|
||||||
@@ -179,5 +197,7 @@ def test_drop_fk():
|
|||||||
ret = Migrate.ddl.drop_fk(Category, Category._meta.fields_map.get("user"))
|
ret = Migrate.ddl.drop_fk(Category, Category._meta.fields_map.get("user"))
|
||||||
if isinstance(Migrate.ddl, MysqlDDL):
|
if isinstance(Migrate.ddl, MysqlDDL):
|
||||||
assert ret == "ALTER TABLE `category` DROP FOREIGN KEY `fk_category_user_e2e3874c`"
|
assert ret == "ALTER TABLE `category` DROP FOREIGN KEY `fk_category_user_e2e3874c`"
|
||||||
|
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||||
|
assert ret == 'ALTER TABLE "category" DROP CONSTRAINT "fk_category_user_e2e3874c"'
|
||||||
else:
|
else:
|
||||||
assert ret == 'ALTER TABLE "category" DROP FOREIGN KEY "fk_category_user_e2e3874c"'
|
assert ret == 'ALTER TABLE "category" DROP FOREIGN KEY "fk_category_user_e2e3874c"'
|
||||||
|
@@ -1,30 +1,79 @@
|
|||||||
|
import pytest
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
from tortoise import Tortoise
|
from tortoise import Tortoise
|
||||||
|
|
||||||
from aerich.ddl.mysql import MysqlDDL
|
from aerich.ddl.mysql import MysqlDDL
|
||||||
|
from aerich.ddl.postgres import PostgresDDL
|
||||||
|
from aerich.ddl.sqlite import SqliteDDL
|
||||||
|
from aerich.exceptions import NotSupportError
|
||||||
from aerich.migrate import Migrate
|
from aerich.migrate import Migrate
|
||||||
|
|
||||||
|
|
||||||
def test_migrate():
|
def test_migrate(mocker: MockerFixture):
|
||||||
|
mocker.patch("click.prompt", return_value=True)
|
||||||
apps = Tortoise.apps
|
apps = Tortoise.apps
|
||||||
models = apps.get("models")
|
models = apps.get("models")
|
||||||
diff_models = apps.get("diff_models")
|
diff_models = apps.get("diff_models")
|
||||||
Migrate.diff_models(diff_models, models)
|
Migrate.diff_models(diff_models, models)
|
||||||
Migrate.diff_models(models, diff_models, False)
|
if isinstance(Migrate.ddl, SqliteDDL):
|
||||||
|
with pytest.raises(NotSupportError):
|
||||||
|
Migrate.diff_models(models, diff_models, False)
|
||||||
|
else:
|
||||||
|
Migrate.diff_models(models, diff_models, False)
|
||||||
|
Migrate._merge_operators()
|
||||||
if isinstance(Migrate.ddl, MysqlDDL):
|
if isinstance(Migrate.ddl, MysqlDDL):
|
||||||
assert Migrate.upgrade_operators == [
|
assert Migrate.upgrade_operators == [
|
||||||
|
"ALTER TABLE `email` DROP FOREIGN KEY `fk_email_user_5b58673d`",
|
||||||
"ALTER TABLE `category` ADD `name` VARCHAR(200) NOT NULL",
|
"ALTER TABLE `category` ADD `name` VARCHAR(200) NOT NULL",
|
||||||
"ALTER TABLE `user` ADD UNIQUE INDEX `uid_user_usernam_9987ab` (`username`)",
|
"ALTER TABLE `user` ADD UNIQUE INDEX `uid_user_usernam_9987ab` (`username`)",
|
||||||
|
"ALTER TABLE `user` RENAME COLUMN `last_login_at` TO `last_login`",
|
||||||
]
|
]
|
||||||
assert Migrate.downgrade_operators == [
|
assert Migrate.downgrade_operators == [
|
||||||
"ALTER TABLE `category` DROP COLUMN `name`",
|
"ALTER TABLE `category` DROP COLUMN `name`",
|
||||||
"ALTER TABLE `user` DROP INDEX `uid_user_usernam_9987ab`",
|
"ALTER TABLE `user` DROP INDEX `uid_user_usernam_9987ab`",
|
||||||
|
"ALTER TABLE `user` RENAME COLUMN `last_login` TO `last_login_at`",
|
||||||
|
"ALTER TABLE `email` ADD CONSTRAINT `fk_email_user_5b58673d` FOREIGN KEY "
|
||||||
|
"(`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE",
|
||||||
]
|
]
|
||||||
else:
|
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||||
assert Migrate.upgrade_operators == [
|
assert Migrate.upgrade_operators == [
|
||||||
|
'ALTER TABLE "email" DROP CONSTRAINT "fk_email_user_5b58673d"',
|
||||||
'ALTER TABLE "category" ADD "name" VARCHAR(200) NOT NULL',
|
'ALTER TABLE "category" ADD "name" VARCHAR(200) NOT NULL',
|
||||||
'ALTER TABLE "user" ADD UNIQUE INDEX "uid_user_usernam_9987ab" ("username")',
|
'ALTER TABLE "user" ADD CONSTRAINT "uid_user_usernam_9987ab" UNIQUE ("username")',
|
||||||
|
'ALTER TABLE "user" RENAME COLUMN "last_login_at" TO "last_login"',
|
||||||
]
|
]
|
||||||
assert Migrate.downgrade_operators == [
|
assert Migrate.downgrade_operators == [
|
||||||
'ALTER TABLE "category" DROP COLUMN "name"',
|
'ALTER TABLE "category" DROP COLUMN "name"',
|
||||||
'ALTER TABLE "user" DROP INDEX "uid_user_usernam_9987ab"',
|
'ALTER TABLE "user" DROP CONSTRAINT "uid_user_usernam_9987ab"',
|
||||||
|
'ALTER TABLE "user" RENAME COLUMN "last_login" TO "last_login_at"',
|
||||||
|
'ALTER TABLE "email" ADD CONSTRAINT "fk_email_user_5b58673d" FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE',
|
||||||
]
|
]
|
||||||
|
elif isinstance(Migrate.ddl, SqliteDDL):
|
||||||
|
assert Migrate.upgrade_operators == [
|
||||||
|
'ALTER TABLE "email" DROP FOREIGN KEY "fk_email_user_5b58673d"',
|
||||||
|
'ALTER TABLE "category" ADD "name" VARCHAR(200) NOT NULL',
|
||||||
|
'ALTER TABLE "user" ADD UNIQUE INDEX "uid_user_usernam_9987ab" ("username")',
|
||||||
|
'ALTER TABLE "user" RENAME COLUMN "last_login_at" TO "last_login"',
|
||||||
|
]
|
||||||
|
assert Migrate.downgrade_operators == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_sort_all_version_files(mocker):
|
||||||
|
mocker.patch(
|
||||||
|
"os.listdir",
|
||||||
|
return_value=[
|
||||||
|
"1_datetime_update.json",
|
||||||
|
"11_datetime_update.json",
|
||||||
|
"10_datetime_update.json",
|
||||||
|
"2_datetime_update.json",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
Migrate.migrate_location = "."
|
||||||
|
|
||||||
|
assert Migrate.get_all_version_files() == [
|
||||||
|
"1_datetime_update.json",
|
||||||
|
"2_datetime_update.json",
|
||||||
|
"10_datetime_update.json",
|
||||||
|
"11_datetime_update.json",
|
||||||
|
]
|
||||||
|
Reference in New Issue
Block a user