Commits

Andrew Godwin committed 0ea4e7e Draft Merge

Branch merge

  • Participants
  • Parent commits 0555d24, 8d758a7

Comments (0)

Files changed (8)

File south/db/generic.py

         """
         return self._get_connection().ops.quote_name(name)
 
-    def execute(self, sql, params=[]):
+    def _print_sql_error(self, e, sql, params=[]):
+        print('FATAL ERROR - The following SQL query failed: %s' % sql, file=sys.stderr)
+        print('The error was: %s' % e, file=sys.stderr)
+        
+    def execute(self, sql, params=[], print_all_errors=True):
         """
         Executes the given SQL statement, with optional parameters.
         If the instance's debug attribute is True, prints out what it executes.
         try:
             cursor.execute(sql, params)
         except DatabaseError as e:
-            print('FATAL ERROR - The following SQL query failed: %s' % sql, file=sys.stderr)
-            print('The error was: %s' % e, file=sys.stderr)
+            if print_all_errors:
+                self._print_sql_error(e, sql, params)
             raise
 
         try:

File south/db/oracle.py

 
 from south.db import generic
 
-warnings.warn("! WARNING: South's Oracle support is still alpha. "
-              "Be wary of possible bugs.")
-
 class DatabaseOperations(generic.DatabaseOperations):    
     """
     Oracle implementation of database operations.    
 
         for sql_template, params in sql_templates:
             try:
-                self.execute(sql_template % params)
+                self.execute(sql_template % params, print_all_errors=False)
             except DatabaseError as exc:
                 description = str(exc)
                 # Oracle complains if a column is already NULL/NOT NULL
                 elif 'ORA-22858' in description or 'ORA-22859' in description:
                     self._alter_column_lob_workaround(table_name, name, field)
                 else:
+                    self._print_sql_error(exc, sql_template % params)
                     raise
 
     def _alter_column_lob_workaround(self, table_name, name, field):

File south/db/sqlite3.py

                     name = renames[name]
                 columns.append(name)
 
-            if columns and columns != uniques_deleted:
+            if columns and set(columns) != set(uniques_deleted):
                 self._create_unique(table_name, columns)
     
     def _column_sql_for_create(self, table_name, name, field, explicit_name=True):

File south/migration/migrators.py

 from copy import copy, deepcopy
 import datetime
 import inspect
-import io
 import sys
 import traceback
+try:
+    from cStringIO import StringIO # python 2
+except ImportError:
+    from io import StringIO # python 3
 
 from django.core.management import call_command
 from django.core.management.commands import loaddata
             # executed
             south.db.db._constraint_cache = constraint_cache
 
-    def run_migration(self, migration):
+    def run_migration(self, migration, database):
         try:
             self._run_migration(migration)
         except exceptions.FailedDryRun:
 
 class FakeMigrator(MigratorWrapper):
     def run(self, migration, database):
+        # Don't actually run, just record as if ran
+        self.record(migration, database)
         if self.verbosity:
             print('   (faked)')
 
         old_debug, old_dry_run = south.db.db.debug, south.db.db.dry_run
         south.db.db.debug = south.db.db.dry_run = True
         stdout = sys.stdout
-        sys.stdout = io.StringIO()
+        sys.stdout = StringIO()
         try:
             try:
                 self.backwards(migration)()

File south/migration/utils.py

     
     # We need to apply all the migrations this one depends on
     for n in children:
-        for result in _dfs(n, get_children, path):
-            results.append(result)
+        results = _dfs(n, get_children, path) + results
 
     path.pop()
 
+    results = list(SortedSet(results))
     dependency_cache[(start, get_children)] = results
     return results
 
     return _dfs(start, get_children, [])
 
 def depends(start, get_children):
-    result = SortedSet(reversed(list(dfs(start, get_children))))
-    return list(result)
+    return dfs(start, get_children)

File south/tests/__init__.py

         if hasattr(self, 'installed_apps'):
             hacks.store_app_cache_state()
             hacks.set_installed_apps(self.installed_apps)
+            # Make sure dependencies are calculated for new apps
+            Migrations._dependencies_done = False
 
     def tearDown(self):
         """

File south/tests/db.py

 import datetime
 
 from south.db import db, generic
-from django.db import connection, models, IntegrityError
+from django.db import connection, models, IntegrityError as DjangoIntegrityError
 
 from south.tests import unittest, skipIf, skipUnless
 from south.utils.py3 import text_type, with_metaclass
     pass
 errors = tuple(errors)
 
+# On SQL Server, the backend's IntegrityError is not (a subclass of) Django's.
+try:
+    from sql_server.pyodbc.base import IntegrityError as SQLServerIntegrityError
+    IntegrityError = (DjangoIntegrityError, SQLServerIntegrityError)
+except ImportError:
+    IntegrityError = DjangoIntegrityError
+
 try:
     from south.db import mysql
 except ImportError:

File south/tests/logic.py

 
 import datetime
 import sys
+try:
+    set # builtin, python >=2.6
+except NameError:
+    from sets import Set as set # in stdlib, python >=2.3
 
 from south import exceptions
 from south.migration import migrate_app
     
     installed_apps = ["fakeapp", "otherfakeapp"]
 
+    def setUp(self):
+        super(TestMigrationLogic, self).setUp()
+        MigrationHistory.objects.all().delete()
+        
     def assertListEqual(self, list1, list2, msg=None):
-        list1 = list(list1)
-        list2 = list(list2)
-        try:
-            list1.sort()
-            list2.sort()
-        except TypeError:
-            # emulate Python 2 behavior in Python 3
-            list1 = sorted(list1, key=id)
-            list2 = sorted(list2, key=id)
+        list1 = set(list1)
+        list2 = set(list2)
         return self.assert_(list1 == list2, "%s is not equal to %s" % (list1, list2))
 
     def test_find_ghost_migrations(self):
         pass
     
     def test_apply_migrations(self):
-        MigrationHistory.objects.all().delete()
         migrations = Migrations("fakeapp")
         
         # We should start with no migrations
     
     
     def test_migration_merge_forwards(self):
-        MigrationHistory.objects.all().delete()
         migrations = Migrations("fakeapp")
         
         # We should start with no migrations