def test_multiple_dir_no_bases(self): assert_raises_message( util.CommandError, "Multiple version locations present, please specify " "--version-path", command.revision, self.cfg, message="some message" )
def test_create_index_no_expr_allowed(self): op_fixture() assert_raises_message( ValueError, "String or text\(\) construct expected", op.create_index, 'name', 'tname', [func.foo(column('x'))] )
def test_nonsensical_sql_mode_autogen(self): self._env_fixture() assert_raises_message( util.CommandError, "Using --sql with --autogenerate does not make any sense", command.revision, self.cfg, autogenerate=True, sql=True )
def test_create_script_branches_old_template(self): script = ScriptDirectory.from_config(self.cfg) with open(os.path.join(script.dir, "script.py.mako"), "w") as file_: file_.write( "<%text>#</%text> ${message}\n" "revision = ${repr(up_revision)}\n" "down_revision = ${repr(down_revision)}\n" "def upgrade():\n" " ${upgrades if upgrades else 'pass'}\n\n" "def downgrade():\n" " ${downgrade if downgrades else 'pass'}\n\n" ) # works OK if no branch names command.revision(self.cfg, message="some message") assert_raises_message( util.CommandError, r"Version \w+ specified branch_labels foobar, " r"however the migration file .+?\b does not have them; have you " "upgraded your script.py.mako to include the 'branch_labels' " r"section\?", command.revision, self.cfg, message="some message", branch_label="foobar" )
def test_upgrade_downgrade_ops_list_accessors(self): u1 = ops.UpgradeOps(ops=[]) d1 = ops.DowngradeOps(ops=[]) m1 = ops.MigrationScript( "somerev", u1, d1 ) is_( m1.upgrade_ops, u1 ) is_( m1.downgrade_ops, d1 ) u2 = ops.UpgradeOps(ops=[]) d2 = ops.DowngradeOps(ops=[]) m1._upgrade_ops.append(u2) m1._downgrade_ops.append(d2) assert_raises_message( ValueError, "This MigrationScript instance has a multiple-entry list for " "UpgradeOps; please use the upgrade_ops_list attribute.", getattr, m1, "upgrade_ops" ) assert_raises_message( ValueError, "This MigrationScript instance has a multiple-entry list for " "DowngradeOps; please use the downgrade_ops_list attribute.", getattr, m1, "downgrade_ops" ) eq_(m1.upgrade_ops_list, [u1, u2]) eq_(m1.downgrade_ops_list, [d1, d2])
def test_failure_message(self): iter_ = self.map.iterate_revisions("c1", "base1") assert_raises_message( RevisionError, "Dependency resolution failed;", list, iter_ )
def test_same_branch_wrong_direction(self): assert_raises_message( RevisionError, r"Revision d2 is not an ancestor of revision b2", list, self.map._iterate_revisions('b2', 'd2') )
def test_drop_check(self): op_fixture('mysql') assert_raises_message( NotImplementedError, "MySQL does not support CHECK constraints.", op.drop_constraint, "f1", "t1", "check" )
def test_no_script_error(self): cfg = config.Config() assert_raises_message( util.CommandError, "No 'script_location' key found in configuration.", ScriptDirectory.from_config, cfg )
def test_drop_constraint_not_available(self): op = ops.DropConstraintOp('x', 'y', type_='unique') assert_raises_message( ValueError, "constraint cannot be produced", op.to_constraint )
def test_col_alter_type_required(self): op_fixture('mysql') assert_raises_message( util.CommandError, "MySQL CHANGE/MODIFY COLUMN operations require the existing type.", op.alter_column, 't1', 'c1', nullable=False, server_default="q" )
def test_detect_invalid_base_selection(self): assert_raises_message( RevisionError, "Requested revision a2 overlaps with " "other requested revisions", list, self.map._iterate_revisions(["c2"], ["a2", "b2"]), )
def test_no_revision_exists(self): assert_raises_message( RevisionError, "No such revision or branch 'q'", self.map.get_revision, "abranch@q", )
def test_error_on_new_with_missing_revision(self): self.cfg.set_main_option("file_template", "%%(slug)s_%%(rev)s") script = ScriptDirectory.from_config(self.cfg) a = util.rev_id() script.generate_revision(a, "foobar", refresh=True) path = script.get_revision(a).path with open(path, 'w') as fp: fp.write(""" down_revision = None from alembic import op def upgrade(): op.execute("CREATE TABLE foo(id integer)") def downgrade(): op.execute("DROP TABLE foo") """) pyc_path = util.pyc_file_from_path(path) if os.access(pyc_path, os.F_OK): os.unlink(pyc_path) assert_raises_message( util.CommandError, "Could not determine revision id from filename foobar_%s.py. " "Be sure the 'revision' variable is declared " "inside the script." % a, Script._from_path, script, path)
def test_raise_on_dupe(self): m1a = MetaData() m1b = MetaData() m2a = MetaData() m2b = MetaData() Table("a", m1a, Column("id", Integer, primary_key=True)) Table("b1", m1b, Column("id", Integer, primary_key=True)) Table("b2", m1b, Column("id", Integer, primary_key=True)) Table("b3", m1b, Column("id", Integer, primary_key=True)) Table("a", m2a, Column("id", Integer, primary_key=True)) Table("a", m2b, Column("id", Integer, primary_key=True)) Table("b1", m2b, Column("id", Integer, primary_key=True)) Table("b2", m2a, Column("id", Integer, primary_key=True)) Table("b2", m2b, Column("id", Integer, primary_key=True)) assert_raises_message( ValueError, 'Duplicate table keys across multiple MetaData objects: "a", "b2"', self._fixture, [m1a, m1b], [m2a, m2b], )
def test_multiple_dir_no_bases_invalid_version_path(self): assert_raises_message( util.CommandError, "Path foo/bar/ is not represented in current version locations", command.revision, self.cfg, message="x", version_path=os.path.join("foo/bar/") )
def test_invalid_move_rev_to_none(self): a, b, c, d, e = self.a, self.b, self.c, self.d, self.e assert_raises_message( util.CommandError, r"Destination %s is not a valid downgrade " "target from current head\(s\)" % b.revision[0:3], self.env._downgrade_revs, b.revision[0:3], None )
def test_starting_rev_pre_context_cmd_w_no_startrev(self): env_file_fixture(""" assert context.get_starting_revision_argument() == 'x' """) assert_raises_message( util.CommandError, "No starting revision argument is available.", command.current, self.cfg)
def test_create_rev_invalid_depends_on(self): self._env_fixture() command.revision(self.cfg) assert_raises_message( util.CommandError, "Can't locate revision identified by 'invalid'", command.revision, self.cfg, depends_on='invalid' )
def test_edit_no_current(self): assert_raises_message( util.CommandError, "No current revisions", command.edit, self.cfg, "current", )
def test_invalid_move_higher_to_lower(self): assert_raises_message( util.CommandError, r"Destination %s is not a valid downgrade " "target from current head\(s\)" % self.c.revision[0:4], self.env._downgrade_revs, self.c.revision[0:4], self.b.revision )
def test_nonsensical_sql_no_env(self): self._env_fixture() assert_raises_message( util.CommandError, "Using --sql with the revision command when revision_environment " "is not configured does not make any sense", command.revision, self.cfg, sql=True )
def test_drop_unknown(self): op_fixture('mysql') assert_raises_message( TypeError, "'type' can be one of 'check', 'foreignkey', " "'primary', 'unique', None", op.drop_constraint, "f1", "t1", "typo" )
def test_drop_generic_constraint(self): op_fixture('mysql') assert_raises_message( NotImplementedError, "No generic 'DROP CONSTRAINT' in MySQL - please " "specify constraint type", op.drop_constraint, "f1", "t1" )
def test_distinct_branches(self): # nodes db2cb2 and b1 have no path to each other assert_raises_message( RevisionError, r"Revision b1 is not an ancestor of revision d2cb2", list, self.map._iterate_revisions('d2cb2', 'b1') )
def test_edit_no_revs(self): assert_raises_message( util.CommandError, "No revision files indicated by symbol 'base'", command.edit, self.cfg, "base", )
def test_create_script_missing_splice(self): assert_raises_message( util.CommandError, "Revision %s is not a head revision; please specify --splice " "to create a new branch from this revision" % self.b, command.revision, self.cfg, message="some message", head=self.b )
def test_create_rev_autogen_db_not_up_to_date(self): self._env_fixture() assert command.revision(self.cfg) assert_raises_message( util.CommandError, "Target database is not up to date.", command.revision, self.cfg, autogenerate=True )
def test_edit_with_missing_editor(self): with mock.patch('editor.edit') as edit_mock: edit_mock.side_effect = OSError("file not found") assert_raises_message( util.CommandError, 'file not found', util.edit, "/not/a/file.txt")
def test_update_no_match(self): self.updater.update_to_step(_up(None, 'a', True)) self.updater.heads.add('x') assert_raises_message( CommandError, "Online migration expected to match one row when updating " "'x' to 'b' in 'version_table'; 0 found", self.updater.update_to_step, _up('x', 'b') )
def test_nonsensical_sql_no_env(self): self._env_fixture() assert_raises_message( util.CommandError, "Using --sql with the revision command when revision_environment " "is not configured does not make any sense", command.revision, self.cfg, sql=True)
def test_drop_explicit_constraint(self): op_fixture("sqlite") assert_raises_message( NotImplementedError, "No support for ALTER of constraints in SQLite dialect", op.drop_constraint, "foo", "sometable", )
def test_wrong_direction_to_base_as_empty(self): # this needs to raise and not just return empty iteration # as added by #258 assert_raises_message( RevisionError, r"Revision d1cb1 is not an ancestor of revision base", list, self.map._iterate_revisions((), "d1cb1"), )
def test_edit_with_missing_editor(self): with mock.patch("editor.edit") as edit_mock: edit_mock.side_effect = OSError("file not found") assert_raises_message( util.CommandError, "file not found", util.edit, "/not/a/file.txt", )
def test_partial_id_resolve_too_short(self): assert_raises_message( RevisionError, "No such revision or branch 'sos'; please ensure at least " "four characters are present for partial revision identifier " "matches", self.map.get_revision, "ebranch@sos", )
def test_same_branch_wrong_direction(self): # nodes b1 and d1cb1 are connected, but # db1cb1 is the descendant of b1 assert_raises_message( RevisionError, r"Revision d1cb1 is not an ancestor of revision b1", list, self.map._iterate_revisions("b1", "d1cb1"), )
def test_nonsensical_sql_mode_autogen(self): self._env_fixture() assert_raises_message( util.CommandError, "Using --sql with --autogenerate does not make any sense", command.revision, self.cfg, autogenerate=True, sql=True)
def test_detect_invalid_head_selection(self): # db1 is an ancestor of fe1b1 assert_raises_message( RevisionError, "Requested revision fe1b1 overlaps " "with other requested revisions", list, self.map._iterate_revisions(["db1", "b2", "fe1b1"], ()), )
def test_compare_metadata_as_sql(self): context = MigrationContext.configure(connection=self.bind.connect(), opts={'as_sql': True}) metadata = self.m2 assert_raises_message( CommandError, "autogenerate can't use as_sql=True as it prevents " "querying the database for schema information", autogenerate.compare_metadata, context, metadata)
def test_update_no_match(self): self.updater.update_to_step(_up(None, "a", True)) self.updater.heads.add("x") assert_raises_message( CommandError, "Online migration expected to match one row when updating " "'x' to 'b' in 'version_table'; 0 found", self.updater.update_to_step, _up("x", "b"), )
def test_create_index_no_expr_allowed(self): op_fixture() assert_raises_message( ValueError, r"String or text\(\) construct expected", op.create_index, "name", "tname", [func.foo(column("x"))], )
def test_different_branch_not_wrong_direction(self): # Changed from empty list. Expect this should raise an error in # --sql mode (since there is not a direct path), or in upgrade mode # it should return revision b3, not an empty list. assert_raises_message( RevisionError, r"Revision d2 is not an ancestor of revision b3", list, self.map.iterate_revisions("b3", "d2"), )
def test_invalid_move_higher_to_lower(self): assert_raises_message( util.CommandError, r"Destination %s is not a valid downgrade " r"target from current head\(s\)" % self.c.revision[0:4], self.env._downgrade_revs, self.c.revision[0:4], self.b.revision, )
def test_update_multi_match(self): self.connection.execute(version_table.insert(), version_num='a') self.connection.execute(version_table.insert(), version_num='a') self.updater.heads.add('a') assert_raises_message( CommandError, "Online migration expected to match one row when updating " "'a' to 'b' in 'version_table'; 2 found", self.updater.update_to_step, _up('a', 'b'))
def test_alter_column_nullable_type_required(self): context = op_fixture('mssql') assert_raises_message(util.CommandError, "MS-SQL ALTER COLUMN operations with NULL or " "NOT NULL require the existing_type or a new " "type_ be passed.", op.alter_column, "t", "c", nullable=False)
def test_stamp_purge_no_sql(self): assert_raises_message( util.CommandError, "Can't use --purge with --sql mode", command.stamp, self.cfg, [self.c], sql=True, purge=True, )
def test_col_alter_type_required(self): op_fixture('mysql') assert_raises_message( util.CommandError, "MySQL CHANGE/MODIFY COLUMN operations require the existing type.", op.alter_column, 't1', 'c1', nullable=False, server_default="q")
def test_create_rev_invalid_depends_on(self): self._env_fixture() command.revision(self.cfg) assert_raises_message( util.CommandError, "Can't locate revision identified by 'invalid'", command.revision, self.cfg, depends_on="invalid", )
def test_sql_stamp_different_multi_start(self): assert_raises_message( util.CommandError, "Stamp operation with --sql only supports a single " "starting revision at a time", command.stamp, self.cfg, ["%s:%s" % (self.b, self.c), "%s:%s" % (self.a, self.e)], sql=True, )
def test_downgrade_wo_colon(self): env_file_fixture(""" context.configure(dialect_name='sqlite') """) assert_raises_message( util.CommandError, "downgrade with --sql requires <fromrev>:<torev>", command.downgrade, self.cfg, b, sql=True )
def test_create_rev_autogen_db_not_up_to_date(self): self._env_fixture() assert command.revision(self.cfg) assert_raises_message( util.CommandError, "Target database is not up to date.", command.revision, self.cfg, autogenerate=True, )
def test_add_explicit_constraint(self): op_fixture("sqlite") assert_raises_message( NotImplementedError, "No support for ALTER of constraints in SQLite dialect", op.create_check_constraint, "foo", "sometable", column("name") > 5, )
def test_delete_no_match(self): self.updater.update_to_step(_up(None, 'a', True)) self.updater.heads.add('x') assert_raises_message( CommandError, "Online migration expected to match one row when " "deleting 'x' in 'version_table'; 0 found", self.updater.update_to_step, _down('x', None, True) )
def test_create_script_missing_splice(self): assert_raises_message( util.CommandError, "Revision %s is not a head revision; please specify --splice " "to create a new branch from this revision" % self.b, command.revision, self.cfg, message="some message", head=self.b, )
def test_wrong_direction_to_base(self): assert_raises_message( RevisionError, r"Revision d1cb1 is not an ancestor of revision base", list, self.map._iterate_revisions(None, 'd1cb1')) assert_raises_message( RevisionError, r"Revision d1cb1 is not an ancestor of revision base", list, self.map._iterate_revisions((), 'd1cb1'))
def test_drop_generic_constraint(self): op_fixture("mysql") assert_raises_message( NotImplementedError, "No generic 'DROP CONSTRAINT' in MySQL - please " "specify constraint type", op.drop_constraint, "f1", "t1", )
def test_cant_op(self): if hasattr(op, '_proxy'): del op._proxy assert_raises_message( NameError, "Can't invoke function 'inline_literal', as the " "proxy object has not yet been established " "for the Alembic 'Operations' class. " "Try placing this code inside a callable.", op.inline_literal, "asdf" )
def test_drop_unknown(self): op_fixture("mysql") assert_raises_message( TypeError, "'type' can be one of 'check', 'foreignkey', " "'primary', 'unique', None", op.drop_constraint, "f1", "t1", "typo", )
def test_invalid_relative_upgrade_path(self): assert_raises_message( util.CommandError, "Relative revision -2 didn't produce 2 migrations", self.env._upgrade_revs, "-2", self.b.revision) assert_raises_message( util.CommandError, r"Relative revision \+5 didn't produce 5 migrations", self.env._upgrade_revs, "+5", self.b.revision)
def test_delete_multi_match(self): self.connection.execute(version_table.insert(), version_num='a') self.connection.execute(version_table.insert(), version_num='a') self.updater.heads.add('a') assert_raises_message( CommandError, "Online migration expected to match one row when " "deleting 'a' in 'version_table'; 2 found", self.updater.update_to_step, _down('a', None, True) )