简体   繁体   English

如何以编程方式运行/调用flask cli命令?

[英]How to run/invoke a flask cli command programmatically?

I am using python 3 and flask, with flask-migrate (which uses alembic) to handle my SQL migrations.我正在使用 python 3 和flask,使用flask-migrate(使用alembic)来处理我的SQL 迁移。 When I run local integration tests, I want to rebuild the database each time so I can run my API calls against a clean db for each api call i'm testing (yes, i could use sqlite, but i want to check constraints are correct).当我运行本地集成测试时,我想每次都重建数据库,以便我可以针对我正在测试的每个 api 调用针对干净的数据库运行我的 API 调用(是的,我可以使用 sqlite,但我想检查约束是否正确)。

I can do the following on the command line easily:我可以轻松地在命令行上执行以下操作:

mysql -uroot -e 'drop database DBNAME; create database DBNAME;'
FLASK_APP=flask_app.py flask db upgrade

But I would rather run it in the python code for 2 reasons:但我宁愿在 python 代码中运行它,原因有两个:

  1. I don't want to have to worry about the mysql client being installed on the CI machines that will (eventually) run this code (they should just need to the python mysql packages).我不想担心安装在 CI 机器上的 mysql 客户端将(最终)运行此代码(他们应该只需要 python mysql 包)。
  2. I want to manipulate the flask settings to force the database name to avoid accidents (so it needs to run in the same thread/memory space as the script which invokes it).我想操纵烧瓶设置以强制使用数据库名称以避免意外(因此它需要在与调用它的脚本相同的线程/内存空间中运行)。

The app object (created with app = Flask(__name__) ) has a cli property, but it requires a context object, and it doesn't feel like i'm using the right tool. app对象(用app = Flask(__name__) )有一个cli属性,但它需要一个上下文对象,而且我觉得我没有使用正确的工具。 I expected app.cli.invoke('db', 'upgrade') or similar...我期望app.cli.invoke('db', 'upgrade')或类似的...

Any suggestions on how to invoke flask commands from the code without a child cli process?关于如何在没有子 cli 进程的情况下从代码调用烧瓶命令的任何建议?

I use the following pattern (see below).我使用以下模式(见下文)。 An alternate approach can be seen at https://flask.palletsprojects.com/en/1.1.x/cli/?highlight=click#application-context可以在https://flask.palletsprojects.com/en/1.1.x/cli/?highlight=click#application-context上看到另一种方法

# file: commands.py
import click
from click import pass_context
from flask.cli import AppGroup, with_appcontext
from flask import current_app
from flask_migrate import Migrate
from alembic import command

from extensions import flask_db as db

db_cli = AppGroup('db', help='Various database management commands.')

@db_cli.command('init')
def db_init():
    """Initialize the database."""
    db.create_all()
    click.echo("Create all tables.")


@db_cli.command('drop')
def db_drop():
    """Drop the database."""
    db.engine.execute("SET FOREIGN_KEY_CHECKS=0;")
    db.drop_all()
    db.engine.execute("SET FOREIGN_KEY_CHECKS=1;")
    click.echo("Drop all tables.")

@db_cli.command('migrate')
def db_migrate():
    "Migrate with alembic."

    config = Migrate(current_app, db).get_config()
    command.upgrade(config, 'head')


@db_cli.command('db_upgrade')
@pass_context
def db_upgrade(ctx):
    """Alias for 'db reset'."""
    db_drop.invoke(ctx)
    db_init.invoke(ctx)
    db_migrate.invoke(ctx)
# file: extensions.py
# Keep your extenstions separate to allow importing without import loops.

from flask_sqlalchemy import SQLAlchemy

flask_db = SQLAlchemy()
# file: app.py (app/__init__.py) wherever your app is built
from extensions import flask_db

app = Flask(__name__)

flask_db.init_app(app)  # I'm not sure if the order matters here.
app.cli.add_command(db_cli)
# file: wsgi.py (top level file)
# This file lets you run 'flask' commands (e.g. flask routes)

# noinspection PyUnresolvedReferences
from app import app as application  # noqa
# file layout
- /
  - app/  (or app.py)
    - __init__.py  (optional)
  - commands.py
  - extensions.py
  - wsgi.py

Usage: flask db upgrade用法: flask db upgrade

It's not great, but in the end I avoided using flask commands directly and this seems to do what i need:这不是很好,但最后我避免直接​​使用烧瓶命令,这似乎满足了我的需要:

from my.app import app, db, initialize_app
from flask_migrate import Migrate
from alembic import command
from my.settings import settings
from sqlalchemy_utils.functions import drop_database, create_database, database_exists

test_db_name = 'test_db'
db_url = f'mysql+pymysql://mysqluser@127.0.0.1/{test_db_name}'
settings.SQLALCHEMY_DATABASE_URI = db_url


def reset():
    if database_exists(db_url):
        drop_database(db_url)
    create_database(db_url)
    initialize_app(app) # sets flask config SQLALCHEMY_DATABASE_URI to include test_db
    with app.app_context():
        config = Migrate(app, db).get_config()
        command.upgrade(config, 'head')

Is there any reason that you can't simply wrap the functions that have all the logic for the CLI?是否有任何理由不能简单地包装具有 CLI 的所有逻辑的函数?

something like就像是

# cli.py

def db_init(cli=False):
    db.create_all()
    if cli:
        print("Created all tables")

@app.cli.command('db-init')
def _db_init(): # I'm just a wrapper function
    db_init(cli=True) 

If you do it that way, there should be no reason why you can't simply do this afterwards:如果你这样做,就没有理由事后不能简单地这样做:

# some_module.py

from .cli import db_init

db_init()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何以编程方式“解决” Flask cli 命令? - How to “resolve” a Flask cli command programmatically? 如何在前台运行 flask 自定义 cli 命令? - How to run flask custom cli command in foreground? Flask如何处理“flask run”cli命令? - How does Flask process the “flask run” cli command? 如何在 AWS Elastic Beanstalk 中运行 flask CLI 命令 - How to run flask CLI command in AWS Elastic Beanstalk 使用PyCharm调试器运行Flask CLI命令 - Run Flask CLI command with PyCharm debugger 有什么方法可以在 azure cli 中运行多个调用命令? - is there any way to run multiple invoke command in azure cli? 带有多个命令行参数的az cli运行命令调用失败 - az cli run-command invoke with multiple command line parameters fails 如何从 Python 脚本运行 CLI 命令? - How to run a CLI command from a Python script? 如何在 supervisord 中捕获 Flask CLI 命令的 output 并将其重定向到标准输出? - How to capture output of Flask CLI command in supervisord and redirect it to stdout? Azure Python CLI:使用运行命令调用的启动脚本在使用 @ 但不使用内联命令传递脚本文件时失败 - Azure Python CLI: launch script with run-command invoke fails when passing the script file with @ but not with inline commands
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM