def test_it_does_not_add_duplicate_steps(self, tmpdir): m = read_migrations(tmpdir)[0] m.load() assert len(m.steps) == 1 m = read_migrations(tmpdir)[0] m.load() assert len(m.steps) == 1
def apply_db_migrations(): print("APPLYING DB MIGRATIONS") backend = get_backend(DB_URI) migrations = read_migrations('./migrations') with backend.lock(): # Apply any outstanding migrations backend.apply_migrations(backend.to_apply(migrations))
def apply_migrations(dbconn: sqlite3.Connection) -> None: url = yoyo.connections.parse_uri(f'sqlite:///{app.config["DB_PATH"]}') backend = SQLite3BackendWithConnection(dbconn, url, default_migration_table) migrations = read_migrations('migrations/') with backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
def test_execution_continues_with_ignore_errors_in_transaction(tmpdir): backend = get_backend(dburi) migrations = read_migrations(tmpdir) backend.apply_migrations(migrations) cursor = backend.cursor() cursor.execute("SELECT * FROM yoyo_test") assert cursor.fetchall() == [(2, )]
def test_execution_continues_with_ignore_errors_in_transaction(tmpdir): conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, tmpdir) migrations.apply() cursor = conn.cursor() cursor.execute("SELECT * FROM test") assert cursor.fetchall() == [(2, )]
def setUp(self): self.backend = get_backend(f"sqlite:///{SQLITE_DB_LOCATION}") self.migrations = read_migrations('./migrations') with self.backend.lock(): self.backend.apply_migrations( self.backend.to_apply(self.migrations))
def init_app(): if _config["db_provider"] == 'sqlite': _db.bind(provider='sqlite', filename=_config["db_filename"], create_db=_config["db_create"]) migration_url = 'sqlite:///{}'.format(_config['db_filename']) elif _config["db_provider"] == 'postgres': _db.bind(provider='postgres', user=_config["db_user"], password=_config["db_password"], host=_config["db_host"], database=_config["db_database"]) migration_url = 'postgresql://{}:{}@{}/{}'.format( _config["db_user"], _config["db_password"], _config["db_host"], _config["db_database"]) else: raise ConfigurationException("Database configured improperly") if _config["db_debug"]: orm.set_sql_debug(True) if _config["db_startup"] == 'make_tables': _db.generate_mapping(create_tables=True) elif _config["db_startup"] == 'migrate': backend = yoyo.get_backend(migration_url) migrations = yoyo.read_migrations(_config['db_migrations_dir']) backend.apply_migrations(backend.to_apply(migrations)) _db.generate_mapping(create_tables=False) elif _config["db_startup"] == 'none': _db.generate_mapping(create_tables=False) else: raise ConfigurationException("Database startup configured improperly")
def migrate(db_uri, migrations_path): """ Perform yoyo migrations on the specified database using the specified migrations repository. :param db_uri: The URI path to the SQLite database file. May be any format that can be passed to yoyo.connections.connect. :type db_uri: str :param migrations_path: Filesystem path to directory containing the yoyo migration files. :type migrations_path: str """ parsed_uri = yoyo.connections.parse_uri(db_uri) scheme, _, _, _, _, database, _ = parsed_uri if scheme == 'sqlite': directory = os.path.dirname(database) if not os.path.exists(directory): os.makedirs(directory) try: conn, paramstyle = yoyo.connections.connect(db_uri) except Exception: logging.debug('Failed migration URI: %s', db_uri) raise migrations = yoyo.read_migrations(conn, paramstyle, migrations_path) pending = migrations.to_apply() if len(pending): logging.info('Applying %s migrations to %s' % (len(pending), db_uri)) pending.apply() conn.commit() conn.close()
def apply_migrations(self, migrations_directory: str) -> None: """Run the migrations of the repository schema. Args: migrations_directory: path to the directory containing the migration scripts. """ backend = get_backend(self.database_url) migrations = read_migrations(migrations_directory) with backend.lock(): log.info("Running database migrations") try: backend.apply_migrations(backend.to_apply(migrations)) except Exception as error: # noqa: W0703 # We need to add tests for this function and use a less generic # exception log.error("Error running database migrations") log.error(error) log.debug("Rolling back the database migrations") try: backend.rollback_migrations( backend.to_rollback(migrations)) except Exception as rollback_error: # noqa: W0703 # We need to add tests for this function and use a less generic # exception log.error("Error rolling back database migrations") log.error(rollback_error) raise rollback_error from error log.debug("Complete running database migrations")
def test_apply_migrations_only_does_not_run_hooks(self, tmpdir): backend = get_backend(dburi) backend.apply_migrations_only(backend.to_apply( read_migrations(tmpdir))) cursor = backend.cursor() cursor.execute("SELECT * FROM postapply") assert cursor.fetchall() == []
def run_migrations(db_host, db_port, db_user, db_pass, db_name): connect_str = 'postgresql://'+ db_user +':'+ db_pass +'@'+ db_host + ':' + db_port +'/' + db_name print(connect_str) backend = get_backend(connect_str) migrations = read_migrations('db_migration') backend.apply_migrations(backend.to_apply(migrations))
def __init__(self, *args, **kwargs): """ When a subclass is initiated, the migrations should automatically be run. """ if _DEFAULT in (BACKEND, DATABASE): raise RuntimeError( 'Migration database connection not setup. Need to run `_init_database`' ) # Init parents with additional params we may have received super(Datastore, self).__init__(*args, **kwargs) path = self.MIGRATIONS_PATH if path is _DEFAULT: # `migrations` should be a sub directory of the calling package, unless a path is specified filename = inspect.stack()[1][1] path = os.path.join(os.path.dirname(filename), 'migrations') elif not os.path.isdir(str(path)): raise RuntimeError('The migrations directory does not exist') try: migrations = read_migrations(path) BACKEND.apply_migrations(BACKEND.to_apply(migrations)) except (IOError, OSError): """ If `migrations` directory is not present, then whatever is subclassing us will not have any DB schemas to load. """ pass
def apply_migrations(db_path): connection_string = f'sqlite:///{db_path}' backend = get_backend(connection_string) migrations = read_migrations(str(MIGRATIONS_PATH)) applied = False try: with backend.lock(): # Apply any outstanding migrations to_apply = backend.to_apply(migrations) if to_apply: log.info("Applying migrations:\n%s", pretty_migration_list(to_apply)) backend.apply_migrations(to_apply) log.info("Migrations successfully applied.") else: log.info("All migrations already applied.") applied = True finally: # Rollback all migrations if not applied: rollback = backend.to_rollback(migrations) log.error( "Error while applying migration. " "Rolling back migrations:\n%s", pretty_migration_list(rollback)) backend.rollback_migrations(rollback) raise MigrationError()
def test_rollback_happens_on_step_failure(backend): with migrations_dir(""" step("", "CREATE TABLE yoyo_is_rolledback (i INT)"), step("CREATE TABLE yoyo_test (s VARCHAR(100))", "DROP TABLE yoyo_test") step("invalid sql!")""") as tmpdir: migrations = read_migrations(tmpdir) with pytest.raises(backend.DatabaseError): backend.apply_migrations(migrations) # The yoyo_test table should have either been deleted (transactional ddl) # or dropped (non-transactional-ddl) with pytest.raises(backend.DatabaseError): backend.execute("SELECT * FROM yoyo_test") # Transactional DDL: rollback steps not executed if backend.has_transactional_ddl: with pytest.raises(backend.DatabaseError): backend.execute("SELECT * FROM yoyo_is_rolledback") # Non-transactional DDL: ensure the rollback steps were executed else: cursor = backend.execute("SELECT * FROM yoyo_is_rolledback") assert list(cursor.fetchall()) == []
def __init__(self, *args, **kwargs): """ When a subclass is initiated, the migrations should automatically be run. """ if _DEFAULT in (BACKEND, DATABASE): raise RuntimeError('Migration database connection not setup. Need to run `_init_database`') # Init parents with additional params we may have received super(Datastore, self).__init__(*args, **kwargs) path = self.MIGRATIONS_PATH if path is _DEFAULT: # `migrations` should be a sub directory of the calling package, unless a path is specified filename = inspect.stack()[1][1] path = os.path.join(os.path.dirname(filename), 'migrations') elif not os.path.isdir(str(path)): raise RuntimeError('The migrations directory does not exist') try: migrations = read_migrations(path) BACKEND.apply_migrations(BACKEND.to_apply(migrations)) except (IOError, OSError): """ If `migrations` directory is not present, then whatever is subclassing us will not have any DB schemas to load. """ pass
def migrate(): try: backend = get_backend(URL, '_migrations') migrations = read_migrations('./db/migrations') backend.apply_migrations(backend.to_apply(migrations)) except: print(traceback.format_exc())
def test_specify_migration_table(tmpdir): backend = get_backend(dburi, migration_table="another_migration_table") migrations = read_migrations(tmpdir) backend.apply_migrations(migrations) cursor = backend.cursor() cursor.execute("SELECT migration_id FROM another_migration_table") assert cursor.fetchall() == [("0", )]
def test_migrations_can_import_step_and_group(tmpdir): backend = get_backend(dburi) migrations = read_migrations(tmpdir) backend.apply_migrations(migrations) cursor = backend.cursor() cursor.execute("SELECT id FROM yoyo_test") assert cursor.fetchall() == [(1, )]
def migrate(self) -> DBCreator: logger.debug('migrate') backend = get_backend(self.conn_str) migrations = read_migrations(MIGRATIONS_PATH) with backend.lock(): backend.apply_migrations(backend.to_apply(migrations)) return self
def test_execution_continues_with_ignore_errors_in_transaction(tmpdir): conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, tmpdir) migrations.apply() cursor = conn.cursor() cursor.execute("SELECT * FROM test") assert cursor.fetchall() == [(2,)]
def yoyo_context(db_path): backend_uri = f"sqlite:///{db_path}" migrations_path = Path(__file__).parent / "migrations" backend = get_backend(backend_uri) migrations = read_migrations(str(migrations_path)) log.debug(f"loaded yoyo db context {backend_uri} from {migrations_path}") return backend, migrations
def migration(self): rootLogger.debug("Lancement de la migration yoyo") backend = get_backend( 'mysql://{user}:{password}@{host}/{database}'.format(**BDD_INFO)) migrations = read_migrations('sql') with backend.lock(): backend.apply_migrations(backend.to_apply(migrations)) rootLogger.debug("migration terminée")
def migrate(self): backend = get_backend( f'mysql://{self.MYSQL_USER}:{self.MYSQL_PASSWORD}@{self.MYSQL_HOST}:{self.MYSQL_PORT}/{self.MYSQL_DB}' ) migrations = read_migrations(self.MYSQL_DB_SCRIPT_DIR) with backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
def test_specify_migration_table(tmpdir): conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, tmpdir, migration_table='another_migration_table') migrations.apply() cursor = conn.cursor() cursor.execute("SELECT id FROM another_migration_table") assert cursor.fetchall() == [('0',)]
def _do_migrations(): current_dir = os.path.dirname(__file__) migrations_dir = os.path.join(current_dir, 'migrations') conn = components.get_psql() exceptions.register(DatabaseError) migrations = read_migrations(conn, 'pyformat', migrations_dir) migrations.to_apply().apply() conn.commit()
def test_migration_is_committed(backend): with migrations_dir('step("CREATE TABLE yoyo_test (id INT)")') as tmpdir: migrations = read_migrations(tmpdir) backend.apply_migrations(migrations) backend.rollback() rows = backend.execute("SELECT * FROM yoyo_test").fetchall() assert list(rows) == []
def test_migrations_can_import_step_and_transaction(tmpdir): conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, tmpdir, migration_table='another_migration_table') migrations.apply() cursor = conn.cursor() cursor.execute("SELECT id FROM test") assert cursor.fetchall() == [(1,)]
def test_transaction_is_not_committed_on_error(tmpdir): backend = get_backend(dburi) migrations = read_migrations(tmpdir) with pytest.raises(backend.DatabaseError): backend.apply_migrations(migrations) cursor = backend.cursor() cursor.execute("SELECT count(1) FROM yoyo_test") assert cursor.fetchone() == (0, )
def migrate(): """ apply yoyo migrations """ logger.info("Migrating to the latest schema") log.getLogger('yoyo').setLevel(log.DEBUG) backend = get_backend('sqlite:///' + DB_PATH) migrations = read_migrations('./migrations') with backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
def test_rollbacks_happen_in_reverse(tmpdir): conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, tmpdir) migrations.apply() cursor = conn.cursor() cursor.execute("SELECT * FROM test") assert cursor.fetchall() == [(2,)] migrations.rollback() cursor.execute("SELECT * FROM test") assert cursor.fetchall() == []
def _upgrade_db(self): """upgrade db using scripts for specified (current) schema version""" migration_path = "_data/migrations" sqlite3.connect(self._db_path).close() # ensure that it exists db_url = "sqlite:///" + self._db_path backend = yoyo.get_backend(db_url) migration_dir = pkg_resources.resource_filename(__package__, migration_path) migrations = yoyo.read_migrations(migration_dir) migrations_to_apply = backend.to_apply(migrations) backend.apply_migrations(migrations_to_apply)
def main(): parent_dir = path.dirname(path.abspath(__file__)) with open(f"{parent_dir}/{DB_INFO}", 'r') as configuration_file: config = json.load(configuration_file)["mysql"] backend = get_backend(f'mysql://{config["user"]}:{config["password"]}@{config["host"]}/{config["database"]}') migrations = read_migrations(f"{parent_dir}/{MIGRATIOS_DIR}") with backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
def __apply_migrations(self): """ Create the needed tables to run the application. """ from yoyo import read_migrations from yoyo import get_backend backend = get_backend('sqlite:///' + self.db_file) migrations = read_migrations(self.migrations_dir) with backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
def apply_migrations(self, namespace, migrations_path): migration_table = 'migration_%s' % escape_for_sql_identifier(namespace) migrations = yoyo.read_migrations(self.db, sqlite3.paramstyle, migrations_path, migration_table=migration_table) to_apply = migrations.to_apply() log.info('Found %i migrations for %s, applying %i', len(migrations), namespace, len(to_apply)) to_apply.apply() self.db.commit()
def test_migration_functions_have_namespace_access(tmpdir): """ Test that functions called via step have access to the script namespace """ backend = get_backend(dburi) migrations = read_migrations(tmpdir) backend.apply_migrations(migrations) cursor = backend.cursor() cursor.execute("SELECT id FROM foo_test") assert cursor.fetchall() == [(1, )]
async def initialize(config=None, callback=None): async with aiopg.sa.create_engine(user=config['db_user'], database=config['db_database'], host=config['db_host'], password=config['db_pass']) as engine: ## Run Migrations log.info("Running Migrations") backend = get_backend('postgres://{}:{}@{}/{}'.format( config['db_user'], config['db_pass'], config['db_host'], config['db_database'])) if os.path.isdir('./migrations'): migrations = read_migrations('./migrations') else: migrations = read_migrations('/usr/lib/pygmalion/migrations') backend.apply_migrations(backend.to_apply(migrations)) if callback: await callback(engine=engine, config=config)
def test_rollbacks_happen_in_reverse(tmpdir): backend = get_backend(dburi) migrations = read_migrations(tmpdir) backend.apply_migrations(migrations) cursor = backend.cursor() cursor.execute("SELECT * FROM yoyo_test") assert cursor.fetchall() == [(2, )] backend.rollback_migrations(migrations) cursor.execute("SELECT * FROM yoyo_test") assert cursor.fetchall() == []
def test_migration_functions_have_namespace_access(tmpdir): """ Test that functions called via step have access to the script namespace """ conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, tmpdir, migration_table='another_migration_table') migrations.apply() cursor = conn.cursor() cursor.execute("SELECT id FROM foo_test") assert cursor.fetchall() == [(1,)]
def init_migrations(rollback=False): """Run migrations Also rollback if the rollback parameter is True (useful for testing migrations), but kinda dangerous for production though.""" backend = get_backend( 'postgres://{user}:{password}@{host}/postgres'.format(**DBARGS)) migrations = read_migrations('src/migrations') if rollback: backend.rollback_migrations(backend.to_rollback(migrations)) backend.apply_migrations(backend.to_apply(migrations))
def migrate(self, path=None): if path is None: # `migrations` should be a sub directory of the calling package, unless a path is specified filename = inspect.stack()[1][1] path = os.path.join(os.path.dirname(filename), 'migrations') elif not os.path.isdir(str(path)): raise RuntimeError('The migrations directory does not exist') try: migrations = read_migrations(path) self.backend.apply_migrations(self.backend.to_apply(migrations)) except (IOError, OSError): """
def test_transaction_is_not_committed_on_error(tmpdir): conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, tmpdir) try: migrations.apply() except DatabaseError: # Expected pass else: raise AssertionError("Expected a DatabaseError") cursor = conn.cursor() cursor.execute("SELECT count(1) FROM test") assert cursor.fetchone() == (0,)
def migrate(self, path=None): if path is None: # `migrations` should be a sub directory of the calling package, unless a path is specified filename = inspect.stack()[1][1] path = os.path.join(os.path.dirname(filename), 'migrations') elif not os.path.isdir(str(path)): raise RuntimeError('The migrations directory does not exist') try: migrations = read_migrations(path) self.backend.apply_migrations(self.backend.to_apply(migrations)) except (IOError, OSError): """ If `migrations` directory is not present, then whatever is subclassing us will not have any DB schemas to load. """ pass
def __init__(self): """ When a subclass is initiated, the migrations should automatically be run. """ path = self.MIGRATIONS_PATH if path is _DEFAULT: # `migrations` should be a sub directory of the calling package, unless a path is specified filename = inspect.stack()[1][1] path = os.path.join(os.path.dirname(filename), 'migrations') elif not os.path.isdir(str(path)): raise RuntimeError('The migrations directory does not exist') backend = self.database.backend with backend.connection as conn: migrations = read_migrations(path) backend.apply_migrations(backend.to_apply(migrations))
def _migrate_database(self): db_config = { 'host':'localhost', 'user':'******', 'passwd':'', 'name':'vilya-test'} db_config.update(self.app.config['DATABASE']) migrations_dir = self.app.config['MIGRATIONS_DIR'] if db_config['passwd']: db_config['user'] += ':' + db_config['passwd'] if db_config.get('port'): db_config['host'] += ':' + db_config['port'] db_connection_url = "mysql://{user}@{host}/{name}".format(**db_config) connection, paramstyle = connect(db_connection_url) migrations = yoyo.read_migrations(connection, paramstyle, migrations_dir) migrations.to_apply().apply() connection.commit() self.migrate_info = (connection, paramstyle, migrations_dir)
import settings import cloudmanager.migrations import yoyo import yoyo.connections if __name__ == '__main__': conn, paramstyle = yoyo.connections.connect(settings.DATABASE_PATH) migrations = yoyo.read_migrations(conn, paramstyle, cloudmanager.migrations.path()) migrations.to_apply().apply() conn.commit()
cur.execute("SELECT NULL::point") point_oid = cur.description[0][1] finally: pool.putconn(conn) Point = psycopg2.extensions.new_type((point_oid,), "Point", dao.cast_point) psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(Point) psycopg2.extensions.register_adapter(dao.Point, dao.adapt_point) migrations_dir = os.path.join(os.path.dirname(__file__), 'migrations') conn = pool.getconn() yoyo.exceptions.register(psycopg2.DatabaseError) migrations = read_migrations(conn, psycopg2.paramstyle, migrations_dir) migrations.to_apply().apply() conn.commit() pool.putconn(conn) summits_images_dao = dao.SummitsImagesDao(pool) summits_dao = dao.SummitsDao(pool, summits_images_dao) users_dao = dao.UsersDao(pool) ridges_dao = dao.RidgesDao(pool, summits_dao) if app.config['IMAGES_BACKEND'] == 'filesystem': images_dao = dao.FilesystemImagesDao(app.config['IMAGES_DIR']) else: images_dao = dao.DatabaseImagesDao(pool) climbs_dao = dao.ClimbsDao(pool)
def main(argv=None): argparser = make_argparser() args = argparser.parse_args(argv) if args.verbosity_level: verbosity_level = args.verbosity_level else: verbosity_level = args.verbose verbosity_level = min(verbosity_level, max(verbosity_levels)) verbosity_level = max(verbosity_level, min(verbosity_levels)) configure_logging(verbosity_level) command = args.command migrations_dir = os.path.normpath(os.path.abspath(args.migrations_dir)) dburi = args.database config_path = os.path.join(migrations_dir, '.yoyo-migrate') config = readconfig(config_path) if dburi is None and args.cache: try: logger.debug("Looking up connection string for %r", migrations_dir) dburi = config.get('DEFAULT', 'dburi') except (ValueError, NoSectionError, NoOptionError): pass if args.migration_table: migration_table = args.migration_table else: try: migration_table = config.get('DEFAULT', 'migration_table') except (ValueError, NoSectionError, NoOptionError): migration_table = None # Earlier versions had a bug where the migration_table could be set to the # string 'None'. if migration_table in (None, 'None'): migration_table = default_migration_table config.set('DEFAULT', 'migration_table', migration_table) if dburi is None: argparser.error( "Please specify command, migrations directory and " "database connection string arguments" ) if args.prompt_password: password = getpass('Password for %s: ' % dburi) scheme, username, _, host, port, database, db_params = parse_uri(dburi) dburi = unparse_uri((scheme, username, password, host, port, database, db_params)) # Cache the database this migration set is applied to so that subsequent # runs don't need the dburi argument. Don't cache anything in batch mode - # we can't prompt to find the user's preference. if args.cache and not args.batch: if not config.has_option('DEFAULT', 'dburi'): response = prompt( "Save connection string to %s for future migrations?\n" "This is saved in plain text and " "contains your database password." % (config_path,), "yn" ) if response == 'y': config.set('DEFAULT', 'dburi', dburi) elif config.get('DEFAULT', 'dburi') != dburi: response = prompt( "Specified connection string differs from that saved in %s. " "Update saved connection string?" % (config_path,), "yn" ) if response == 'y': config.set('DEFAULT', 'dburi', dburi) config.set('DEFAULT', 'migration_table', migration_table) saveconfig(config, config_path) conn, paramstyle = connect(dburi) migrations = read_migrations(conn, paramstyle, migrations_dir, migration_table=migration_table) if args.match: migrations = migrations.filter( lambda m: re.search(args.match, m.id) is not None) if not args.all: if command in ['apply']: migrations = migrations.to_apply() elif command in ['reapply', 'rollback']: migrations = migrations.to_rollback() if not args.batch: migrations = prompt_migrations(conn, paramstyle, migrations, command) if not args.batch and migrations: if prompt(command.title() + plural(len(migrations), " %d migration", " %d migrations") + " to %s?" % dburi, "Yn") != 'y': return 0 if command == 'reapply': migrations.rollback(args.force) migrations.apply(args.force) elif command == 'apply': migrations.apply(args.force) elif command == 'rollback': migrations.rollback(args.force)
def _rollback_database(self): connection, paramstyle, migrations_dir = self.migrate_info migrations = yoyo.read_migrations(connection, paramstyle, migrations_dir) migrations.to_rollback().rollback() connection.commit()
def apply_db_migrations(gocd_dash_path, db_port): conn_str = 'postgresql://*****:*****@dev.localhost:{}/go-analysis'.format(db_port) _wait_for_db_to_accept_connections(conn_str) backend = get_backend(conn_str) migrations = read_migrations(gocd_dash_path + '/migrations') backend.apply_migrations(backend.to_apply(migrations))
def get_db_migrations(self): backend = get_backend(self.db) migrations = read_migrations(self.migration_directory) return backend, migrations
def main(): backend = get_backend(env.DATABASE_URI) migrations = read_migrations(os.path.join(env.APP_ROOT, "schema/db")) backend.apply_migrations(migrations)
def migrations(self): migrations = yoyo.read_migrations( self.connection, self.paramstyle, self.migrations_dir) return migrations
def apply_migrations(self, file_path, migrations_path): backend = yoyo.get_backend('sqlite:///' + file_path) migrations = yoyo.read_migrations(migrations_path) with backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
def main(): conn, paramstyle = connect(env.DATABASE_URI) schema_path = os.path.join(env.APP_ROOT, "schema/db") migrations = read_migrations(conn, paramstyle, schema_path) migrations.to_apply().apply() conn.commit()