Hello community,

here is the log from the commit of package python-sqlalchemy-migrate for 
openSUSE:Factory checked in at 2014-09-17 17:26:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-sqlalchemy-migrate (Old)
 and      /work/SRC/openSUSE:Factory/.python-sqlalchemy-migrate.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-sqlalchemy-migrate"

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-sqlalchemy-migrate/python-sqlalchemy-migrate.changes
      2014-05-24 07:41:13.000000000 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-sqlalchemy-migrate.new/python-sqlalchemy-migrate.changes
 2014-09-17 17:27:28.000000000 +0200
@@ -1,0 +2,9 @@
+Tue Sep 16 06:26:48 UTC 2014 - tbecht...@suse.com
+
+- update to version 0.9.2:
+  * SqlScript: execute multiple statements one by one
+  * Make sure we don't throw away exception on SQL script failure
+  * Pin testtools to < 0.9.36
+- update Requires according to requirements.txt
+
+-------------------------------------------------------------------

Old:
----
  sqlalchemy-migrate-0.9.1.tar.gz

New:
----
  sqlalchemy-migrate-0.9.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-sqlalchemy-migrate.spec ++++++
--- /var/tmp/diff_new_pack.ezMeho/_old  2014-09-17 17:27:29.000000000 +0200
+++ /var/tmp/diff_new_pack.ezMeho/_new  2014-09-17 17:27:29.000000000 +0200
@@ -18,7 +18,7 @@
 
 
 Name:           python-sqlalchemy-migrate
-Version:        0.9.1
+Version:        0.9.2
 Release:        0
 Summary:        Database schema migration for SQLAlchemy
 License:        MIT
@@ -36,9 +36,12 @@
 BuildRequires:  python-decorator
 #BuildRequires:  python-pysqlite
 #BuildRequires:  python-pytz
-Requires:       python-SQLAlchemy >= 0.6
+Requires:       python-SQLAlchemy >= 0.7.8
+Requires:       python-Tempita >= 0.4
 Requires:       python-Tempita >= 0.4
 Requires:       python-decorator
