Source code for aiida.storage.psql_dos.alembic_cli

#!/usr/bin/env python
###########################################################################
# Copyright (c), The AiiDA team. All rights reserved.                     #
# This file is part of the AiiDA code.                                    #
#                                                                         #
# The code is hosted on GitHub at https://github.com/aiidateam/aiida-core #
# For further information on the license, see the LICENSE.txt file        #
# For further information please visit http://www.aiida.net               #
###########################################################################
"""Simple wrapper around the alembic command line tool that first loads an AiiDA profile."""

from __future__ import annotations

import contextlib

import alembic
import click

from aiida.cmdline import is_verbose
from aiida.cmdline.groups.verdi import VerdiCommandGroup
from aiida.cmdline.params import options
from aiida.manage.configuration import Profile
from aiida.storage.psql_dos.migrator import PsqlDosMigrator


[docs] class AlembicRunner: """Wrapper around the alembic command line tool that first loads an AiiDA profile."""
[docs] def __init__(self) -> None: self.profile: Profile | None = None
[docs] def execute_alembic_command(self, command_name, connect=True, **kwargs): """Execute an Alembic CLI command. :param command_name: the sub command name :param kwargs: parameters to pass to the command """ if self.profile is None: raise click.ClickException('No profile specified') migrator = PsqlDosMigrator(self.profile) context = migrator._alembic_connect() if connect else contextlib.nullcontext(migrator._alembic_config()) with context as config: command = getattr(alembic.command, command_name) config.stdout = click.get_text_stream('stdout') command(config, **kwargs)
pass_runner = click.make_pass_decorator(AlembicRunner, ensure=True) @click.group(cls=VerdiCommandGroup) @options.PROFILE(required=True) @pass_runner def alembic_cli(runner, profile): """Simple wrapper around the alembic command line tool that first loads an AiiDA profile.""" runner.profile = profile @alembic_cli.command('revision') @click.argument('message') @pass_runner def alembic_revision(runner, message): """Create a new database revision.""" # to-do this does not currently work, because `alembic.RevisionContext._run_environment` has issues with heads # (it works if we comment out the initial autogenerate check) runner.execute_alembic_command('revision', message=message, autogenerate=True, head='main@head') @alembic_cli.command('current') @options.VERBOSITY() @pass_runner def alembic_current(runner): """Show the current revision.""" runner.execute_alembic_command('current', verbose=is_verbose()) @alembic_cli.command('history') @click.option('-r', '--rev-range') @options.VERBOSITY() @pass_runner def alembic_history(runner, rev_range): """Show the history for the given revision range.""" runner.execute_alembic_command('history', connect=False, rev_range=rev_range, verbose=is_verbose()) @alembic_cli.command('show') @click.argument('revision', type=click.STRING) @pass_runner def alembic_show(runner, revision): """Show details of the given REVISION.""" runner.execute_alembic_command('show', rev=revision) @alembic_cli.command('upgrade') @click.argument('revision', type=click.STRING) @pass_runner def alembic_upgrade(runner, revision): """Upgrade the database to the given REVISION.""" runner.execute_alembic_command('upgrade', revision=revision) @alembic_cli.command('downgrade') @click.argument('revision', type=click.STRING) @pass_runner def alembic_downgrade(runner, revision): """Downgrade the database to the given REVISION.""" runner.execute_alembic_command('downgrade', revision=revision) if __name__ == '__main__': alembic_cli()