diff options
-rw-r--r-- | migrate/changeset/__init__.py | 3 | ||||
-rw-r--r-- | migrate/changeset/databases/ibmdb2.py | 13 | ||||
-rw-r--r-- | migrate/tests/versioning/test_cfgparse.py | 2 | ||||
-rw-r--r-- | migrate/tests/versioning/test_repository.py | 2 | ||||
-rw-r--r-- | migrate/tests/versioning/test_script.py | 22 | ||||
-rw-r--r-- | migrate/tests/versioning/test_shell.py | 3 | ||||
-rw-r--r-- | migrate/versioning/script/sql.py | 19 | ||||
-rw-r--r-- | migrate/versioning/templates/manage/default.py_tmpl | 1 | ||||
-rw-r--r-- | migrate/versioning/templates/manage/pylons.py_tmpl | 1 | ||||
-rw-r--r-- | setup.cfg | 3 | ||||
-rw-r--r-- | tox.ini | 52 |
11 files changed, 101 insertions, 20 deletions
diff --git a/migrate/changeset/__init__.py b/migrate/changeset/__init__.py index 256d704..7eb256a 100644 --- a/migrate/changeset/__init__.py +++ b/migrate/changeset/__init__.py @@ -5,13 +5,10 @@ .. [#] SQL Data Definition Language """ import re -import warnings import sqlalchemy from sqlalchemy import __version__ as _sa_version -warnings.simplefilter('always', DeprecationWarning) - _sa_version = tuple(int(re.match("\d+", x).group(0)) for x in _sa_version.split(".")) SQLA_07 = _sa_version >= (0, 7) SQLA_08 = _sa_version >= (0, 8) diff --git a/migrate/changeset/databases/ibmdb2.py b/migrate/changeset/databases/ibmdb2.py index fe28512..7b6a3a1 100644 --- a/migrate/changeset/databases/ibmdb2.py +++ b/migrate/changeset/databases/ibmdb2.py @@ -14,6 +14,7 @@ from sqlalchemy.schema import (Index, from migrate.changeset import ansisql from migrate.changeset import constraint +from migrate.changeset import util from migrate import exceptions @@ -107,7 +108,8 @@ class IBMDBSchemaChanger(IBMDBSchemaGenerator, ansisql.ANSISchemaChanger): """Rename a table; #38. Other ops aren't supported.""" self._rename_table(table) - self.append("TO %s" % self.preparer.quote(table.new_name, table.quote)) + q = util.safe_quote(table) + self.append("TO %s" % self.preparer.quote(table.new_name, q)) self.execute() self.append("COMMIT") self.execute() @@ -128,10 +130,11 @@ class IBMDBSchemaChanger(IBMDBSchemaGenerator, ansisql.ANSISchemaChanger): def _run_subvisit(self, delta, func, start_alter=True): """Runs visit method based on what needs to be changed on column""" table = delta.table + q = util.safe_quote(table) if start_alter: self.start_alter_table(table) ret = func(table, - self.preparer.quote(delta.current_name, delta.quote), + self.preparer.quote(delta.current_name, q), delta) self.execute() self._reorg_table(self.preparer.format_table(delta.table)) @@ -262,13 +265,13 @@ class IBMDBConstraintGenerator(ansisql.ANSIConstraintGenerator): if (isinstance(constraint, UniqueConstraint) and is_unique_constraint_with_null_columns_supported( self.dialect)): - for column in constraint.columns._all_cols: + for column in constraint: if column.nullable: constraint.exclude_nulls = True break if getattr(constraint, 'exclude_nulls', None): index = Index(constraint.name, - *(column for column in constraint.columns._all_cols), + *(column for column in constraint), unique=True) sql = self.process(CreateIndex(index)) sql += ' EXCLUDE NULL KEYS' @@ -285,7 +288,7 @@ class IBMDBConstraintDropper(ansisql.ANSIConstraintDropper, if (isinstance(constraint, UniqueConstraint) and is_unique_constraint_with_null_columns_supported( self.dialect)): - for column in constraint.columns._all_cols: + for column in constraint: if column.nullable: constraint.exclude_nulls = True break diff --git a/migrate/tests/versioning/test_cfgparse.py b/migrate/tests/versioning/test_cfgparse.py index 39649cc..a31273e 100644 --- a/migrate/tests/versioning/test_cfgparse.py +++ b/migrate/tests/versioning/test_cfgparse.py @@ -24,4 +24,4 @@ class TestConfigParser(fixture.Base): 'repository_name', {}) specified_text = Repository.prepare_config(Template().get_repository(), 'repository_name', {'version_table': '_other_table'}) - self.assertNotEquals(default_text, specified_text) + self.assertNotEqual(default_text, specified_text) diff --git a/migrate/tests/versioning/test_repository.py b/migrate/tests/versioning/test_repository.py index 6845a0e..6e87c02 100644 --- a/migrate/tests/versioning/test_repository.py +++ b/migrate/tests/versioning/test_repository.py @@ -44,7 +44,7 @@ class TestRepository(fixture.Pathed): self.assertTrue(repos.config.get('db_settings', 'version_table')) # version_table's default isn't none - self.assertNotEquals(repos.config.get('db_settings', 'version_table'), 'None') + self.assertNotEqual(repos.config.get('db_settings', 'version_table'), 'None') def test_load_notfound(self): """Nonexistant repositories shouldn't be loaded""" diff --git a/migrate/tests/versioning/test_script.py b/migrate/tests/versioning/test_script.py index c26b03b..954bc0d 100644 --- a/migrate/tests/versioning/test_script.py +++ b/migrate/tests/versioning/test_script.py @@ -271,3 +271,25 @@ class TestSqlScript(fixture.Pathed, fixture.DB): sqls = SqlScript(src) sqls.run(self.engine) tmp_sql_table.metadata.drop_all(self.engine, checkfirst=True) + + @fixture.usedb() + def test_transaction_management_statements(self): + """ + Test that we can successfully execute SQL scripts with transaction + management statements. + """ + for script_pattern in ( + "BEGIN TRANSACTION; %s; COMMIT;", + "BEGIN; %s; END TRANSACTION;", + ): + + test_statement = ("CREATE TABLE TEST1 (field1 int); " + "DROP TABLE TEST1") + script = script_pattern % test_statement + src = self.tmp() + + with open(src, 'wt') as f: + f.write(script) + + sqls = SqlScript(src) + sqls.run(self.engine) diff --git a/migrate/tests/versioning/test_shell.py b/migrate/tests/versioning/test_shell.py index 62dc8e0..173e30e 100644 --- a/migrate/tests/versioning/test_shell.py +++ b/migrate/tests/versioning/test_shell.py @@ -101,7 +101,7 @@ class TestShellCommands(Shell): # The default table should not be None repos_ = Repository(repos) - self.assertNotEquals(repos_.config.get('db_settings', 'version_table'), 'None') + self.assertNotEqual(repos_.config.get('db_settings', 'version_table'), 'None') # Can't create it again: it already exists result = self.env.run('migrate create %s repository_name' % repos, @@ -485,7 +485,6 @@ class TestShellDatabase(Shell, DB): result = self.env.run('migrate compare_model_to_db %s %s --model=%s' \ % (self.url, repos_path, model_module.replace(":", ".")), expect_error=True) self.assertEqual(result.returncode, 0) - self.assertTrue("DeprecationWarning" in result.stderr) self.assertTrue("tables missing from database: tmp_account_rundiffs" in result.stdout) # Update db to latest model. diff --git a/migrate/versioning/script/sql.py b/migrate/versioning/script/sql.py index 70b49ec..4b0536d 100644 --- a/migrate/versioning/script/sql.py +++ b/migrate/versioning/script/sql.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- import logging +import re import shutil import sqlparse @@ -36,13 +37,29 @@ class SqlScript(base.BaseScript): try: trans = conn.begin() try: + # ignore transaction management statements that are + # redundant in SQL script context and result in + # operational error being returned. + # + # Note: we don't ignore ROLLBACK in migration scripts + # since its usage would be insane anyway, and we're + # better to fail on its occurance instead of ignoring it + # (and committing transaction, which is contradictory to + # the whole idea of ROLLBACK) + ignored_statements = ('BEGIN', 'END', 'COMMIT') + ignored_regex = re.compile('^\s*(%s).*;?$' % '|'.join(ignored_statements), + re.IGNORECASE) + # NOTE(ihrachys): script may contain multiple statements, and # not all drivers reliably handle multistatement queries or # commands passed to .execute(), so split them and execute one # by one for statement in sqlparse.split(text): if statement: - conn.execute(statement) + if re.match(ignored_regex, statement): + log.warning('"%s" found in SQL script; ignoring' % statement) + else: + conn.execute(statement) trans.commit() except Exception as e: log.error("SQL script %s failed: %s", self.path, e) diff --git a/migrate/versioning/templates/manage/default.py_tmpl b/migrate/versioning/templates/manage/default.py_tmpl index e72097a..971c70f 100644 --- a/migrate/versioning/templates/manage/default.py_tmpl +++ b/migrate/versioning/templates/manage/default.py_tmpl @@ -5,6 +5,7 @@ from migrate.versioning.shell import main import six _vars = locals().copy() del _vars['__template_name__'] +del _vars['six'] _vars.pop('repository_name', None) defaults = ", ".join(["%s='%s'" % var for var in six.iteritems(_vars)]) }} diff --git a/migrate/versioning/templates/manage/pylons.py_tmpl b/migrate/versioning/templates/manage/pylons.py_tmpl index ccaac05..0d6c32c 100644 --- a/migrate/versioning/templates/manage/pylons.py_tmpl +++ b/migrate/versioning/templates/manage/pylons.py_tmpl @@ -20,6 +20,7 @@ else: import six _vars = locals().copy() del _vars['__template_name__'] +del _vars['six'] defaults = ", ".join(["%s='%s'" % var for var in six.iteritems(_vars)]) }} @@ -30,6 +30,3 @@ console_scripts = all_files = 1 build-dir = doc/build source-dir = doc/source - -[egg_info] -tag_svn_revision = 1 @@ -1,7 +1,7 @@ [tox] minversion = 1.6 skipsdist = True -envlist = py26,py27,py26sa07,py27sa07,py26sa08,py27sa08,py26sa09,py27sa09,py33,pep8 +envlist = py26,py27,py26sa07,py27sa07,py26sa08,py27sa08,py26sa09,py27sa09,py33,py34,pep8 [testenv] usedevelop = True @@ -63,6 +63,11 @@ deps = sqlalchemy>=0.9 -r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements-py3.txt +[testenv:py34] +deps = sqlalchemy>=0.9 + -r{toxinidir}/test-requirements.txt + -r{toxinidir}/test-requirements-py3.txt + [testenv:pep8] commands = flake8 @@ -75,12 +80,51 @@ commands = python setup.py testr --slowest --testr-args='{posargs}' [flake8] -# F841 local variable 'json_template' is assigned to but never used +# E121 continuation line indentation is not a multiple of four +# E122 continuation line missing indentation or outdented +# E123 closing bracket does not match indentation of opening bracket's line +# E124 closing bracket does not match visual indentation +# E125 continuation line does not distinguish itself from next logical line +# E126 continuation line over-indented for hanging indent +# E127 continuation line over-indented for visual indent +# E128 continuation line under-indented for visual indent +# E202 whitespace before ')' +# E203 whitespace before ',' +# E225 missing whitespace around operator +# E226 missing whitespace around arithmetic operator +# E228 missing whitespace around modulo operator +# E231 missing whitespace after ',' +# H234 assertEquals is deprecated, use assertEqual +# E251 unexpected spaces around keyword / parameter equals +# E261 at least two spaces before inline comment +# E272 multiple spaces before keyword +# E301 expected 1 blank line, found 0 +# E302 expected 2 blank lines, found 1 +# E303 too many blank lines (3) +# E401 multiple imports on one line +# E501 line too long (<number-of-chars> > 79 characters) +# E502 the backslash is redundant between brackets +# E702 multiple statements on one line (semicolon) +# E712 comparison to True should be 'if cond is True:' or 'if cond:' +# F401 '<module>' imported but unused +# F403 'from migrate.exceptions import *' used; unable to detect undefined names +# F811 redefinition of unused '<type>' from line <lineno> +# F821 undefined name '<name>' +# F841 local variable '<variable>' is assigned to but never used +# H101 Use TODO(NAME) # H201 no 'except:' at least use 'except Exception:' -# H302 import only modules.'bla..' does not import a module +# H202 assertRaises Exception too broad +# H233 Python 3.x incompatible use of print operator +# H301 one import per line +# H302 import only modules. '<import>' does not import a module # H306 imports not in alphabetical order +# H401 docstring should not start with a space +# H402 one line docstring needs punctuation. +# H403 multi line docstring end on new line # H404 multi line docstring should start with a summary -ignore = F841,H201,H302,H306,H404 +# H501 Do not use locals() for string formatting +# W391 blank line at end of file +ignore = E121,E122,E123,E124,E125,E126,E127,E128,E202,E203,E225,E226,E228,E231,E251,E261,E272,E301,E302,E303,E401,E501,E502,E702,E712,F401,F403,F811,F821,F841,H101,H201,H202,H233,H234,H301,H302,H306,H401,H402,H403,H404,H501,W391 show-source = true builtins = _ exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools,build |