├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── MANIFEST.in ├── README.md ├── fastapi_migrations ├── __init__.py ├── cli.py ├── lib.py └── templates │ └── default │ ├── README │ ├── alembic.ini.mako │ ├── env.py │ └── script.py.mako ├── poetry.lock ├── pyproject.toml ├── setup.py └── tests ├── __init__.py ├── fixtures.py ├── models.py ├── test_config.py ├── test_imports.py └── test_programatic_commands.py /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python ### 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # Tests 8 | .pytest_cache/ 9 | .coverage 10 | htmlcov/ 11 | migrations/ 12 | migrations_test/ 13 | .mypy_cache/ 14 | 15 | # Distribution / packaging 16 | .Python 17 | build/ 18 | dist/ 19 | .eggs/ 20 | *.egg-info/ 21 | *.dist-info/ 22 | 23 | # virtual environmnents 24 | .venv/ -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: Module", 9 | "type": "python", 10 | "request": "launch", 11 | "module": "pytest", 12 | "args": ["--ignore=venv/*", "-v", "-s", "tests/*"] 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.venvPath": "${workspaceFolder}/.venv/", 3 | "python.pythonPath": ".venv\\Scripts\\python.exe", 4 | "[python]": { 5 | "editor.rulers": [79, 120] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "options": { 4 | "cwd": "${workspaceFolder}" 5 | }, 6 | "tasks": [ 7 | { 8 | "group": "test", 9 | "label": "Run tests", 10 | "type": "shell", 11 | "command": ".venv/Scripts/pytest", 12 | "args": ["--ignore=.venv/*", "-v", "-s", "tests/*"], 13 | "presentation": { 14 | "reveal": "always" 15 | } 16 | }, 17 | { 18 | "group": "test", 19 | "label": "Run coverage", 20 | "type": "shell", 21 | "command": ".venv/Scripts/coverage", 22 | "args": [ 23 | "run", 24 | "--omit=.venv/*", 25 | "-m", 26 | "pytest", 27 | "--ignore=.venv/*", 28 | "-v", 29 | "tests/" 30 | ], 31 | "presentation": { 32 | "reveal": "always" 33 | } 34 | }, 35 | { 36 | "group": "test", 37 | "label": "Run coverage with html", 38 | "type": "shell", 39 | "command": ".venv/Scripts/coverage", 40 | "args": ["html", "-i"], 41 | "presentation": { 42 | "reveal": "always" 43 | }, 44 | "dependsOn": ["Run coverage"] 45 | }, 46 | { 47 | "group": "test", 48 | "label": "Run flake8", 49 | "type": "shell", 50 | "command": ".venv/Scripts/flake8", 51 | "args": ["--exclude", ".venv,.eggs"], 52 | "presentation": { 53 | "reveal": "always" 54 | } 55 | }, 56 | { 57 | "group": "test", 58 | "label": "Run mypy", 59 | "type": "shell", 60 | "command": ".venv/Scripts/mypy", 61 | "args": ["--strict", "."], 62 | "presentation": { 63 | "reveal": "always" 64 | } 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ariel Carvajal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include __version__ README.md LICENSE \ 2 | fastapi_migrations/templates/default/* \ 3 | fastapi_migrations/templates/multidb/* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fastapi Migrations 2 | 3 | ![PyPI](https://img.shields.io/pypi/v/fastapi-migrations) 4 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/fastapi-migrations) 5 | ![PyPI - License](https://img.shields.io/pypi/l/fastapi-migrations) 6 | 7 | ![GitHub last commit](https://img.shields.io/github/last-commit/uselessscat/fastapi-migrations) 8 | ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/uselessscat/fastapi-migrations) 9 | ![GitHub issues](https://img.shields.io/github/issues/uselessscat/fastapi-migrations) 10 | ![GitHub pull requests](https://img.shields.io/github/issues-pr/uselessscat/fastapi-migrations) 11 | 12 | This library provides a small wrapper for alembic. 13 | 14 | ### Notice 15 | 16 | **Under inital development. This can not be ready-for-production library.** 17 | 18 | This can means: 19 | 20 | - Breaking changes may be introduced 21 | - Poor documentation and changeslogs 22 | - Not totally tested 23 | - Be forced to navigate through the source code to find out how it works 24 | 25 | Wait to a version > 0.1.0 for usage in production environments. 26 | 27 | ## Installation 28 | 29 | You can install this library with: 30 | 31 | pip3 install fastapi-migrations 32 | 33 | ## Usage 34 | 35 | You can use both programatically and by CLI (command line interface). 36 | 37 | Imagine your project folders 38 | 39 | app/ 40 | cli/ 41 | __init__.py 42 | action.py 43 | db/ 44 | __init__.py 45 | base.py 46 | models/ 47 | __init__.py 48 | my_model.py 49 | endpoints/ 50 | __init__.py 51 | my_endpoint.py 52 | __init__.py 53 | config.py 54 | main.py 55 | 56 | This is an example of `main.py`: 57 | 58 | from fastapi import FastAPI 59 | from fastapi_sqlalchemy import DBSessionMiddleware 60 | 61 | # Load configs and endpoints 62 | from app.config import settings 63 | from app.endpoints import router 64 | 65 | app: FastAPI = FastAPI(title=settings.project_name) 66 | 67 | # register routes 68 | app.include_router(router) 69 | 70 | # add middlewares 71 | app.add_middleware(DBSessionMiddleware, db_url=settings.database_uri) 72 | 73 | if __name__ == '__main__': 74 | # Load cli commands 75 | from app.cli import app as cli 76 | 77 | cli() 78 | 79 | Then your `app/cli/__init__.py` can be like: 80 | 81 | import typer 82 | 83 | from fastapi_migrations.cli import MigrationsCli 84 | import app.cli.action as action 85 | 86 | # main cli app 87 | app: typer.Typer = typer.Typer() 88 | 89 | # these are our cli actions 90 | app.add_typer(action.app, name='action', help='Common actions the app do') 91 | 92 | # this line adds the fastapi-migrations cli commands to our app 93 | app.add_typer(MigrationsCli()) 94 | 95 | Now you can call your app from the command line and use `fastapi-migrations` like: 96 | 97 | py app/main.py db show 98 | 99 | If you want to use this library programatically, this is an example: 100 | 101 | The file `app/cli/action.py` can be like: 102 | 103 | import typer 104 | from fastapi_migrations import MigrationsConfig, Migrations 105 | 106 | app: typer.Typer = typer.Typer() 107 | 108 | @app.command() 109 | def show() -> None: 110 | config = MigrationsConfig() 111 | 112 | migrations = Migrations(config) 113 | 114 | migrations.show() 115 | 116 | You can add this lines where you wish in your proyect. Here we ar adding it to a command line so we can call our app like: 117 | 118 | py app/main.py action show 119 | 120 | # License 121 | 122 | This software is distributed under [MIT license](LICENSE). 123 | -------------------------------------------------------------------------------- /fastapi_migrations/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from lib import Migrations, MigrationsConfig 4 | from cli import MigrationsCli 5 | 6 | __version__: str = '0.0.4' 7 | __all__: List[str] = [ 8 | 'Migrations', 9 | 'MigrationsConfig', 10 | 'MigrationsCli' 11 | ] 12 | -------------------------------------------------------------------------------- /fastapi_migrations/cli.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Any 2 | 3 | from typer import Typer 4 | from fastapi_migrations import Migrations, MigrationsConfig 5 | 6 | 7 | class MigrationsCli(Typer): 8 | def __init__( 9 | self, 10 | config: Optional[MigrationsConfig] = None, 11 | *, 12 | name: Optional[str] = 'db', 13 | help: Optional[str] = 'Database tools', 14 | **kwargs: Any 15 | ): 16 | super().__init__(name=name, help=help, **kwargs) 17 | 18 | self.migrations = Migrations(config or MigrationsConfig()) 19 | self.__register_commands() 20 | 21 | def __register_commands(self) -> None: 22 | self.command('init')(self.migrations.init) 23 | self.command('revision')(self.migrations.revision) 24 | self.command('autogenerate')(self.migrations.autogenerate) 25 | self.command('upgrade')(self.migrations.upgrade) 26 | self.command('downgrade')(self.migrations.downgrade) 27 | self.command('edit')(self.migrations.edit) 28 | self.command('merge')(self.migrations.merge) 29 | self.command('show')(self.migrations.show) 30 | self.command('history')(self.migrations.history) 31 | self.command('heads')(self.migrations.heads) 32 | self.command('branches')(self.migrations.branches) 33 | self.command('current')(self.migrations.current) 34 | self.command('stamp')(self.migrations.stamp) 35 | -------------------------------------------------------------------------------- /fastapi_migrations/lib.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Any, Tuple 2 | 3 | import logging 4 | 5 | from functools import wraps 6 | from os.path import join, abspath, dirname 7 | 8 | from pydantic import BaseSettings, Extra 9 | 10 | from alembic import command 11 | from alembic import __version__ as __alembic_version__ 12 | from alembic.util import CommandError 13 | from alembic.config import Config as AlembicConfig 14 | 15 | alembic_version: Tuple[int, ...] = tuple( 16 | [ 17 | int(v) 18 | for v in __alembic_version__.split('.')[0:3] 19 | ] 20 | ) 21 | 22 | 23 | # TODO: FIX 24 | def catch_errors(f): # type: ignore 25 | @wraps(f) 26 | def wrapped(*args, **kwargs): 27 | try: 28 | f(*args, **kwargs) 29 | except (CommandError, RuntimeError) as exc: 30 | logging.error('Error: ' + str(exc)) 31 | 32 | return wrapped 33 | 34 | 35 | class MigrationsConfig(BaseSettings): 36 | sqlalchemy_url: Optional[str] 37 | 38 | script_location: str = 'migrations' 39 | config_file_name: str = 'alembic.ini' 40 | 41 | default_template_dir: str = 'default' 42 | multidb_template_dir: str = 'multidb' 43 | template_directory: str = join( 44 | abspath(dirname(__file__)), 'templates' 45 | ) 46 | 47 | file_template: str = '%%(rev)s' 48 | truncate_slug_length: str = '40' 49 | 50 | @classmethod 51 | def from_alembic_config(cls) -> 'MigrationsConfig': 52 | # TODO: implement 53 | return cls() 54 | 55 | def to_alembic_config(self) -> AlembicConfig: 56 | def get_template_directory() -> str: 57 | return self.template_directory 58 | 59 | alembic = AlembicConfig( 60 | join(self.script_location, self.config_file_name) 61 | ) 62 | 63 | # set the template directory getter 64 | alembic.get_template_directory = get_template_directory 65 | 66 | # default alembic confs 67 | if self.sqlalchemy_url: 68 | alembic.set_main_option('sqlalchemy.url', self.sqlalchemy_url) 69 | 70 | alembic.set_main_option('script_location', self.script_location) 71 | alembic.set_main_option('file_template', self.file_template) 72 | alembic.set_main_option( 73 | 'truncate_slug_length', 74 | self.truncate_slug_length 75 | ) 76 | 77 | return alembic 78 | 79 | class Config: 80 | extra = Extra.allow 81 | 82 | 83 | class Migrations(): 84 | def __init__( 85 | self, 86 | config: Optional[MigrationsConfig] = None 87 | ): 88 | self.configuration = config or MigrationsConfig() 89 | 90 | def init( 91 | self, 92 | multidb: bool = False 93 | ) -> Any: 94 | config: AlembicConfig = self.configuration.to_alembic_config() 95 | 96 | return command.init( 97 | config, 98 | directory=self.configuration.script_location, 99 | template='multidb' if multidb else 'default', 100 | package=False 101 | ) 102 | 103 | def revision( 104 | self, 105 | message: Optional[str] = None, 106 | autogenerate: bool = False, 107 | sql: bool = False, 108 | head: str = 'head', 109 | splice: bool = False, 110 | branch_label: Optional[str] = None, 111 | version_path: Optional[str] = None, 112 | rev_id: Optional[str] = None 113 | ) -> Any: 114 | config = self.configuration.to_alembic_config() 115 | 116 | return command.revision( 117 | config, 118 | message, 119 | autogenerate=autogenerate, 120 | sql=sql, 121 | head=head, 122 | splice=splice, 123 | branch_label=branch_label, 124 | version_path=version_path, 125 | rev_id=rev_id 126 | ) 127 | 128 | def autogenerate( 129 | self, 130 | message: Optional[str] = None, 131 | sql: bool = False, 132 | head: str = 'head', 133 | splice: bool = False, 134 | branch_label: Optional[str] = None, 135 | version_path: Optional[str] = None, 136 | rev_id: Optional[str] = None 137 | ) -> Any: 138 | config = self.configuration.to_alembic_config() 139 | 140 | return command.revision( 141 | config, 142 | message, 143 | autogenerate=True, 144 | sql=sql, 145 | head=head, 146 | splice=splice, 147 | branch_label=branch_label, 148 | version_path=version_path, 149 | rev_id=rev_id 150 | ) 151 | 152 | def upgrade( 153 | self, 154 | revision: str = 'head', 155 | sql: bool = False, 156 | tag: Optional[str] = None 157 | ) -> Any: 158 | config = self.configuration.to_alembic_config() 159 | 160 | return command.upgrade( 161 | config, 162 | revision, 163 | sql=sql, 164 | tag=tag 165 | ) 166 | 167 | def downgrade( 168 | self, 169 | revision: str = '-1', 170 | sql: bool = False, 171 | tag: Optional[str] = None 172 | ) -> Any: 173 | config = self.configuration.to_alembic_config() 174 | 175 | if sql and revision == '-1': 176 | revision = 'head:-1' 177 | 178 | return command.downgrade( 179 | config, 180 | revision, 181 | sql=sql, 182 | tag=tag 183 | ) 184 | 185 | def edit( 186 | self, 187 | revision: str = 'current' 188 | ) -> Any: 189 | if alembic_version >= (0, 8, 0): 190 | config = self.configuration.to_alembic_config() 191 | 192 | return command.edit(config, revision) 193 | else: 194 | raise RuntimeError('Alembic 0.8.0 or greater is required') 195 | 196 | def merge( 197 | self, 198 | revisions: str = '', 199 | message: Optional[str] = None, 200 | branch_label: Optional[str] = None, 201 | rev_id: Optional[str] = None 202 | ) -> Any: 203 | config = self.configuration.to_alembic_config() 204 | 205 | return command.merge( 206 | config, 207 | revisions, 208 | message=message, 209 | branch_label=branch_label, 210 | rev_id=rev_id 211 | ) 212 | 213 | def show( 214 | self, 215 | revision: str = 'head' 216 | ) -> Any: 217 | config = self.configuration.to_alembic_config() 218 | 219 | return command.show(config, revision) 220 | 221 | def history( 222 | self, 223 | rev_range: Optional[str] = None, 224 | verbose: bool = False, 225 | indicate_current: bool = False 226 | ) -> Any: 227 | config = self.configuration.to_alembic_config() 228 | 229 | if alembic_version >= (0, 9, 9): 230 | return command.history( 231 | config, 232 | rev_range, 233 | verbose=verbose, 234 | indicate_current=indicate_current 235 | ) 236 | else: 237 | return command.history( 238 | config, 239 | rev_range, 240 | verbose=verbose 241 | ) 242 | 243 | def heads( 244 | self, 245 | verbose: bool = False, 246 | resolve_dependencies: bool = False 247 | ) -> Any: 248 | config = self.configuration.to_alembic_config() 249 | 250 | return command.heads( 251 | config, 252 | verbose=verbose, 253 | resolve_dependencies=resolve_dependencies 254 | ) 255 | 256 | def branches( 257 | self, 258 | verbose: bool = False 259 | ) -> Any: 260 | config = self.configuration.to_alembic_config() 261 | 262 | return command.branches(config, verbose=verbose) 263 | 264 | def current( 265 | self, 266 | verbose: bool = False, 267 | head_only: bool = False 268 | ) -> Any: 269 | config = self.configuration.to_alembic_config() 270 | 271 | return command.current( 272 | config, 273 | verbose=verbose, 274 | head_only=head_only 275 | ) 276 | 277 | def stamp( 278 | self, 279 | revision: str = 'head', 280 | sql: bool = False, 281 | tag: Optional[str] = None 282 | ) -> Any: 283 | config = self.configuration.to_alembic_config() 284 | 285 | return command.stamp( 286 | config, 287 | revision, 288 | sql=sql, 289 | tag=tag 290 | ) 291 | -------------------------------------------------------------------------------- /fastapi_migrations/templates/default/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /fastapi_migrations/templates/default/alembic.ini.mako: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | [alembic] 3 | 4 | # Logging configuration 5 | [loggers] 6 | keys = root,sqlalchemy,alembic 7 | 8 | [handlers] 9 | keys = console 10 | 11 | [formatters] 12 | keys = generic 13 | 14 | [logger_root] 15 | level = WARN 16 | handlers = console 17 | qualname = 18 | 19 | [logger_sqlalchemy] 20 | level = WARN 21 | handlers = 22 | qualname = sqlalchemy.engine 23 | 24 | [logger_alembic] 25 | level = INFO 26 | handlers = 27 | qualname = alembic 28 | 29 | [handler_console] 30 | class = StreamHandler 31 | args = (sys.stderr,) 32 | level = NOTSET 33 | formatter = generic 34 | 35 | [formatter_generic] 36 | format = %(levelname)-5.5s [%(name)s] %(message)s 37 | datefmt = %H:%M:%S -------------------------------------------------------------------------------- /fastapi_migrations/templates/default/env.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | from sqlalchemy import pool 4 | from sqlalchemy import engine_from_config 5 | 6 | from alembic import context 7 | 8 | from logging.config import fileConfig 9 | import logging 10 | 11 | # this is the Alembic Config object, which provides 12 | # access to the values within the .ini file in use. 13 | # pylint: disable=no-member 14 | config = context.config 15 | 16 | # other values from the config, defined by the needs of env.py, 17 | # can be acquired: 18 | # my_important_option = config.get_main_option("my_important_option") 19 | # ... etc. 20 | 21 | # Interpret the config file for Python logging. 22 | # This line sets up loggers basically. 23 | fileConfig(config.config_file_name) 24 | logger = logging.getLogger('alembic.env') 25 | 26 | try: 27 | from fastapi_sqlalchemy import db 28 | 29 | with db(): 30 | config.set_main_option( 31 | 'sqlalchemy.url', 32 | str(db.session.get_bind().engine.url) 33 | ) 34 | except Exception: 35 | # TODO: Add url to MigrationsConfig 36 | config.set_main_option( 37 | 'sqlalchemy.url', 38 | 'sqlite:///?check_same_thread=false' 39 | ) 40 | 41 | 42 | def get_metadata(): 43 | # add your model's MetaData object here 44 | # for 'autogenerate' support 45 | # from myapp import mymodel 46 | # target_metadata = mymodel.Base.metadata 47 | try: 48 | from app.db.base import Base 49 | 50 | return Base.metadata 51 | except Exception: 52 | # TODO: pass metadata though config 53 | return None 54 | 55 | 56 | target_metadata = get_metadata() 57 | 58 | 59 | def run_migrations_offline(): 60 | """Run migrations in 'offline' mode. 61 | This configures the context with just a URL 62 | and not an Engine, though an Engine is acceptable 63 | here as well. By skipping the Engine creation 64 | we don't even need a DBAPI to be available. 65 | Calls to context.execute() here emit the given string to the 66 | script output. 67 | """ 68 | url = config.get_main_option("sqlalchemy.url") 69 | context.configure( 70 | url=url, target_metadata=target_metadata, literal_binds=True 71 | ) 72 | 73 | with context.begin_transaction(): 74 | context.run_migrations() 75 | 76 | 77 | def run_migrations_online(): 78 | """Run migrations in 'online' mode. 79 | In this scenario we need to create an Engine 80 | and associate a connection with the context. 81 | """ 82 | 83 | # this callback is used to prevent an auto-migration from being generated 84 | # when there are no changes to the schema 85 | # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html 86 | def process_revision_directives(context, revision, directives): 87 | if getattr(config.cmd_opts, 'autogenerate', False): 88 | script = directives[0] 89 | if script.upgrade_ops.is_empty(): 90 | directives[:] = [] 91 | logger.info('No changes in schema detected.') 92 | 93 | connectable = engine_from_config( 94 | config.get_section(config.config_ini_section), 95 | prefix='sqlalchemy.', 96 | poolclass=pool.NullPool, 97 | ) 98 | 99 | with connectable.connect() as connection: 100 | context.configure( 101 | connection=connection, 102 | target_metadata=target_metadata, 103 | process_revision_directives=process_revision_directives, 104 | # **configure_args 105 | ) 106 | 107 | with context.begin_transaction(): 108 | context.run_migrations() 109 | 110 | 111 | if context.is_offline_mode(): 112 | run_migrations_offline() 113 | else: 114 | run_migrations_online() 115 | -------------------------------------------------------------------------------- /fastapi_migrations/templates/default/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "alembic" 3 | version = "1.5.5" 4 | description = "A database migration tool for SQLAlchemy." 5 | category = "main" 6 | optional = false 7 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" 8 | 9 | [package.dependencies] 10 | Mako = "*" 11 | python-dateutil = "*" 12 | python-editor = ">=0.3" 13 | SQLAlchemy = ">=1.3.0" 14 | 15 | [[package]] 16 | name = "astroid" 17 | version = "2.5" 18 | description = "An abstract syntax tree for Python with inference support." 19 | category = "dev" 20 | optional = false 21 | python-versions = ">=3.6" 22 | 23 | [package.dependencies] 24 | lazy-object-proxy = ">=1.4.0" 25 | typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} 26 | wrapt = ">=1.11,<1.13" 27 | 28 | [[package]] 29 | name = "atomicwrites" 30 | version = "1.4.0" 31 | description = "Atomic file writes." 32 | category = "dev" 33 | optional = false 34 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 35 | 36 | [[package]] 37 | name = "attrs" 38 | version = "20.3.0" 39 | description = "Classes Without Boilerplate" 40 | category = "dev" 41 | optional = false 42 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 43 | 44 | [package.extras] 45 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] 46 | docs = ["furo", "sphinx", "zope.interface"] 47 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 48 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] 49 | 50 | [[package]] 51 | name = "autopep8" 52 | version = "1.5.5" 53 | description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" 54 | category = "dev" 55 | optional = false 56 | python-versions = "*" 57 | 58 | [package.dependencies] 59 | pycodestyle = ">=2.6.0" 60 | toml = "*" 61 | 62 | [[package]] 63 | name = "click" 64 | version = "7.1.2" 65 | description = "Composable command line interface toolkit" 66 | category = "main" 67 | optional = false 68 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 69 | 70 | [[package]] 71 | name = "colorama" 72 | version = "0.4.4" 73 | description = "Cross-platform colored terminal text." 74 | category = "dev" 75 | optional = false 76 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 77 | 78 | [[package]] 79 | name = "flake8" 80 | version = "3.8.4" 81 | description = "the modular source code checker: pep8 pyflakes and co" 82 | category = "dev" 83 | optional = false 84 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" 85 | 86 | [package.dependencies] 87 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 88 | mccabe = ">=0.6.0,<0.7.0" 89 | pycodestyle = ">=2.6.0a1,<2.7.0" 90 | pyflakes = ">=2.2.0,<2.3.0" 91 | 92 | [[package]] 93 | name = "importlib-metadata" 94 | version = "3.7.0" 95 | description = "Read metadata from Python packages" 96 | category = "dev" 97 | optional = false 98 | python-versions = ">=3.6" 99 | 100 | [package.dependencies] 101 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 102 | zipp = ">=0.5" 103 | 104 | [package.extras] 105 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 106 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] 107 | 108 | [[package]] 109 | name = "iniconfig" 110 | version = "1.1.1" 111 | description = "iniconfig: brain-dead simple config-ini parsing" 112 | category = "dev" 113 | optional = false 114 | python-versions = "*" 115 | 116 | [[package]] 117 | name = "isort" 118 | version = "5.7.0" 119 | description = "A Python utility / library to sort Python imports." 120 | category = "dev" 121 | optional = false 122 | python-versions = ">=3.6,<4.0" 123 | 124 | [package.extras] 125 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 126 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 127 | colors = ["colorama (>=0.4.3,<0.5.0)"] 128 | 129 | [[package]] 130 | name = "lazy-object-proxy" 131 | version = "1.5.2" 132 | description = "A fast and thorough lazy object proxy." 133 | category = "dev" 134 | optional = false 135 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 136 | 137 | [[package]] 138 | name = "mako" 139 | version = "1.1.4" 140 | description = "A super-fast templating language that borrows the best ideas from the existing templating languages." 141 | category = "main" 142 | optional = false 143 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 144 | 145 | [package.dependencies] 146 | MarkupSafe = ">=0.9.2" 147 | 148 | [package.extras] 149 | babel = ["babel"] 150 | lingua = ["lingua"] 151 | 152 | [[package]] 153 | name = "markupsafe" 154 | version = "1.1.1" 155 | description = "Safely add untrusted strings to HTML/XML markup." 156 | category = "main" 157 | optional = false 158 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 159 | 160 | [[package]] 161 | name = "mccabe" 162 | version = "0.6.1" 163 | description = "McCabe checker, plugin for flake8" 164 | category = "dev" 165 | optional = false 166 | python-versions = "*" 167 | 168 | [[package]] 169 | name = "mypy" 170 | version = "0.812" 171 | description = "Optional static typing for Python" 172 | category = "dev" 173 | optional = false 174 | python-versions = ">=3.5" 175 | 176 | [package.dependencies] 177 | mypy-extensions = ">=0.4.3,<0.5.0" 178 | typed-ast = ">=1.4.0,<1.5.0" 179 | typing-extensions = ">=3.7.4" 180 | 181 | [package.extras] 182 | dmypy = ["psutil (>=4.0)"] 183 | 184 | [[package]] 185 | name = "mypy-extensions" 186 | version = "0.4.3" 187 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 188 | category = "dev" 189 | optional = false 190 | python-versions = "*" 191 | 192 | [[package]] 193 | name = "packaging" 194 | version = "20.9" 195 | description = "Core utilities for Python packages" 196 | category = "dev" 197 | optional = false 198 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 199 | 200 | [package.dependencies] 201 | pyparsing = ">=2.0.2" 202 | 203 | [[package]] 204 | name = "pluggy" 205 | version = "0.13.1" 206 | description = "plugin and hook calling mechanisms for python" 207 | category = "dev" 208 | optional = false 209 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 210 | 211 | [package.dependencies] 212 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 213 | 214 | [package.extras] 215 | dev = ["pre-commit", "tox"] 216 | 217 | [[package]] 218 | name = "py" 219 | version = "1.10.0" 220 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 221 | category = "dev" 222 | optional = false 223 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 224 | 225 | [[package]] 226 | name = "pycodestyle" 227 | version = "2.6.0" 228 | description = "Python style guide checker" 229 | category = "dev" 230 | optional = false 231 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 232 | 233 | [[package]] 234 | name = "pydantic" 235 | version = "1.7.3" 236 | description = "Data validation and settings management using python 3.6 type hinting" 237 | category = "main" 238 | optional = false 239 | python-versions = ">=3.6" 240 | 241 | [package.extras] 242 | dotenv = ["python-dotenv (>=0.10.4)"] 243 | email = ["email-validator (>=1.0.3)"] 244 | typing_extensions = ["typing-extensions (>=3.7.2)"] 245 | 246 | [[package]] 247 | name = "pyflakes" 248 | version = "2.2.0" 249 | description = "passive checker of Python programs" 250 | category = "dev" 251 | optional = false 252 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 253 | 254 | [[package]] 255 | name = "pylint" 256 | version = "2.7.1" 257 | description = "python code static checker" 258 | category = "dev" 259 | optional = false 260 | python-versions = "~=3.6" 261 | 262 | [package.dependencies] 263 | astroid = "2.5.0" 264 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 265 | isort = ">=4.2.5,<6" 266 | mccabe = ">=0.6,<0.7" 267 | toml = ">=0.7.1" 268 | 269 | [package.extras] 270 | docs = ["sphinx (>=3.2,<4.0)", "python-docs-theme"] 271 | 272 | [[package]] 273 | name = "pyparsing" 274 | version = "2.4.7" 275 | description = "Python parsing module" 276 | category = "dev" 277 | optional = false 278 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 279 | 280 | [[package]] 281 | name = "pytest" 282 | version = "6.2.2" 283 | description = "pytest: simple powerful testing with Python" 284 | category = "dev" 285 | optional = false 286 | python-versions = ">=3.6" 287 | 288 | [package.dependencies] 289 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 290 | attrs = ">=19.2.0" 291 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 292 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 293 | iniconfig = "*" 294 | packaging = "*" 295 | pluggy = ">=0.12,<1.0.0a1" 296 | py = ">=1.8.2" 297 | toml = "*" 298 | 299 | [package.extras] 300 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 301 | 302 | [[package]] 303 | name = "python-dateutil" 304 | version = "2.8.1" 305 | description = "Extensions to the standard Python datetime module" 306 | category = "main" 307 | optional = false 308 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 309 | 310 | [package.dependencies] 311 | six = ">=1.5" 312 | 313 | [[package]] 314 | name = "python-editor" 315 | version = "1.0.4" 316 | description = "Programmatically open an editor, capture the result." 317 | category = "main" 318 | optional = false 319 | python-versions = "*" 320 | 321 | [[package]] 322 | name = "six" 323 | version = "1.15.0" 324 | description = "Python 2 and 3 compatibility utilities" 325 | category = "main" 326 | optional = false 327 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 328 | 329 | [[package]] 330 | name = "sqlalchemy" 331 | version = "1.3.23" 332 | description = "Database Abstraction Library" 333 | category = "main" 334 | optional = false 335 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 336 | 337 | [package.extras] 338 | mssql = ["pyodbc"] 339 | mssql_pymssql = ["pymssql"] 340 | mssql_pyodbc = ["pyodbc"] 341 | mysql = ["mysqlclient"] 342 | oracle = ["cx-oracle"] 343 | postgresql = ["psycopg2"] 344 | postgresql_pg8000 = ["pg8000 (<1.16.6)"] 345 | postgresql_psycopg2binary = ["psycopg2-binary"] 346 | postgresql_psycopg2cffi = ["psycopg2cffi"] 347 | pymysql = ["pymysql (<1)", "pymysql"] 348 | 349 | [[package]] 350 | name = "toml" 351 | version = "0.10.2" 352 | description = "Python Library for Tom's Obvious, Minimal Language" 353 | category = "dev" 354 | optional = false 355 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 356 | 357 | [[package]] 358 | name = "typed-ast" 359 | version = "1.4.2" 360 | description = "a fork of Python 2 and 3 ast modules with type comment support" 361 | category = "dev" 362 | optional = false 363 | python-versions = "*" 364 | 365 | [[package]] 366 | name = "typer" 367 | version = "0.3.2" 368 | description = "Typer, build great CLIs. Easy to code. Based on Python type hints." 369 | category = "main" 370 | optional = false 371 | python-versions = ">=3.6" 372 | 373 | [package.dependencies] 374 | click = ">=7.1.1,<7.2.0" 375 | 376 | [package.extras] 377 | test = ["pytest-xdist (>=1.32.0,<2.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "mypy (==0.782)", "black (>=19.10b0,<20.0b0)", "isort (>=5.0.6,<6.0.0)", "shellingham (>=1.3.0,<2.0.0)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "coverage (>=5.2,<6.0)"] 378 | all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"] 379 | dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)"] 380 | doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)", "markdown-include (>=0.5.1,<0.6.0)"] 381 | 382 | [[package]] 383 | name = "typing-extensions" 384 | version = "3.7.4.3" 385 | description = "Backported and Experimental Type Hints for Python 3.5+" 386 | category = "dev" 387 | optional = false 388 | python-versions = "*" 389 | 390 | [[package]] 391 | name = "wrapt" 392 | version = "1.12.1" 393 | description = "Module for decorators, wrappers and monkey patching." 394 | category = "dev" 395 | optional = false 396 | python-versions = "*" 397 | 398 | [[package]] 399 | name = "zipp" 400 | version = "3.4.0" 401 | description = "Backport of pathlib-compatible object wrapper for zip files" 402 | category = "dev" 403 | optional = false 404 | python-versions = ">=3.6" 405 | 406 | [package.extras] 407 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 408 | testing = ["pytest (>=3.5,!=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"] 409 | 410 | [metadata] 411 | lock-version = "1.1" 412 | python-versions = "^3.7" 413 | content-hash = "e95c843191bf9fd83e78db94dfdda50439899aa3d1ca86ce33e59e1d76865620" 414 | 415 | [metadata.files] 416 | alembic = [ 417 | {file = "alembic-1.5.5.tar.gz", hash = "sha256:df0028c19275a2cff137e39617a39cdcdbd1173733b87b6bfa257b7c0860213b"}, 418 | ] 419 | astroid = [ 420 | {file = "astroid-2.5-py3-none-any.whl", hash = "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc"}, 421 | {file = "astroid-2.5.tar.gz", hash = "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d"}, 422 | ] 423 | atomicwrites = [ 424 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 425 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 426 | ] 427 | attrs = [ 428 | {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, 429 | {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, 430 | ] 431 | autopep8 = [ 432 | {file = "autopep8-1.5.5-py2.py3-none-any.whl", hash = "sha256:9e136c472c475f4ee4978b51a88a494bfcd4e3ed17950a44a988d9e434837bea"}, 433 | {file = "autopep8-1.5.5.tar.gz", hash = "sha256:cae4bc0fb616408191af41d062d7ec7ef8679c7f27b068875ca3a9e2878d5443"}, 434 | ] 435 | click = [ 436 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 437 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 438 | ] 439 | colorama = [ 440 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 441 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 442 | ] 443 | flake8 = [ 444 | {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, 445 | {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, 446 | ] 447 | importlib-metadata = [ 448 | {file = "importlib_metadata-3.7.0-py3-none-any.whl", hash = "sha256:c6af5dbf1126cd959c4a8d8efd61d4d3c83bddb0459a17e554284a077574b614"}, 449 | {file = "importlib_metadata-3.7.0.tar.gz", hash = "sha256:24499ffde1b80be08284100393955842be4a59c7c16bbf2738aad0e464a8e0aa"}, 450 | ] 451 | iniconfig = [ 452 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 453 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 454 | ] 455 | isort = [ 456 | {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, 457 | {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"}, 458 | ] 459 | lazy-object-proxy = [ 460 | {file = "lazy-object-proxy-1.5.2.tar.gz", hash = "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4"}, 461 | {file = "lazy_object_proxy-1.5.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315"}, 462 | {file = "lazy_object_proxy-1.5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871"}, 463 | {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9"}, 464 | {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128"}, 465 | {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win32.whl", hash = "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847"}, 466 | {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108"}, 467 | {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068"}, 468 | {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7"}, 469 | {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win32.whl", hash = "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb"}, 470 | {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a"}, 471 | {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39"}, 472 | {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0"}, 473 | {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win32.whl", hash = "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef"}, 474 | {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302"}, 475 | {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163"}, 476 | {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f"}, 477 | {file = "lazy_object_proxy-1.5.2-cp38-cp38-win32.whl", hash = "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694"}, 478 | {file = "lazy_object_proxy-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa"}, 479 | {file = "lazy_object_proxy-1.5.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c"}, 480 | {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d"}, 481 | {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458"}, 482 | {file = "lazy_object_proxy-1.5.2-cp39-cp39-win32.whl", hash = "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166"}, 483 | {file = "lazy_object_proxy-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84"}, 484 | ] 485 | mako = [ 486 | {file = "Mako-1.1.4.tar.gz", hash = "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab"}, 487 | ] 488 | markupsafe = [ 489 | {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, 490 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, 491 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, 492 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, 493 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, 494 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, 495 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, 496 | {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, 497 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, 498 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, 499 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, 500 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, 501 | {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, 502 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, 503 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, 504 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, 505 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, 506 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, 507 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, 508 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, 509 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, 510 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, 511 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, 512 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, 513 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, 514 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, 515 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, 516 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, 517 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, 518 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, 519 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, 520 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, 521 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, 522 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, 523 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, 524 | {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, 525 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, 526 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, 527 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, 528 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, 529 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, 530 | {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, 531 | {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, 532 | {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, 533 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, 534 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, 535 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, 536 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, 537 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, 538 | {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, 539 | {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, 540 | {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, 541 | ] 542 | mccabe = [ 543 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 544 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 545 | ] 546 | mypy = [ 547 | {file = "mypy-0.812-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49"}, 548 | {file = "mypy-0.812-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c"}, 549 | {file = "mypy-0.812-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521"}, 550 | {file = "mypy-0.812-cp35-cp35m-win_amd64.whl", hash = "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"}, 551 | {file = "mypy-0.812-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a"}, 552 | {file = "mypy-0.812-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c"}, 553 | {file = "mypy-0.812-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6"}, 554 | {file = "mypy-0.812-cp36-cp36m-win_amd64.whl", hash = "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064"}, 555 | {file = "mypy-0.812-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56"}, 556 | {file = "mypy-0.812-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8"}, 557 | {file = "mypy-0.812-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7"}, 558 | {file = "mypy-0.812-cp37-cp37m-win_amd64.whl", hash = "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564"}, 559 | {file = "mypy-0.812-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506"}, 560 | {file = "mypy-0.812-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5"}, 561 | {file = "mypy-0.812-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66"}, 562 | {file = "mypy-0.812-cp38-cp38-win_amd64.whl", hash = "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e"}, 563 | {file = "mypy-0.812-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a"}, 564 | {file = "mypy-0.812-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a"}, 565 | {file = "mypy-0.812-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97"}, 566 | {file = "mypy-0.812-cp39-cp39-win_amd64.whl", hash = "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df"}, 567 | {file = "mypy-0.812-py3-none-any.whl", hash = "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4"}, 568 | {file = "mypy-0.812.tar.gz", hash = "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119"}, 569 | ] 570 | mypy-extensions = [ 571 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 572 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 573 | ] 574 | packaging = [ 575 | {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, 576 | {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, 577 | ] 578 | pluggy = [ 579 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 580 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 581 | ] 582 | py = [ 583 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, 584 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, 585 | ] 586 | pycodestyle = [ 587 | {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, 588 | {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, 589 | ] 590 | pydantic = [ 591 | {file = "pydantic-1.7.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd"}, 592 | {file = "pydantic-1.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009"}, 593 | {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d8df4b9090b595511906fa48deda47af04e7d092318bfb291f4d45dfb6bb2127"}, 594 | {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:514b473d264671a5c672dfb28bdfe1bf1afd390f6b206aa2ec9fed7fc592c48e"}, 595 | {file = "pydantic-1.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:dba5c1f0a3aeea5083e75db9660935da90216f8a81b6d68e67f54e135ed5eb23"}, 596 | {file = "pydantic-1.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59e45f3b694b05a69032a0d603c32d453a23f0de80844fb14d55ab0c6c78ff2f"}, 597 | {file = "pydantic-1.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5b24e8a572e4b4c18f614004dda8c9f2c07328cb5b6e314d6e1bbd536cb1a6c1"}, 598 | {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:b2b054d095b6431cdda2f852a6d2f0fdec77686b305c57961b4c5dd6d863bf3c"}, 599 | {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:025bf13ce27990acc059d0c5be46f416fc9b293f45363b3d19855165fee1874f"}, 600 | {file = "pydantic-1.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6e3874aa7e8babd37b40c4504e3a94cc2023696ced5a0500949f3347664ff8e2"}, 601 | {file = "pydantic-1.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e682f6442ebe4e50cb5e1cfde7dda6766fb586631c3e5569f6aa1951fd1a76ef"}, 602 | {file = "pydantic-1.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:185e18134bec5ef43351149fe34fda4758e53d05bb8ea4d5928f0720997b79ef"}, 603 | {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:f5b06f5099e163295b8ff5b1b71132ecf5866cc6e7f586d78d7d3fd6e8084608"}, 604 | {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:24ca47365be2a5a3cc3f4a26dcc755bcdc9f0036f55dcedbd55663662ba145ec"}, 605 | {file = "pydantic-1.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:d1fe3f0df8ac0f3a9792666c69a7cd70530f329036426d06b4f899c025aca74e"}, 606 | {file = "pydantic-1.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f6864844b039805add62ebe8a8c676286340ba0c6d043ae5dea24114b82a319e"}, 607 | {file = "pydantic-1.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ecb54491f98544c12c66ff3d15e701612fc388161fd455242447083350904730"}, 608 | {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ffd180ebd5dd2a9ac0da4e8b995c9c99e7c74c31f985ba090ee01d681b1c4b95"}, 609 | {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8d72e814c7821125b16f1553124d12faba88e85405b0864328899aceaad7282b"}, 610 | {file = "pydantic-1.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:475f2fa134cf272d6631072554f845d0630907fce053926ff634cc6bc45bf1af"}, 611 | {file = "pydantic-1.7.3-py3-none-any.whl", hash = "sha256:38be427ea01a78206bcaf9a56f835784afcba9e5b88fbdce33bbbfbcd7841229"}, 612 | {file = "pydantic-1.7.3.tar.gz", hash = "sha256:213125b7e9e64713d16d988d10997dabc6a1f73f3991e1ff8e35ebb1409c7dc9"}, 613 | ] 614 | pyflakes = [ 615 | {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, 616 | {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, 617 | ] 618 | pylint = [ 619 | {file = "pylint-2.7.1-py3-none-any.whl", hash = "sha256:a251b238db462b71d25948f940568bb5b3ae0e37dbaa05e10523f54f83e6cc7e"}, 620 | {file = "pylint-2.7.1.tar.gz", hash = "sha256:81ce108f6342421169ea039ff1f528208c99d2e5a9c4ca95cfc5291be6dfd982"}, 621 | ] 622 | pyparsing = [ 623 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 624 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 625 | ] 626 | pytest = [ 627 | {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"}, 628 | {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"}, 629 | ] 630 | python-dateutil = [ 631 | {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, 632 | {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, 633 | ] 634 | python-editor = [ 635 | {file = "python-editor-1.0.4.tar.gz", hash = "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b"}, 636 | {file = "python_editor-1.0.4-py2-none-any.whl", hash = "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8"}, 637 | {file = "python_editor-1.0.4-py2.7.egg", hash = "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522"}, 638 | {file = "python_editor-1.0.4-py3-none-any.whl", hash = "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d"}, 639 | {file = "python_editor-1.0.4-py3.5.egg", hash = "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77"}, 640 | ] 641 | six = [ 642 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 643 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 644 | ] 645 | sqlalchemy = [ 646 | {file = "SQLAlchemy-1.3.23-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:fd3b96f8c705af8e938eaa99cbd8fd1450f632d38cad55e7367c33b263bf98ec"}, 647 | {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:29cccc9606750fe10c5d0e8bd847f17a97f3850b8682aef1f56f5d5e1a5a64b1"}, 648 | {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:927ce09e49bff3104459e1451ce82983b0a3062437a07d883a4c66f0b344c9b5"}, 649 | {file = "SQLAlchemy-1.3.23-cp27-cp27m-win32.whl", hash = "sha256:b4b0e44d586cd64b65b507fa116a3814a1a53d55dce4836d7c1a6eb2823ff8d1"}, 650 | {file = "SQLAlchemy-1.3.23-cp27-cp27m-win_amd64.whl", hash = "sha256:6b8b8c80c7f384f06825612dd078e4a31f0185e8f1f6b8c19e188ff246334205"}, 651 | {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9e9c25522933e569e8b53ccc644dc993cab87e922fb7e142894653880fdd419d"}, 652 | {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a0e306e9bb76fd93b29ae3a5155298e4c1b504c7cbc620c09c20858d32d16234"}, 653 | {file = "SQLAlchemy-1.3.23-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:6c9e6cc9237de5660bcddea63f332428bb83c8e2015c26777281f7ffbd2efb84"}, 654 | {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:94f667d86be82dd4cb17d08de0c3622e77ca865320e0b95eae6153faa7b4ecaf"}, 655 | {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:751934967f5336a3e26fc5993ccad1e4fee982029f9317eb6153bc0bc3d2d2da"}, 656 | {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:63677d0c08524af4c5893c18dbe42141de7178001360b3de0b86217502ed3601"}, 657 | {file = "SQLAlchemy-1.3.23-cp35-cp35m-win32.whl", hash = "sha256:ddfb511e76d016c3a160910642d57f4587dc542ce5ee823b0d415134790eeeb9"}, 658 | {file = "SQLAlchemy-1.3.23-cp35-cp35m-win_amd64.whl", hash = "sha256:040bdfc1d76a9074717a3f43455685f781c581f94472b010cd6c4754754e1862"}, 659 | {file = "SQLAlchemy-1.3.23-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d1a85dfc5dee741bf49cb9b6b6b8d2725a268e4992507cf151cba26b17d97c37"}, 660 | {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:639940bbe1108ac667dcffc79925db2966826c270112e9159439ab6bb14f8d80"}, 661 | {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e8a1750b44ad6422ace82bf3466638f1aa0862dbb9689690d5f2f48cce3476c8"}, 662 | {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e5bb3463df697279e5459a7316ad5a60b04b0107f9392e88674d0ece70e9cf70"}, 663 | {file = "SQLAlchemy-1.3.23-cp36-cp36m-win32.whl", hash = "sha256:e273367f4076bd7b9a8dc2e771978ef2bfd6b82526e80775a7db52bff8ca01dd"}, 664 | {file = "SQLAlchemy-1.3.23-cp36-cp36m-win_amd64.whl", hash = "sha256:ac2244e64485c3778f012951fdc869969a736cd61375fde6096d08850d8be729"}, 665 | {file = "SQLAlchemy-1.3.23-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:23927c3981d1ec6b4ea71eb99d28424b874d9c696a21e5fbd9fa322718be3708"}, 666 | {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d90010304abb4102123d10cbad2cdf2c25a9f2e66a50974199b24b468509bad5"}, 667 | {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a8bfc1e1afe523e94974132d7230b82ca7fa2511aedde1f537ec54db0399541a"}, 668 | {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:269990b3ab53cb035d662dcde51df0943c1417bdab707dc4a7e4114a710504b4"}, 669 | {file = "SQLAlchemy-1.3.23-cp37-cp37m-win32.whl", hash = "sha256:fdd2ed7395df8ac2dbb10cefc44737b66c6a5cd7755c92524733d7a443e5b7e2"}, 670 | {file = "SQLAlchemy-1.3.23-cp37-cp37m-win_amd64.whl", hash = "sha256:6a939a868fdaa4b504e8b9d4a61f21aac11e3fecc8a8214455e144939e3d2aea"}, 671 | {file = "SQLAlchemy-1.3.23-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:24f9569e82a009a09ce2d263559acb3466eba2617203170e4a0af91e75b4f075"}, 672 | {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2578dbdbe4dbb0e5126fb37ffcd9793a25dcad769a95f171a2161030bea850ff"}, 673 | {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1fe5d8d39118c2b018c215c37b73fd6893c3e1d4895be745ca8ff6eb83333ed3"}, 674 | {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c7dc052432cd5d060d7437e217dd33c97025287f99a69a50e2dc1478dd610d64"}, 675 | {file = "SQLAlchemy-1.3.23-cp38-cp38-win32.whl", hash = "sha256:ecce8c021894a77d89808222b1ff9687ad84db54d18e4bd0500ca766737faaf6"}, 676 | {file = "SQLAlchemy-1.3.23-cp38-cp38-win_amd64.whl", hash = "sha256:37b83bf81b4b85dda273aaaed5f35ea20ad80606f672d94d2218afc565fb0173"}, 677 | {file = "SQLAlchemy-1.3.23-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8be835aac18ec85351385e17b8665bd4d63083a7160a017bef3d640e8e65cadb"}, 678 | {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6ec1044908414013ebfe363450c22f14698803ce97fbb47e53284d55c5165848"}, 679 | {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eab063a70cca4a587c28824e18be41d8ecc4457f8f15b2933584c6c6cccd30f0"}, 680 | {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:baeb451ee23e264de3f577fee5283c73d9bbaa8cb921d0305c0bbf700094b65b"}, 681 | {file = "SQLAlchemy-1.3.23-cp39-cp39-win32.whl", hash = "sha256:94208867f34e60f54a33a37f1c117251be91a47e3bfdb9ab8a7847f20886ad06"}, 682 | {file = "SQLAlchemy-1.3.23-cp39-cp39-win_amd64.whl", hash = "sha256:f4d972139d5000105fcda9539a76452039434013570d6059993120dc2a65e447"}, 683 | {file = "SQLAlchemy-1.3.23.tar.gz", hash = "sha256:6fca33672578666f657c131552c4ef8979c1606e494f78cd5199742dfb26918b"}, 684 | ] 685 | toml = [ 686 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 687 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 688 | ] 689 | typed-ast = [ 690 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, 691 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, 692 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, 693 | {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, 694 | {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, 695 | {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, 696 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, 697 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, 698 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, 699 | {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, 700 | {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, 701 | {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, 702 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, 703 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, 704 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, 705 | {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, 706 | {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, 707 | {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, 708 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, 709 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, 710 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, 711 | {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, 712 | {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, 713 | {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, 714 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, 715 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, 716 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, 717 | {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, 718 | {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, 719 | {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, 720 | ] 721 | typer = [ 722 | {file = "typer-0.3.2-py3-none-any.whl", hash = "sha256:ba58b920ce851b12a2d790143009fa00ac1d05b3ff3257061ff69dbdfc3d161b"}, 723 | {file = "typer-0.3.2.tar.gz", hash = "sha256:5455d750122cff96745b0dec87368f56d023725a7ebc9d2e54dd23dc86816303"}, 724 | ] 725 | typing-extensions = [ 726 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 727 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 728 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 729 | ] 730 | wrapt = [ 731 | {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, 732 | ] 733 | zipp = [ 734 | {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, 735 | {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, 736 | ] 737 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "fastapi-migrations" 3 | version = "0.0.5" 4 | description = "Sqlalchemy integration with async support" 5 | authors = ["Ariel Carvajal "] 6 | license = "MIT" 7 | 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.7" 11 | 12 | # main deps 13 | alembic = "^1.5.5" 14 | typer = "^0.3.2" 15 | pydantic = "^1.7.3" 16 | 17 | [tool.poetry.dev-dependencies] 18 | # lint 19 | flake8 = "^3.8.4" 20 | mypy = "^0.812" 21 | pylint = "^2.7.1" 22 | autopep8 = "^1.5.5" 23 | 24 | # tests 25 | pytest = "^6.2.2" 26 | 27 | [build-system] 28 | # TODO: configure build 29 | #requires = ["poetry-core>=1.0.0"] 30 | #build-backend = "poetry.core.masonry.api" 31 | requires = ["setuptools", "wheel", "toml"] 32 | build-backend = "setuptools.build_meta" 33 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # type: ignore 2 | 3 | ''' 4 | Fastapi migrations 5 | -------------- 6 | A small integration between Fastapi and Alembic. 7 | ''' 8 | from setuptools import setup 9 | from toml import load 10 | 11 | pyproject = load('pyproject.toml') 12 | 13 | long_description = open('README.md', 'r').read() 14 | 15 | setup_info = pyproject.get('tool').get('poetry') 16 | version = setup_info.get('version') 17 | requirements = setup_info.get('dependencies').keys() 18 | dev_requirements = setup_info.get('dev-dependencies').keys() 19 | 20 | 21 | setup( 22 | name='fastapi-migrations', 23 | version=version, 24 | url='https://github.com/patiprecios/fastapi-migrations', 25 | project_urls={ 26 | 'Code': 'https://github.com/patiprecios/fastapi-migrations', 27 | 'Issues': 'https://github.com/patiprecios/fastapi-migrations/issues', 28 | }, 29 | license='MIT', 30 | author='Ariel Carvajal', 31 | author_email='arie.cbpro@gmail.com', 32 | description=('A small integration between Fastapi and Alembic.'), 33 | long_description=long_description, 34 | long_description_content_type='text/markdown', 35 | packages=['fastapi_migrations'], 36 | zip_safe=False, 37 | include_package_data=True, 38 | platforms='any', 39 | install_requires=requirements, 40 | tests_require=dev_requirements, 41 | test_suite='tests', 42 | classifiers=[ 43 | 'Environment :: Web Environment', 44 | 'Intended Audience :: Developers', 45 | 'License :: OSI Approved :: MIT License', 46 | 'Operating System :: OS Independent', 47 | 'Programming Language :: Python', 48 | 'Programming Language :: Python :: 3', 49 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 50 | 'Topic :: Software Development :: Libraries :: Python Modules' 51 | ] 52 | ) 53 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uselessscat/fastapi-migrations/600f5c588d908c4c927a2ab6b0f6a333faf17a38/tests/__init__.py -------------------------------------------------------------------------------- /tests/fixtures.py: -------------------------------------------------------------------------------- 1 | from typing import Type, Callable, Any, Generator, Dict, Optional 2 | 3 | import shutil 4 | from os.path import isdir 5 | 6 | import pytest 7 | 8 | from fastapi_migrations import Migrations, MigrationsConfig 9 | 10 | 11 | class TestDirectories: 12 | DEFAULT: str = 'migrations' 13 | TEST: str = 'migrations_test' 14 | 15 | 16 | @pytest.fixture 17 | def dirs() -> Type[TestDirectories]: 18 | return TestDirectories 19 | 20 | 21 | def init_migrate(): 22 | mig_list = [] 23 | 24 | def instance_migrations(**kwargs) -> Type[Migrations]: 25 | c = MigrationsConfig(**kwargs) 26 | m = Migrations(c) 27 | mig_list.append(m) 28 | 29 | # check directory doesn't exists 30 | assert not isdir(m.configuration.script_location) 31 | 32 | m.init() 33 | 34 | return m 35 | 36 | yield instance_migrations 37 | 38 | for mig in mig_list: 39 | shutil.rmtree(mig.configuration.script_location) 40 | 41 | # check directory was erased 42 | assert not isdir(mig.configuration.script_location) 43 | -------------------------------------------------------------------------------- /tests/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uselessscat/fastapi-migrations/600f5c588d908c4c927a2ab6b0f6a333faf17a38/tests/models.py -------------------------------------------------------------------------------- /tests/test_config.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | from os.path import join 3 | 4 | from tests.fixtures import dirs, TestDirectories 5 | 6 | from fastapi_migrations.cli import MigrationsCli 7 | from fastapi_migrations import Migrations, MigrationsConfig 8 | 9 | 10 | def test_create_migrations(dirs: TestDirectories) -> None: 11 | m = Migrations() 12 | 13 | assert m 14 | assert m.configuration 15 | assert m.configuration.script_location == dirs.DEFAULT 16 | 17 | 18 | def test_create_migrations_cli(dirs: TestDirectories) -> None: 19 | m = MigrationsCli() 20 | 21 | assert m 22 | assert m.migrations 23 | assert m.migrations.configuration 24 | assert m.migrations.configuration.script_location == dirs.DEFAULT 25 | 26 | 27 | def test_create_migrations_config(dirs: TestDirectories) -> None: 28 | c = MigrationsConfig(script_location=dirs.TEST) 29 | m = Migrations(c) 30 | 31 | assert m.configuration 32 | assert m.configuration.script_location == dirs.TEST 33 | 34 | 35 | def test_create_migrations_cli_config(dirs: TestDirectories) -> None: 36 | c = MigrationsConfig(script_location=dirs.TEST) 37 | m = MigrationsCli(c) 38 | 39 | assert m.migrations.configuration 40 | assert m.migrations.configuration.script_location == dirs.TEST 41 | 42 | 43 | def test_get_ini_config(dirs: TestDirectories) -> None: 44 | from alembic.config import Config as aconf 45 | 46 | m = Migrations() 47 | m.init() 48 | 49 | c = aconf(join(dirs.DEFAULT, 'alembic.ini')) 50 | 51 | print("ASDASDAS", c.file_config.sections) 52 | 53 | shutil.rmtree(dirs.DEFAULT) 54 | -------------------------------------------------------------------------------- /tests/test_imports.py: -------------------------------------------------------------------------------- 1 | def test_import_alembic() -> None: 2 | import alembic 3 | 4 | assert alembic 5 | 6 | 7 | def test_import_typer() -> None: 8 | import typer 9 | 10 | assert typer 11 | 12 | 13 | def test_import_pydantic() -> None: 14 | import pydantic 15 | 16 | assert pydantic 17 | 18 | 19 | def test_import_classes() -> None: 20 | from fastapi_migrations import Migrations, MigrationsConfig 21 | from fastapi_migrations.cli import MigrationsCli 22 | 23 | assert Migrations 24 | assert MigrationsCli 25 | assert MigrationsConfig 26 | -------------------------------------------------------------------------------- /tests/test_programatic_commands.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, List, Set, Any 2 | 3 | import shutil 4 | from os import listdir 5 | from os.path import isdir, isfile, join 6 | 7 | from tests.fixtures import dirs, init_migrate, TestDirectories 8 | 9 | from fastapi_migrations import Migrations 10 | 11 | 12 | def exclude_non_revision(dir_list: List[str]) -> Set[str]: 13 | return set(dir_list) - set(['__pycache__']) 14 | 15 | 16 | def test_migrations_dirs_not_exist(dirs: TestDirectories) -> None: 17 | assert not isdir(dirs.DEFAULT) 18 | assert not isdir(dirs.TEST) 19 | 20 | 21 | def test_init_creates_folders(dirs: TestDirectories) -> None: 22 | m = Migrations() 23 | 24 | assert not isdir(dirs.DEFAULT) 25 | 26 | m.init() 27 | assert isdir(dirs.DEFAULT) 28 | 29 | shutil.rmtree(dirs.DEFAULT) 30 | 31 | 32 | def test_init_fixture( 33 | dirs: TestDirectories, 34 | init_migrate 35 | ) -> None: 36 | init_migrate() 37 | 38 | assert isdir(dirs.DEFAULT) 39 | 40 | 41 | def test_init_creates_files( 42 | dirs: TestDirectories, 43 | init_migrate 44 | ) -> None: 45 | init_migrate(script_location=dirs.DEFAULT) 46 | 47 | assert isfile(join(dirs.DEFAULT, 'alembic.ini')) 48 | assert isfile(join(dirs.DEFAULT, 'env.py')) 49 | assert isfile(join(dirs.DEFAULT, 'README')) 50 | assert isfile(join(dirs.DEFAULT, 'script.py.mako')) 51 | assert isdir(join(dirs.DEFAULT, 'versions')) 52 | assert len(listdir(join(dirs.DEFAULT, 'versions'))) == 0 53 | 54 | 55 | def test_init_creates_files_specified_folder( 56 | dirs: TestDirectories, 57 | init_migrate 58 | ) -> None: 59 | init_migrate(script_location=dirs.TEST) 60 | 61 | assert isdir(dirs.TEST) 62 | assert isfile(join(dirs.TEST, 'alembic.ini')) 63 | assert isfile(join(dirs.TEST, 'env.py')) 64 | assert isfile(join(dirs.TEST, 'README')) 65 | assert isfile(join(dirs.TEST, 'script.py.mako')) 66 | assert isdir(join(dirs.TEST, 'versions')) 67 | assert len(listdir(join(dirs.TEST, 'versions'))) == 0 68 | 69 | 70 | def test_init_creates_different_ini_file( 71 | dirs: TestDirectories, 72 | init_migrate 73 | ) -> None: 74 | init_migrate( 75 | script_location=dirs.TEST, 76 | config_file_name='different.ini' 77 | ) 78 | 79 | assert isdir(dirs.TEST) 80 | assert isfile(join(dirs.TEST, 'different.ini')) 81 | 82 | 83 | def test_revision_create( 84 | dirs: TestDirectories, 85 | init_migrate 86 | ) -> None: 87 | m = init_migrate(script_location=dirs.DEFAULT) 88 | 89 | assert len(listdir(join(dirs.DEFAULT, 'versions'))) == 0 90 | 91 | script = m.revision('revision_one') 92 | 93 | dir_list = listdir(join(m.configuration.script_location, 'versions')) 94 | assert len(exclude_non_revision(dir_list)) == 1 95 | 96 | assert script.doc == 'revision_one' 97 | assert isfile(script.path) 98 | assert isfile(join(dirs.DEFAULT, 'versions', script.revision + '.py')) 99 | 100 | script2 = m.revision('revision_two') 101 | 102 | dir_list = listdir(join(m.configuration.script_location, 'versions')) 103 | assert len(exclude_non_revision(dir_list)) == 2 104 | 105 | assert script2.doc == 'revision_two' 106 | assert isfile(script2.path) 107 | assert isfile(join(dirs.DEFAULT, 'versions', script2.revision + '.py')) 108 | 109 | 110 | def test_revision_create_auto( 111 | dirs: TestDirectories, 112 | init_migrate 113 | ) -> None: 114 | init_migrate(script_location=dirs.DEFAULT) 115 | 116 | # TODO: Update this 117 | # m.revision('revision_one', autogenerate=True) 118 | --------------------------------------------------------------------------------