{"id":15576354,"url":"https://github.com/alvassin/alembic-quickstart","last_synced_at":"2025-08-11T17:12:13.371Z","repository":{"id":53856467,"uuid":"218514893","full_name":"alvassin/alembic-quickstart","owner":"alvassin","description":"Examples how to test Alembic migrations for Yandex Backend Development school \u0026 Moscow Python meetup №69","archived":false,"fork":false,"pushed_at":"2022-08-02T12:48:22.000Z","size":129,"stargazers_count":233,"open_issues_count":0,"forks_count":33,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-17T12:11:14.532Z","etag":null,"topics":["aiohttp","alembic","example","migrations","pytest","python","python3","sqlalchemy","testing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alvassin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-30T11:45:55.000Z","updated_at":"2025-03-05T14:53:16.000Z","dependencies_parsed_at":"2022-08-23T08:10:40.722Z","dependency_job_id":null,"html_url":"https://github.com/alvassin/alembic-quickstart","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvassin%2Falembic-quickstart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvassin%2Falembic-quickstart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvassin%2Falembic-quickstart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvassin%2Falembic-quickstart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alvassin","download_url":"https://codeload.github.com/alvassin/alembic-quickstart/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245761295,"owners_count":20667895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiohttp","alembic","example","migrations","pytest","python","python3","sqlalchemy","testing"],"created_at":"2024-10-02T18:47:23.287Z","updated_at":"2025-03-27T01:09:47.477Z","avatar_url":"https://github.com/alvassin.png","language":"Python","readme":"Migrations testing and [Alembic](https://alembic.sqlalchemy.org/en/latest/) \nusage examples.\n\nPrepared for [\"Databases: models, migrations, testing\"](https://habr.com/ru/company/yandex/blog/498856/#5) lection at \n[Yandex Backend Development school](https://yandex.ru/promo/academy/backend-school/) and \n[\"How to develop \u0026 test database migrations with Alembic\"](https://youtu.be/qrlTDNaUQ-Q?t=5650) presentation at \n[Moscow Python meetup №69](https://events.yandex.ru/events/moscow-python-meetup-30-10-2019) (videos are in Russian). \n\nCode \u0026 examples are updated from time to time, please browse files at [7b804f8371bc14bbc35991654a37fc90b7fe4358](https://github.com/alvassin/alembic-quickstart/tree/7b804f8371bc14bbc35991654a37fc90b7fe4358) commit if you need exact code shown at Moscow Python meetup.\n\n[🇷🇺 Russian translation](README_ru.md) is available for this document.\n\n## What's inside\n\nAiohttp application with couple migrations and two commands: `staff-db` to control database state (Alembic wrapper) and `staff-api` (REST API aiohttp service).\n\nExecute `make devenv` command to prepare development environment. It will create virtual environment in `./env` folder and install all dependencies (execute `make` for all available commands).\n\n## How to control database state\n\nAlembic provides `alembic` command to control database state (apply, rollback migrations, etc). In some cases it has the following disadvantages:\n\n* `alembic` command requires `alembic.ini` configuration file, which is searched at current working directory. It is possible to specify path to `alembic.ini` using command-line argument `--config`, but it is easier to call the command from any folder without additional parameters.\n* To connect Alembic to specific database it is required to change `sqlalachemy.url` parameter in `alembic.ini`. Sometimes (e.g. if the application is distributed via Docker container) it is much more convenient to specify the database URL with an environment variable and/or a command-line argument.\n* Some applications need to extend standard Alembic arguments (e.g. to support working in different PostgreSQL schemas).\n\nThey can be solved by using Alembic wrapper. For example, `staff-db` provides ability to specify database URL using environment variable `STAFF_PG_URL` or `--pg-url` argument, resolves the path to `alembic.ini` using its location, rather than the current working directory.\n\n## How to prepare database for tests\n\nVery often tests require the database. You can create separate database for each test using pytest fixture (see [postgres fixture](tests/migrations/conftest.py#L8)), this approach allows to isolate tests from each other.\n\nIn most cases, tests require already prepared database with migrations applied. Since it is expensive to run migrations when creating a database for each test, you could do it once to prepare database, and then use it as template to create new databases.\n\nTemplate database is created using [`migrated_postgres_template`](tests/api/conftest.py#L10) fixture within `session` scope. Databases for tests are created using [`migrated_postgres`](tests/api/conftest.py#L24) fixture.\n\n## How to test migrations\n\n### Stairway test\nSimple and efficient method to check that migration does not have typos and \nrolls back all schema changes. Does not require maintenance - you can add this test \nto your project once and forget about it.\n\nIn particular, test detects the data types, that were previously created by `upgrade()` method \nand were not removed by `downgrade()`: when creating a table/column, Alembic automatically \ncreates custom data types specified in columns (e.g. enum), but does not delete them when \ndeleting table or column - developer has to do it manually.\n\n#### How it works\nTest retrieves all migrations list, and for each migration executes `upgrade`, \n`downgrade`, `upgrade` Alembic commands.\nSee [test_stairway.py](tests/migrations/test_stairway.py) for example.\n\n\u003cimg src=\"assets/stairway.gif\" width=\"800\" height=\"277\" alt=\"Stairway test\"\u003e\n\n### Data-migration test\nSome migrations don't just add new columns or tables, but change the data in \nsome way.\n\nIn addition to checking that the migration correctly rolls back changes to the \ndata structure (stairway test), you need to check that the data is correctly \nchanged by the `upgrade()` method and returned to the previous state by the \n`downgrade()` method.\n\nThis test does not guarantee that there are no bugs - it is very difficult to \nprovide data sets for all cases. But data-altering migrations code is \noften very complex, errors are more common, and errors in such migrations can have \nthe most serious consequences.\n\n#### How it works\n\nThe test applies all migrations up to the one being tested and adds a dataset to the database that will be modified by the migration being tested.\nThen test executes the `upgrade()` method and checks that the data was changed correctly. \nAfter this, test calls `downgrade()` method and checks that all data was returned to its initial state.\nSee [test_data_migrations.py](tests/migrations/test_data_migrations.py) for example.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvassin%2Falembic-quickstart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falvassin%2Falembic-quickstart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvassin%2Falembic-quickstart/lists"}