Python - 使用安装工具打包 Alembic 迁移

问题描述 投票:0回答:3

将 Alembic 迁移文件打包到 Setuptools

setup.py
文件中的正确方法是什么?一切都在我的仓库根目录中,为
alembic/

这是一个 Python 应用程序,而不是一个库。

我想要的安装流程是有人可以

pip install
我的应用程序的轮子。然后,他们可以通过运行类似
<app> alembic upgrade --sqlalchemy.url=<db_url>
的操作来初始化应用程序数据库。然后升级需要
pip install -U
,之后他们可以再次运行 Alembic 命令。

这是非正统吗?

如果没有,我将如何实现这一点?当然是

console_scripts
entry_points
。但除此之外?

python setuptools alembic
3个回答
9
投票

我不确定这是正确的方法,但我这样做了:

首先,您可以使用 -x 选项向 alembic 添加自定义选项,您可以在 这个很棒的答案中找到详细说明。这允许您在运行时指定

db_url
并使其覆盖
config.ini
中的值。

然后,我通过将

alembic.ini
文件和
alembic
目录从项目根移动到顶级 python 包,成功打包了 alembic 和我的迁移:

<project root>
├── src
│   └── <top-level package dir>
│       ├── alembic
│       │   ├── env.py
│       │   ├── README
│       │   ├── script.py.mako
│       │   └── versions
│       │       ├── 58c8dcd5fbdc_revision_1.py
│       │       └── ec385b47da23_revision_2.py
│       ├── alembic.ini
│       ├── __init__.py
│       └── <other files and dirs>
└── <other files and dirs>

这允许在我的

package_data
中使用setuptools
setup.py
指令:

setup(
    name=<package_name>,
    package_dir={'': 'src'},
    packages=find_packages(where='src'),
    package_data={
        '<top-level package dir>': ['alembic.ini', 'alembic/*', 'alembic/**/*'],
    },
    [...]
)  

此时,alembic 配置和修订版已正确打包,但必须调整

alembic.ini
设置以反映新的目录树。可以使用
%(here)s
参数来完成,该参数包含包含
alembic.ini
文件的目录的绝对路径:

# A generic, single database configuration.

[alembic]
# path to migration scripts
script_location = %(here)s/alembic

[...]

# version location specification; this defaults
# to alembic/versions.  When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
version_locations = %(here)s/alembic/versions

[...]

最后,您必须使用

alembic
选项调用
-c
,该选项允许提供配置文件的路径:

alembic -c <path to alembic.ini> ...

5
投票

将 alembic 文件夹保留在主包文件夹中的一种方法是将 alembic 文件夹视为它自己的包,与主包一起安装。

要做到这一点,你必须重命名它(它不能被称为

alembic
,因为它将是一个顶级包,所以需要一个唯一的名称 - 我已经使用了
migrations
),并添加一个
__init__.py
文件在 alembic 文件夹和 versions 文件夹中。

在部署上运行迁移需要了解已安装软件包的路径 - 一种简单的方法是提供应用迁移的控制台脚本。

所以项目结构如下所示:

<project root>
├── setup.py
├── mypackage
│   └── <project source files...>
│
├── migrations
│   ├── __init__.py
│   ├── alembic.ini
│   ├── apply.py
│   ├── env.py
│   ├── README
│   ├── script.py.mako
│   └── versions
│       ├── __init__.py
│       ├── 58c8dcd5fbdc_revision_1.py
│       └── ec385b47da23_revision_2.py
│
└── <other files and dirs>

setup.py

from setuptools import find_packages
from setuptools import setup


setup(
    name='mypackage',
    packages=find_packages(exclude=('tests',)),
    package_data={'migrations': ['alembic.ini']},
    entry_points={
        'console_scripts': ['apply-migrations=migrations.apply:main'],
    },
    install_requires=[
        "SQLAlchemy==1.3.0",
        "alembic==1.0.10",
        # ...
    ]
)

最后

migrations/apply.py

# Python script that will apply the migrations up to head
import alembic.config
import os

here = os.path.dirname(os.path.abspath(__file__))

alembic_args = [
    '-c', os.path.join(here, 'alembic.ini'),
    'upgrade', 'head'
]


def main():
    alembic.config.main(argv=alembic_args)

现在安装好轮子后,您将拥有一个可以直接调用的命令

apply-migrations
。请注意,我在这里实现的版本没有任何参数 - 尽管如果您想通过例如。
--sqlalchemy.url
您可以将其添加到
alembic_args

我个人更喜欢在

migrations/env.py
中设置url。例如,如果您有一个名为
SQLACLHEMYURL
的环境变量,您可以将其添加到
migrations/env.py
:

import os
config.set_main_options(os.getenv('SQLALCHEMYURL'))

然后你可以调用:

SQLALCHEMYURL=... apply-migrations

正在部署。


0
投票

要公开

alembic
的所有参数,请将
sys.argv
传递给 alembic。这是@Alice Heaton 答案的延伸。

项目布局:

my-app
├── my_app
│   └── migrations
│       ├── alembic.ini
│       ├── apply.py
│       ├── env.py
│       ├── script.py.mako
│       └── versions
└── setup.py

setup.py

from setuptools import setup

setup(
    name="my-app",
    packages=["my_app"],
    entry_points={
        "console_scripts": [
            # This overwrites the existing alembic command
            "alembic = my_app.migrations.apply:main",
        ],
    },
)

migrations/apply.py

import sys
from pathlib import Path

import alembic.config

here = Path(__file__).parent


def main():
    argv = [
        # Use our custom config path
        "--config", str(here / "alembic.ini"),
        # Forward all other arguments to alembic as is
        *sys.argv[1:]
    ]
    alembic.config.main(argv=argv)

alembic.ini

[alembic]
script_location = %(here)s
© www.soinside.com 2019 - 2024. All rights reserved.