Using Alembic API from inside application code

前端 未结 8 889
夕颜
夕颜 2020-12-08 04:06

I am using SQLite as an application file format (see here for why you would want to do this) for my PySide-based desktop application. That is, when a user uses my app, their

8条回答
  •  自闭症患者
    2020-12-08 05:00

    Here is a purely programmical example of howto configure and call alembic commands programmatically.

    The directory setup (for easier code reading)

    .                         # root dir
    |- alembic/               # directory with migrations
    |- tests/diy_alembic.py   # example script
    |- alembic.ini            # ini file
    

    And here is diy_alembic.py

    import os
    import argparse
    from alembic.config import Config
    from alembic import command
    import inspect
    
    def alembic_set_stamp_head(user_parameter):
        # set the paths values
        this_file_directory = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
        root_directory      = os.path.join(this_file_directory, '..')
        alembic_directory   = os.path.join(root_directory, 'alembic')
        ini_path            = os.path.join(root_directory, 'alembic.ini')
    
        # create Alembic config and feed it with paths
        config = Config(ini_path)
        config.set_main_option('script_location', alembic_directory)    
        config.cmd_opts = argparse.Namespace()   # arguments stub
    
        # If it is required to pass -x parameters to alembic
        x_arg = 'user_parameter=' + user_parameter
        if not hasattr(config.cmd_opts, 'x'):
            if x_arg is not None:
                setattr(config.cmd_opts, 'x', [])
                if isinstance(x_arg, list) or isinstance(x_arg, tuple):
                    for x in x_arg:
                        config.cmd_opts.x.append(x)
                else:
                    config.cmd_opts.x.append(x_arg)
            else:
                setattr(config.cmd_opts, 'x', None)
    
        #prepare and run the command
        revision = 'head'
        sql = False
        tag = None
        command.stamp(config, revision, sql=sql, tag=tag)
    
        #upgrade command
        command.upgrade(config, revision, sql=sql, tag=tag)
    

    The code is more or less a cut from this Flask-Alembic file. It is a good place to look at other commands usage and details.

    Why this solution? - It was written in a need of creating an alembic stamps, upgrades and downgrades when running automated tests.

    • os.chdir(migration_directory) interfered with some tests.
    • We wanted to have ONE source of database creation and manipulation. "If we crate and manage databases with alembic, alembic but not metadata.create_all() shell be used for tests too".
    • Even if the code above is longer than 4 lines, alembic showed itself as a good controllable beast if driven this way.

提交回复
热议问题