+Requires:       python-six >= 1.4.1
+Requires:       python-sqlparse
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 %if 0%{?suse_version} && 0%{?suse_version} <= 1110
 %{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print get_python_lib()")}

++++++ sqlalchemy-migrate-0.9.1.tar.gz -> sqlalchemy-migrate-0.9.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sqlalchemy-migrate-0.9.1/AUTHORS 
new/sqlalchemy-migrate-0.9.2/AUTHORS
--- old/sqlalchemy-migrate-0.9.1/AUTHORS        2014-05-06 16:40:25.000000000 
+0200
+++ new/sqlalchemy-migrate-0.9.2/AUTHORS        2014-09-11 18:42:29.000000000 
+0200
@@ -1,5 +1,43 @@
-
+Alex Favaro <alexfav...@gmail.com>
+Bob Farrell <robertanthonyfarr...@gmail.com>
+Chris Withers <ch...@simplistix.co.uk>
+Cyril Roelandt <cyril.roela...@enovance.com>
+Dan Prince <dpri...@redhat.com>
+David Ripton <drip...@redhat.com>
+Domen Kožar <do...@dev.si>
+Dustin J. Mitchell <dus...@mozilla.com>
+Eric Harney <ehar...@redhat.com>
+Gabriel <g2p.code+s...@gmail.com>
+Ihar Hrachyshka <ihrac...@redhat.com>
+Jan Dittberner <jan.dittber...@gmail.com>
+Jan Dittberner <jan.dittber...@googlemail.com>
+Jan Dittberner <j...@dittberner.info>
+Jason Michalski <arm...@armooo.net>
+Josip Delic <delij...@googlemail.com>
+Matt Riedemann <mrie...@us.ibm.com>
+Monty Taylor <mord...@inaugust.com>
+Pete Keen <p...@bugsplat.info>
+Pádraig Brady <p...@draigbrady.com>
 Pádraig Brady <pbr...@redhat.com>
 Rahul Priyadarshi <rahul.priyadar...@in.ibm.com>
+Rick Copeland <rick...@usa.net>
+Roman Podolyaka <rpodoly...@mirantis.com>
+Sascha Peilicke <sasc...@gmx.de>
+Sascha Peilicke <speili...@suse.com>
+Sean Dague <sean.da...@samsung.com>
 Sheng Bo Hou <sb...@cn.ibm.com>
+Thomas Goirand <tho...@goirand.fr>
 Thuy Christenson <t...@us.ibm.com>
+al.ya...@gmail.com <unknown>
+asuffi...@gmail.com <unknown>
+ches.martin <unknown>
+christian.simms <unknown>
+chrisw <unknown>
+emil.kroymann <unknown>
+hud...@fubarite.fubar.si <unknown>
+iElectric <unknown>
+jan.dittberner <unknown>
+mark...@gmail.com <unknown>
+percious17 <unknown>
+r...@fubarite.fubar.si <unknown>
+wyue...@gmail.com <unknown>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sqlalchemy-migrate-0.9.1/ChangeLog 
new/sqlalchemy-migrate-0.9.2/ChangeLog
--- old/sqlalchemy-migrate-0.9.1/ChangeLog      2014-05-06 16:40:25.000000000 
+0200
+++ new/sqlalchemy-migrate-0.9.2/ChangeLog      2014-09-11 18:42:29.000000000 
+0200
@@ -1,6 +1,13 @@
 CHANGES
 =======
 
+0.9.2
+-----
+
+* SqlScript: execute multiple statements one by one
+* Make sure we don't throw away exception on SQL script failure
+* Pin testtools to < 0.9.36
+
 0.9.1
 -----
 
@@ -19,6 +26,7 @@
 * Conditionally import ibmdb2/ibm_db_sa
 * migrate needs subunit >= 0.0.18
 * UniqueConstraint named and escaped twice
+* Fix 3 files with Windows line endings to Unix line endings
 * Eradicate trailing whitespace
 * Convert tabs to spaces in a couple of rst files
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sqlalchemy-migrate-0.9.1/PKG-INFO 
new/sqlalchemy-migrate-0.9.2/PKG-INFO
--- old/sqlalchemy-migrate-0.9.1/PKG-INFO       2014-05-06 16:40:25.000000000 
+0200
+++ new/sqlalchemy-migrate-0.9.2/PKG-INFO       2014-09-11 18:42:29.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: sqlalchemy-migrate
-Version: 0.9.1
+Version: 0.9.2
 Summary: Database schema migration for SQLAlchemy
 Home-page: http://www.openstack.org/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sqlalchemy-migrate-0.9.1/doc/source/theme/layout.html 
new/sqlalchemy-migrate-0.9.2/doc/source/theme/layout.html
--- old/sqlalchemy-migrate-0.9.1/doc/source/theme/layout.html   2014-05-06 
16:39:34.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/doc/source/theme/layout.html   2014-09-11 
18:41:48.000000000 +0200
@@ -1,90 +1,90 @@
-<?xml version="1.0"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-
-<?python
-import pudge
-
-def initialize(t):
-   g = t.generator
-   if not hasattr(t, 'title'):
-       t.title = 'Untitled'
-   t.doc_title = g.index_document['title']
-   t.home_url = g.organization_url or g.blog_url or g.trac_url
-   t.home_title = g.organization
-?>
-
-<html xmlns="http://www.w3.org/1999/xhtml"; 
-      xmlns:py="http://purl.org/kid/ns#";
-      py:def="layout">
-  
-  <head>
-    <title>${title}</title>
-    <link rel="stylesheet" type="text/css" href="layout.css"/>
-    <link py:if="generator.syndication_url" 
-          rel="alternate" 
-          type="application/rss+xml" 
-          title="RSS 2.0" href="${generator.syndication_url}"/>
-
-  </head>
-  <body>
-    <div id="page">
-      <h1 class="doc-title"><a href="${home_url}">${home_title}</a></h1>
-      <div id="navcontainer">
-        <ul id="navlist">
-          <li class="pagenav">
-            <ul>
-              <li class="page_item">
-                <a href="index.html"
-                   class="${'index.html'== destfile and 'selected' or ''}"
-                   title="Project Home / Index">${doc_title}</a>
-              </li>
-              <li class="page_item">
-                <a href="module-index.html" 
-                   class="${'module-index.html'== destfile and 'selected' or 
''}"
-                   title="${doc_title.lower()} package and module 
reference">Modules</a>
-              </li>
-              <?python 
-              trac_url = generator.trac_url 
-              mailing_list_url = generator.mailing_list_url
-              ?>
-              <li py:if="trac_url">
-                <a href="${trac_url}"
-                   title="Wiki / Subversion / Roadmap / Bug Tracker"
-                   >Trac</a>
-              </li>
-              <li py:if="generator.blog_url">
-                <a href="${generator.blog_url}">Blog</a>
-              </li>
-              <li py:if="mailing_list_url">
-                <a href="${mailing_list_url}"
-                   class="${mailing_list_url == destfile and 'selected' or ''}"
-                   title="Mailing List">Discuss</a>
-              </li>
-            </ul>
-          </li>
-        </ul>
-      </div>
-      
-      <hr />
-      
-      <div id="content" py:content="content()"/>
-      
-      <div id="footer">
-        <?python license = generator.get_document('doc-license') ?>
-        
-        <p style="float: left;">
-          built with 
-          <a href="http://lesscode.org/projects/pudge/";
-             >pudge/${pudge.__version__}</a><br />
-             original design by 
-          <a href="http://blog.ratterobert.com/";
-             >ratter / robert</a><br />
-        </p>
-        <p style="float:right;">
-            evan.rosson (at) gmail.com
-        </p>
-      </div>
-    </div>
-  </body>
-
-</html>
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
+
+<?python
+import pudge
+
+def initialize(t):
+   g = t.generator
+   if not hasattr(t, 'title'):
+       t.title = 'Untitled'
+   t.doc_title = g.index_document['title']
+   t.home_url = g.organization_url or g.blog_url or g.trac_url
+   t.home_title = g.organization
+?>
+
+<html xmlns="http://www.w3.org/1999/xhtml";
+      xmlns:py="http://purl.org/kid/ns#";
+      py:def="layout">
+
+  <head>
+    <title>${title}</title>
+    <link rel="stylesheet" type="text/css" href="layout.css"/>
+    <link py:if="generator.syndication_url"
+          rel="alternate"
+          type="application/rss+xml"
+          title="RSS 2.0" href="${generator.syndication_url}"/>
+
+  </head>
+  <body>
+    <div id="page">
+      <h1 class="doc-title"><a href="${home_url}">${home_title}</a></h1>
+      <div id="navcontainer">
+        <ul id="navlist">
+          <li class="pagenav">
+            <ul>
+              <li class="page_item">
+                <a href="index.html"
+                   class="${'index.html'== destfile and 'selected' or ''}"
+                   title="Project Home / Index">${doc_title}</a>
+              </li>
+              <li class="page_item">
+                <a href="module-index.html"
+                   class="${'module-index.html'== destfile and 'selected' or 
''}"
+                   title="${doc_title.lower()} package and module 
reference">Modules</a>
+              </li>
+              <?python
+              trac_url = generator.trac_url
+              mailing_list_url = generator.mailing_list_url
+              ?>
+              <li py:if="trac_url">
+                <a href="${trac_url}"
+                   title="Wiki / Subversion / Roadmap / Bug Tracker"
+                   >Trac</a>
+              </li>
+              <li py:if="generator.blog_url">
+                <a href="${generator.blog_url}">Blog</a>
+              </li>
+              <li py:if="mailing_list_url">
+                <a href="${mailing_list_url}"
+                   class="${mailing_list_url == destfile and 'selected' or ''}"
+                   title="Mailing List">Discuss</a>
+              </li>
+            </ul>
+          </li>
+        </ul>
+      </div>
+
+      <hr />
+
+      <div id="content" py:content="content()"/>
+
+      <div id="footer">
+        <?python license = generator.get_document('doc-license') ?>
+
+        <p style="float: left;">
+          built with
+          <a href="http://lesscode.org/projects/pudge/";
+             >pudge/${pudge.__version__}</a><br />
+             original design by
+          <a href="http://blog.ratterobert.com/";
+             >ratter / robert</a><br />
+        </p>
+        <p style="float:right;">
+            evan.rosson (at) gmail.com
+        </p>
+      </div>
+    </div>
+  </body>
+
+</html>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sqlalchemy-migrate-0.9.1/migrate/changeset/databases/ibmdb2.py 
new/sqlalchemy-migrate-0.9.2/migrate/changeset/databases/ibmdb2.py
--- old/sqlalchemy-migrate-0.9.1/migrate/changeset/databases/ibmdb2.py  
2014-05-06 16:39:34.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/migrate/changeset/databases/ibmdb2.py  
2014-09-11 18:41:48.000000000 +0200
@@ -1,313 +1,313 @@
-"""
-    DB2 database specific implementations of changeset classes.
-"""
-
-import logging
-
-from ibm_db_sa import base
-from sqlalchemy.schema import (AddConstraint,
-                               CreateIndex,
-                               DropConstraint)
-from sqlalchemy.schema import (Index,
-                               PrimaryKeyConstraint,
-                               UniqueConstraint)
-
-from migrate.changeset import ansisql
-from migrate.changeset import constraint
-from migrate import exceptions
-
-
-LOG = logging.getLogger(__name__)
-
-IBMDBSchemaGenerator = base.IBM_DBDDLCompiler
-
-
-def get_server_version_info(dialect):
-    """Returns the DB2 server major and minor version as a list of ints."""
-    return [int(ver_token) for ver_token in dialect.dbms_ver.split('.')[0:2]]
-
-
-def is_unique_constraint_with_null_columns_supported(dialect):
-    """Checks to see if the DB2 version is at least 10.5.
-
-    This is needed for checking if unique constraints with null columns
-    are supported.
-    """
-    return get_server_version_info(dialect) >= [10, 5]
-
-
-class IBMDBColumnGenerator(IBMDBSchemaGenerator,
-                           ansisql.ANSIColumnGenerator):
-    def visit_column(self, column):
-        nullable = True
-        if not column.nullable:
-            nullable = False
-            column.nullable = True
-
-        table = self.start_alter_table(column)
-        self.append("ADD COLUMN ")
-        self.append(self.get_column_specification(column))
-
-        for cons in column.constraints:
-            self.traverse_single(cons)
-        if column.default is not None:
-            self.traverse_single(column.default)
-        self.execute()
-
-        #ALTER TABLE STATEMENTS
-        if not nullable:
-            self.start_alter_table(column)
-            self.append("ALTER COLUMN %s SET NOT NULL" %
-                        self.preparer.format_column(column))
-            self.execute()
-            self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" %
-                        self.preparer.format_table(table))
-            self.execute()
-
-        # add indexes and unique constraints
-        if column.index_name:
-            Index(column.index_name, column).create()
-        elif column.unique_name:
-            constraint.UniqueConstraint(column,
-                                        name=column.unique_name).create()
-
-        # SA bounds FK constraints to table, add manually
-        for fk in column.foreign_keys:
-            self.add_foreignkey(fk.constraint)
-
-        # add primary key constraint if needed
-        if column.primary_key_name:
-            pk = constraint.PrimaryKeyConstraint(
-                column, name=column.primary_key_name)
-            pk.create()
-
-        self.append("COMMIT")
-        self.execute()
-        self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" %
-                    self.preparer.format_table(table))
-        self.execute()
-
-
-class IBMDBColumnDropper(ansisql.ANSIColumnDropper):
-    def visit_column(self, column):
-        """Drop a column from its table.
-
-        :param column: the column object
-        :type column: :class:`sqlalchemy.Column`
-        """
-        #table = self.start_alter_table(column)
-        super(IBMDBColumnDropper, self).visit_column(column)
-        self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" %
-                    self.preparer.format_table(column.table))
-        self.execute()
-
-
-class IBMDBSchemaChanger(IBMDBSchemaGenerator, ansisql.ANSISchemaChanger):
-    def visit_table(self, table):
-        """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))
-        self.execute()
-        self.append("COMMIT")
-        self.execute()
-
-    def _rename_table(self, table):
-        self.append("RENAME TABLE %s " % self.preparer.format_table(table))
-
-    def visit_index(self, index):
-        old_name = self.preparer.quote(self._index_identifier(index.name),
-                                       index.quote)
-        new_name = self.preparer.quote(self._index_identifier(index.new_name),
-                                       index.quote)
-        self.append("RENAME INDEX %s TO %s" % (old_name, new_name))
-        self.execute()
-        self.append("COMMIT")
-        self.execute()
-
-    def _run_subvisit(self, delta, func, start_alter=True):
-        """Runs visit method based on what needs to be changed on column"""
-        table = delta.table
-        if start_alter:
-            self.start_alter_table(table)
-        ret = func(table,
-                   self.preparer.quote(delta.current_name, delta.quote),
-                   delta)
-        self.execute()
-        self._reorg_table(self.preparer.format_table(delta.table))
-
-    def _reorg_table(self, delta):
-        self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" % delta)
-        self.execute()
-
-    def visit_column(self, delta):
-        keys = delta.keys()
-        tr = self.connection.begin()
-        column = delta.result_column.copy()
-
-        if 'type' in keys:
-            try:
-                self._run_subvisit(delta, self._visit_column_change, False)
-            except Exception as e:
-                LOG.warn("Unable to change the column type. Error: %s" % e)
-
-            if column.primary_key and 'primary_key' not in keys:
-                try:
-                    self._run_subvisit(delta, self._visit_primary_key)
-                except Exception as e:
-                    LOG.warn("Unable to add primary key. Error: %s" % e)
-
-        if 'nullable' in keys:
-            self._run_subvisit(delta, self._visit_column_nullable)
-
-        if 'server_default' in keys:
-            self._run_subvisit(delta, self._visit_column_default)
-
-        if 'primary_key' in keys:
-            self._run_subvisit(delta, self._visit_primary_key)
-            self._run_subvisit(delta, self._visit_unique_constraint)
-
-        if 'name' in keys:
-            try:
-                self._run_subvisit(delta, self._visit_column_name, False)
-            except Exception as e:
-                LOG.warn("Unable to change column %(name)s. Error: %(error)s" %
-                         {'name': delta.current_name, 'error': e})
-
-        self._reorg_table(self.preparer.format_table(delta.table))
-        self.append("COMMIT")
-        self.execute()
-        tr.commit()
-
-    def _visit_unique_constraint(self, table, col_name, delta):
-        # Add primary key to the current column
-        self.append("ADD CONSTRAINT %s " % col_name)
-        self.append("UNIQUE (%s)" % col_name)
-
-    def _visit_primary_key(self, table, col_name, delta):
-        # Add primary key to the current column
-        self.append("ADD PRIMARY KEY (%s)" % col_name)
-
-    def _visit_column_name(self, table, col_name, delta):
-        column = delta.result_column.copy()
-
-        # Delete the primary key before renaming the column
-        if column.primary_key:
-            try:
-                self.start_alter_table(table)
-                self.append("DROP PRIMARY KEY")
-                self.execute()
-            except Exception:
-                LOG.debug("Continue since Primary key does not exist.")
-
-        self.start_alter_table(table)
-        new_name = self.preparer.format_column(delta.result_column)
-        self.append("RENAME COLUMN %s TO %s" % (col_name, new_name))
-
-        if column.primary_key:
-            # execute the rename before adding primary key back
-            self.execute()
-            self.start_alter_table(table)
-            self.append("ADD PRIMARY KEY (%s)" % new_name)
-
-    def _visit_column_nullable(self, table, col_name, delta):
-        self.append("ALTER COLUMN %s " % col_name)
-        nullable = delta['nullable']
-        if nullable:
-            self.append("DROP NOT NULL")
-        else:
-            self.append("SET NOT NULL")
-
-    def _visit_column_default(self, table, col_name, delta):
-        default_text = self.get_column_default_string(delta.result_column)
-        self.append("ALTER COLUMN %s " % col_name)
-        if default_text is None:
-            self.append("DROP DEFAULT")
-        else:
-            self.append("SET WITH DEFAULT %s" % default_text)
-
-    def _visit_column_change(self, table, col_name, delta):
-        column = delta.result_column.copy()
-
-        # Delete the primary key before
-        if column.primary_key:
-            try:
-                self.start_alter_table(table)
-                self.append("DROP PRIMARY KEY")
-                self.execute()
-            except Exception:
-                LOG.debug("Continue since Primary key does not exist.")
-            # Delete the identity before
-            try:
-                self.start_alter_table(table)
-                self.append("ALTER COLUMN %s DROP IDENTITY" % col_name)
-                self.execute()
-            except Exception:
-                LOG.debug("Continue since identity does not exist.")
-
-        column.default = None
-        if not column.table:
-            column.table = delta.table
-        self.start_alter_table(table)
-        self.append("ALTER COLUMN %s " % col_name)
-        self.append("SET DATA TYPE ")
-        type_text = self.dialect.type_compiler.process(
-            delta.result_column.type)
-        self.append(type_text)
-
-
-class IBMDBConstraintGenerator(ansisql.ANSIConstraintGenerator):
-    def _visit_constraint(self, constraint):
-        constraint.name = self.get_constraint_name(constraint)
-        if (isinstance(constraint, UniqueConstraint) and
-                is_unique_constraint_with_null_columns_supported(
-                    self.dialect)):
-            for column in constraint.columns._all_cols:
-                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),
-                          unique=True)
-            sql = self.process(CreateIndex(index))
-            sql += ' EXCLUDE NULL KEYS'
-        else:
-            sql = self.process(AddConstraint(constraint))
-        self.append(sql)
-        self.execute()
-
-
-class IBMDBConstraintDropper(ansisql.ANSIConstraintDropper,
-                             ansisql.ANSIConstraintCommon):
-    def _visit_constraint(self, constraint):
-        constraint.name = self.get_constraint_name(constraint)
-        if (isinstance(constraint, UniqueConstraint) and
-                is_unique_constraint_with_null_columns_supported(
-                    self.dialect)):
-            for column in constraint.columns._all_cols:
-                if column.nullable:
-                    constraint.exclude_nulls = True
-                    break
-        if getattr(constraint, 'exclude_nulls', None):
-            index_name = self.preparer.quote(
-                self._index_identifier(constraint.name), constraint.quote)
-            sql = 'DROP INDEX %s ' % index_name
-        else:
-            sql = self.process(DropConstraint(constraint,
-                                              cascade=constraint.cascade))
-        self.append(sql)
-        self.execute()
-
-    def visit_migrate_primary_key_constraint(self, constraint):
-        self.start_alter_table(constraint.table)
-        self.append("DROP PRIMARY KEY")
-        self.execute()
-
-
-class IBMDBDialect(ansisql.ANSIDialect):
-    columngenerator = IBMDBColumnGenerator
-    columndropper = IBMDBColumnDropper
-    schemachanger = IBMDBSchemaChanger
-    constraintgenerator = IBMDBConstraintGenerator
-    constraintdropper = IBMDBConstraintDropper
+"""
+    DB2 database specific implementations of changeset classes.
+"""
+
+import logging
+
+from ibm_db_sa import base
+from sqlalchemy.schema import (AddConstraint,
+                               CreateIndex,
+                               DropConstraint)
+from sqlalchemy.schema import (Index,
+                               PrimaryKeyConstraint,
+                               UniqueConstraint)
+
+from migrate.changeset import ansisql
+from migrate.changeset import constraint
+from migrate import exceptions
+
+
+LOG = logging.getLogger(__name__)
+
+IBMDBSchemaGenerator = base.IBM_DBDDLCompiler
+
+
+def get_server_version_info(dialect):
+    """Returns the DB2 server major and minor version as a list of ints."""
+    return [int(ver_token) for ver_token in dialect.dbms_ver.split('.')[0:2]]
+
+
+def is_unique_constraint_with_null_columns_supported(dialect):
+    """Checks to see if the DB2 version is at least 10.5.
+
+    This is needed for checking if unique constraints with null columns
+    are supported.
+    """
+    return get_server_version_info(dialect) >= [10, 5]
+
+
+class IBMDBColumnGenerator(IBMDBSchemaGenerator,
+                           ansisql.ANSIColumnGenerator):
+    def visit_column(self, column):
+        nullable = True
+        if not column.nullable:
+            nullable = False
+            column.nullable = True
+
+        table = self.start_alter_table(column)
+        self.append("ADD COLUMN ")
+        self.append(self.get_column_specification(column))
+
+        for cons in column.constraints:
+            self.traverse_single(cons)
+        if column.default is not None:
+            self.traverse_single(column.default)
+        self.execute()
+
+        #ALTER TABLE STATEMENTS
+        if not nullable:
+            self.start_alter_table(column)
+            self.append("ALTER COLUMN %s SET NOT NULL" %
+                        self.preparer.format_column(column))
+            self.execute()
+            self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" %
+                        self.preparer.format_table(table))
+            self.execute()
+
+        # add indexes and unique constraints
+        if column.index_name:
+            Index(column.index_name, column).create()
+        elif column.unique_name:
+            constraint.UniqueConstraint(column,
+                                        name=column.unique_name).create()
+
+        # SA bounds FK constraints to table, add manually
+        for fk in column.foreign_keys:
+            self.add_foreignkey(fk.constraint)
+
+        # add primary key constraint if needed
+        if column.primary_key_name:
+            pk = constraint.PrimaryKeyConstraint(
+                column, name=column.primary_key_name)
+            pk.create()
+
+        self.append("COMMIT")
+        self.execute()
+        self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" %
+                    self.preparer.format_table(table))
+        self.execute()
+
+
+class IBMDBColumnDropper(ansisql.ANSIColumnDropper):
+    def visit_column(self, column):
+        """Drop a column from its table.
+
+        :param column: the column object
+        :type column: :class:`sqlalchemy.Column`
+        """
+        #table = self.start_alter_table(column)
+        super(IBMDBColumnDropper, self).visit_column(column)
+        self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" %
+                    self.preparer.format_table(column.table))
+        self.execute()
+
+
+class IBMDBSchemaChanger(IBMDBSchemaGenerator, ansisql.ANSISchemaChanger):
+    def visit_table(self, table):
+        """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))
+        self.execute()
+        self.append("COMMIT")
+        self.execute()
+
+    def _rename_table(self, table):
+        self.append("RENAME TABLE %s " % self.preparer.format_table(table))
+
+    def visit_index(self, index):
+        old_name = self.preparer.quote(self._index_identifier(index.name),
+                                       index.quote)
+        new_name = self.preparer.quote(self._index_identifier(index.new_name),
+                                       index.quote)
+        self.append("RENAME INDEX %s TO %s" % (old_name, new_name))
+        self.execute()
+        self.append("COMMIT")
+        self.execute()
+
+    def _run_subvisit(self, delta, func, start_alter=True):
+        """Runs visit method based on what needs to be changed on column"""
+        table = delta.table
+        if start_alter:
+            self.start_alter_table(table)
+        ret = func(table,
+                   self.preparer.quote(delta.current_name, delta.quote),
+                   delta)
+        self.execute()
+        self._reorg_table(self.preparer.format_table(delta.table))
+
+    def _reorg_table(self, delta):
+        self.append("CALL SYSPROC.ADMIN_CMD('REORG TABLE %s')" % delta)
+        self.execute()
+
+    def visit_column(self, delta):
+        keys = delta.keys()
+        tr = self.connection.begin()
+        column = delta.result_column.copy()
+
+        if 'type' in keys:
+            try:
+                self._run_subvisit(delta, self._visit_column_change, False)
+            except Exception as e:
+                LOG.warn("Unable to change the column type. Error: %s" % e)
+
+            if column.primary_key and 'primary_key' not in keys:
+                try:
+                    self._run_subvisit(delta, self._visit_primary_key)
+                except Exception as e:
+                    LOG.warn("Unable to add primary key. Error: %s" % e)
+
+        if 'nullable' in keys:
+            self._run_subvisit(delta, self._visit_column_nullable)
+
+        if 'server_default' in keys:
+            self._run_subvisit(delta, self._visit_column_default)
+
+        if 'primary_key' in keys:
+            self._run_subvisit(delta, self._visit_primary_key)
+            self._run_subvisit(delta, self._visit_unique_constraint)
+
+        if 'name' in keys:
+            try:
+                self._run_subvisit(delta, self._visit_column_name, False)
+            except Exception as e:
+                LOG.warn("Unable to change column %(name)s. Error: %(error)s" %
+                         {'name': delta.current_name, 'error': e})
+
+        self._reorg_table(self.preparer.format_table(delta.table))
+        self.append("COMMIT")
+        self.execute()
+        tr.commit()
+
+    def _visit_unique_constraint(self, table, col_name, delta):
+        # Add primary key to the current column
+        self.append("ADD CONSTRAINT %s " % col_name)
+        self.append("UNIQUE (%s)" % col_name)
+
+    def _visit_primary_key(self, table, col_name, delta):
+        # Add primary key to the current column
+        self.append("ADD PRIMARY KEY (%s)" % col_name)
+
+    def _visit_column_name(self, table, col_name, delta):
+        column = delta.result_column.copy()
+
+        # Delete the primary key before renaming the column
+        if column.primary_key:
+            try:
+                self.start_alter_table(table)
+                self.append("DROP PRIMARY KEY")
+                self.execute()
+            except Exception:
+                LOG.debug("Continue since Primary key does not exist.")
+
+        self.start_alter_table(table)
+        new_name = self.preparer.format_column(delta.result_column)
+        self.append("RENAME COLUMN %s TO %s" % (col_name, new_name))
+
+        if column.primary_key:
+            # execute the rename before adding primary key back
+            self.execute()
+            self.start_alter_table(table)
+            self.append("ADD PRIMARY KEY (%s)" % new_name)
+
+    def _visit_column_nullable(self, table, col_name, delta):
+        self.append("ALTER COLUMN %s " % col_name)
+        nullable = delta['nullable']
+        if nullable:
+            self.append("DROP NOT NULL")
+        else:
+            self.append("SET NOT NULL")
+
+    def _visit_column_default(self, table, col_name, delta):
+        default_text = self.get_column_default_string(delta.result_column)
+        self.append("ALTER COLUMN %s " % col_name)
+        if default_text is None:
+            self.append("DROP DEFAULT")
+        else:
+            self.append("SET WITH DEFAULT %s" % default_text)
+
+    def _visit_column_change(self, table, col_name, delta):
+        column = delta.result_column.copy()
+
+        # Delete the primary key before
+        if column.primary_key:
+            try:
+                self.start_alter_table(table)
+                self.append("DROP PRIMARY KEY")
+                self.execute()
+            except Exception:
+                LOG.debug("Continue since Primary key does not exist.")
+            # Delete the identity before
+            try:
+                self.start_alter_table(table)
+                self.append("ALTER COLUMN %s DROP IDENTITY" % col_name)
+                self.execute()
+            except Exception:
+                LOG.debug("Continue since identity does not exist.")
+
+        column.default = None
+        if not column.table:
+            column.table = delta.table
+        self.start_alter_table(table)
+        self.append("ALTER COLUMN %s " % col_name)
+        self.append("SET DATA TYPE ")
+        type_text = self.dialect.type_compiler.process(
+            delta.result_column.type)
+        self.append(type_text)
+
+
+class IBMDBConstraintGenerator(ansisql.ANSIConstraintGenerator):
+    def _visit_constraint(self, constraint):
+        constraint.name = self.get_constraint_name(constraint)
+        if (isinstance(constraint, UniqueConstraint) and
+                is_unique_constraint_with_null_columns_supported(
+                    self.dialect)):
+            for column in constraint.columns._all_cols:
+                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),
+                          unique=True)
+            sql = self.process(CreateIndex(index))
+            sql += ' EXCLUDE NULL KEYS'
+        else:
+            sql = self.process(AddConstraint(constraint))
+        self.append(sql)
+        self.execute()
+
+
+class IBMDBConstraintDropper(ansisql.ANSIConstraintDropper,
+                             ansisql.ANSIConstraintCommon):
+    def _visit_constraint(self, constraint):
+        constraint.name = self.get_constraint_name(constraint)
+        if (isinstance(constraint, UniqueConstraint) and
+                is_unique_constraint_with_null_columns_supported(
+                    self.dialect)):
+            for column in constraint.columns._all_cols:
+                if column.nullable:
+                    constraint.exclude_nulls = True
+                    break
+        if getattr(constraint, 'exclude_nulls', None):
+            index_name = self.preparer.quote(
+                self._index_identifier(constraint.name), constraint.quote)
+            sql = 'DROP INDEX %s ' % index_name
+        else:
+            sql = self.process(DropConstraint(constraint,
+                                              cascade=constraint.cascade))
+        self.append(sql)
+        self.execute()
+
+    def visit_migrate_primary_key_constraint(self, constraint):
+        self.start_alter_table(constraint.table)
+        self.append("DROP PRIMARY KEY")
+        self.execute()
+
+
+class IBMDBDialect(ansisql.ANSIDialect):
+    columngenerator = IBMDBColumnGenerator
+    columndropper = IBMDBColumnDropper
+    schemachanger = IBMDBSchemaChanger
+    constraintgenerator = IBMDBConstraintGenerator
+    constraintdropper = IBMDBConstraintDropper
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sqlalchemy-migrate-0.9.1/migrate/tests/fixture/warnings.py 
new/sqlalchemy-migrate-0.9.2/migrate/tests/fixture/warnings.py
--- old/sqlalchemy-migrate-0.9.1/migrate/tests/fixture/warnings.py      
2014-05-06 16:39:34.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/migrate/tests/fixture/warnings.py      
2014-09-11 18:41:48.000000000 +0200
@@ -1,90 +1,88 @@
-# lifted from Python 2.6, so we can use it in Python 2.5
-import sys
-
-class WarningMessage(object):
-
-    """Holds the result of a single showwarning() call."""
-
-    _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
-                        "line")
-
-    def __init__(self, message, category, filename, lineno, file=None,
-                    line=None):
-        local_values = locals()
-        for attr in self._WARNING_DETAILS:
-            setattr(self, attr, local_values[attr])
-        if category:
-            self._category_name = category.__name__
-        else:
-            self._category_name = None
-
-    def __str__(self):
-        return ("{message : %r, category : %r, filename : %r, lineno : %s, "
-                    "line : %r}" % (self.message, self._category_name,
-                                    self.filename, self.lineno, self.line))
-
-
-class catch_warnings(object):
-
-    """A context manager that copies and restores the warnings filter upon
-    exiting the context.
-
-    The 'record' argument specifies whether warnings should be captured by a
-    custom implementation of warnings.showwarning() and be appended to a list
-    returned by the context manager. Otherwise None is returned by the context
-    manager. The objects appended to the list are arguments whose attributes
-    mirror the arguments to showwarning().
-
-    The 'module' argument is to specify an alternative module to the module
-    named 'warnings' and imported under that name. This argument is only useful
-    when testing the warnings module itself.
-
-    """
-
-    def __init__(self, record=False, module=None):
-        """Specify whether to record warnings and if an alternative module
-        should be used other than sys.modules['warnings'].
-
-        For compatibility with Python 3.0, please consider all arguments to be
-        keyword-only.
-
-        """
-        self._record = record
-        if module is None:
-            self._module = sys.modules['warnings']
-        else:
-            self._module = module
-        self._entered = False
-
-    def __repr__(self):
-        args = []
-        if self._record:
-            args.append("record=True")
-        if self._module is not sys.modules['warnings']:
-            args.append("module=%r" % self._module)
-        name = type(self).__name__
-        return "%s(%s)" % (name, ", ".join(args))
-
-    def __enter__(self):
-        if self._entered:
-            raise RuntimeError("Cannot enter %r twice" % self)
-        self._entered = True
-        self._filters = self._module.filters
-        self._module.filters = self._filters[:]
-        self._showwarning = self._module.showwarning
-        if self._record:
-            log = []
-            def showwarning(*args, **kwargs):
-                log.append(WarningMessage(*args, **kwargs))
-            self._module.showwarning = showwarning
-            return log
-        else:
-            return None
-
-    def __exit__(self, *exc_info):
-        if not self._entered:
-            raise RuntimeError("Cannot exit %r without entering first" % self)
-        self._module.filters = self._filters
-        self._module.showwarning = self._showwarning
-
-
+# lifted from Python 2.6, so we can use it in Python 2.5
+import sys
+
+class WarningMessage(object):
+
+    """Holds the result of a single showwarning() call."""
+
+    _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
+                        "line")
+
+    def __init__(self, message, category, filename, lineno, file=None,
+                    line=None):
+        local_values = locals()
+        for attr in self._WARNING_DETAILS:
+            setattr(self, attr, local_values[attr])
+        if category:
+            self._category_name = category.__name__
+        else:
+            self._category_name = None
+
+    def __str__(self):
+        return ("{message : %r, category : %r, filename : %r, lineno : %s, "
+                    "line : %r}" % (self.message, self._category_name,
+                                    self.filename, self.lineno, self.line))
+
+
+class catch_warnings(object):
+
+    """A context manager that copies and restores the warnings filter upon
+    exiting the context.
+
+    The 'record' argument specifies whether warnings should be captured by a
+    custom implementation of warnings.showwarning() and be appended to a list
+    returned by the context manager. Otherwise None is returned by the context
+    manager. The objects appended to the list are arguments whose attributes
+    mirror the arguments to showwarning().
+
+    The 'module' argument is to specify an alternative module to the module
+    named 'warnings' and imported under that name. This argument is only useful
+    when testing the warnings module itself.
+
+    """
+
+    def __init__(self, record=False, module=None):
+        """Specify whether to record warnings and if an alternative module
+        should be used other than sys.modules['warnings'].
+
+        For compatibility with Python 3.0, please consider all arguments to be
+        keyword-only.
+
+        """
+        self._record = record
+        if module is None:
+            self._module = sys.modules['warnings']
+        else:
+            self._module = module
+        self._entered = False
+
+    def __repr__(self):
+        args = []
+        if self._record:
+            args.append("record=True")
+        if self._module is not sys.modules['warnings']:
+            args.append("module=%r" % self._module)
+        name = type(self).__name__
+        return "%s(%s)" % (name, ", ".join(args))
+
+    def __enter__(self):
+        if self._entered:
+            raise RuntimeError("Cannot enter %r twice" % self)
+        self._entered = True
+        self._filters = self._module.filters
+        self._module.filters = self._filters[:]
+        self._showwarning = self._module.showwarning
+        if self._record:
+            log = []
+            def showwarning(*args, **kwargs):
+                log.append(WarningMessage(*args, **kwargs))
+            self._module.showwarning = showwarning
+            return log
+        else:
+            return None
+
+    def __exit__(self, *exc_info):
+        if not self._entered:
+            raise RuntimeError("Cannot exit %r without entering first" % self)
+        self._module.filters = self._filters
+        self._module.showwarning = self._showwarning
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sqlalchemy-migrate-0.9.1/migrate/tests/versioning/test_script.py 
new/sqlalchemy-migrate-0.9.2/migrate/tests/versioning/test_script.py
--- old/sqlalchemy-migrate-0.9.1/migrate/tests/versioning/test_script.py        
2014-05-06 16:39:34.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/migrate/tests/versioning/test_script.py        
2014-09-11 18:41:49.000000000 +0200
@@ -269,5 +269,5 @@
 
         # run the change
         sqls = SqlScript(src)
-        sqls.run(self.engine, executemany=False)
+        sqls.run(self.engine)
         tmp_sql_table.metadata.drop_all(self.engine, checkfirst=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sqlalchemy-migrate-0.9.1/migrate/versioning/script/sql.py 
new/sqlalchemy-migrate-0.9.2/migrate/versioning/script/sql.py
--- old/sqlalchemy-migrate-0.9.1/migrate/versioning/script/sql.py       
2014-05-06 16:39:34.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/migrate/versioning/script/sql.py       
2014-09-11 18:41:49.000000000 +0200
@@ -3,6 +3,8 @@
 import logging
 import shutil
 
+import sqlparse
+
 from migrate.versioning.script import base
 from migrate.versioning.template import Template
 
@@ -24,7 +26,7 @@
         return cls(path)
 
     # TODO: why is step parameter even here?
-    def run(self, engine, step=None, executemany=True):
+    def run(self, engine, step=None):
         """Runs SQL script through raw dbapi execute call"""
         text = self.source()
         # Don't rely on SA's autocommit here
@@ -34,15 +36,16 @@
         try:
             trans = conn.begin()
             try:
-                # HACK: SQLite doesn't allow multiple statements through
-                # its execute() method, but it provides executescript() instead
-                dbapi = conn.engine.raw_connection()
-                if executemany and getattr(dbapi, 'executescript', None):
-                    dbapi.executescript(text)
-                else:
-                    conn.execute(text)
+                # 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)
                 trans.commit()
-            except:
+            except Exception as e:
+                log.error("SQL script %s failed: %s", self.path, e)
                 trans.rollback()
                 raise
         finally:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sqlalchemy-migrate-0.9.1/requirements.txt 
new/sqlalchemy-migrate-0.9.2/requirements.txt
--- old/sqlalchemy-migrate-0.9.1/requirements.txt       2014-05-06 
16:39:34.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/requirements.txt       2014-09-11 
18:41:49.000000000 +0200
@@ -6,4 +6,5 @@
 SQLAlchemy>=0.7.8
 decorator
 six>=1.4.1
+sqlparse
 Tempita >= 0.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sqlalchemy-migrate-0.9.1/sqlalchemy_migrate.egg-info/PKG-INFO 
new/sqlalchemy-migrate-0.9.2/sqlalchemy_migrate.egg-info/PKG-INFO
--- old/sqlalchemy-migrate-0.9.1/sqlalchemy_migrate.egg-info/PKG-INFO   
2014-05-06 16:40:25.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/sqlalchemy_migrate.egg-info/PKG-INFO   
2014-09-11 18:42:29.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: sqlalchemy-migrate
-Version: 0.9.1
+Version: 0.9.2
 Summary: Database schema migration for SQLAlchemy
 Home-page: http://www.openstack.org/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sqlalchemy-migrate-0.9.1/sqlalchemy_migrate.egg-info/requires.txt 
new/sqlalchemy-migrate-0.9.2/sqlalchemy_migrate.egg-info/requires.txt
--- old/sqlalchemy-migrate-0.9.1/sqlalchemy_migrate.egg-info/requires.txt       
2014-05-06 16:40:25.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/sqlalchemy_migrate.egg-info/requires.txt       
2014-09-11 18:42:29.000000000 +0200
@@ -2,4 +2,5 @@
 SQLAlchemy>=0.7.8
 decorator
 six>=1.4.1
+sqlparse
 Tempita >= 0.4
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sqlalchemy-migrate-0.9.1/test-requirements.txt 
new/sqlalchemy-migrate-0.9.2/test-requirements.txt
--- old/sqlalchemy-migrate-0.9.1/test-requirements.txt  2014-05-06 
16:39:34.000000000 +0200
+++ new/sqlalchemy-migrate-0.9.2/test-requirements.txt  2014-09-11 
18:41:49.000000000 +0200
@@ -15,7 +15,7 @@
 sphinx>=1.1.2,<1.2
 sphinxcontrib_issuetracker
 testrepository>=0.0.17
-testtools>=0.9.34
+testtools>=0.9.34,<0.9.36
 
 scripttest
 # NOTE(rpodolyaka): This version identifier is currently necessary as

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to