Browse Source

Fixed #29934 -- Added sqlparse as a require dependency.

Tim Graham 6 years ago
parent
commit
f82be9ebc7

+ 0 - 4
django/db/backends/base/features.py

@@ -194,10 +194,6 @@ class BaseDatabaseFeatures:
     # Does 'a' LIKE 'A' match?
     has_case_insensitive_like = True
 
-    # Does the backend require the sqlparse library for splitting multi-line
-    # statements before executing them?
-    requires_sqlparse_for_splitting = True
-
     # Suffix for backends that don't support "SELECT xxx;" queries.
     bare_select_suffix = ''
 

+ 6 - 11
django/db/backends/base/operations.py

@@ -2,8 +2,9 @@ import datetime
 import decimal
 from importlib import import_module
 
+import sqlparse
+
 from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
 from django.db import NotSupportedError, transaction
 from django.db.backends import utils
 from django.utils import timezone
@@ -298,16 +299,10 @@ class BaseDatabaseOperations:
         cursor.execute() call and PEP 249 doesn't talk about this use case,
         the default implementation is conservative.
         """
-        try:
-            import sqlparse
-        except ImportError:
-            raise ImproperlyConfigured(
-                "The sqlparse package is required if you don't split your SQL "
-                "statements manually."
-            )
-        else:
-            return [sqlparse.format(statement, strip_comments=True)
-                    for statement in sqlparse.split(sql) if statement]
+        return [
+            sqlparse.format(statement, strip_comments=True)
+            for statement in sqlparse.split(sql) if statement
+        ]
 
     def process_clob(self, value):
         """

+ 0 - 1
django/db/backends/postgresql/features.py

@@ -26,7 +26,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     nulls_order_largest = True
     closed_cursor_error_class = InterfaceError
     has_case_insensitive_like = False
-    requires_sqlparse_for_splitting = False
     greatest_least_ignores_nulls = True
     can_clone_databases = True
     supports_temporal_subtraction = True

+ 1 - 1
docs/internals/contributing/writing-code/unit-tests.txt

@@ -233,7 +233,7 @@ dependencies:
 *  memcached_, plus a :ref:`supported Python binding <memcached>`
 *  gettext_ (:ref:`gettext_on_windows`)
 *  selenium_
-*  sqlparse_
+*  sqlparse_ (required)
 
 You can find these dependencies in `pip requirements files`_ inside the
 ``tests/requirements`` directory of the Django source tree and install them

+ 1 - 4
docs/ref/migration-operations.txt

@@ -240,8 +240,7 @@ partial indexes.
 
 ``sql``, and ``reverse_sql`` if provided, should be strings of SQL to run on
 the database. On most database backends (all but PostgreSQL), Django will
-split the SQL into individual statements prior to executing them. This
-requires installing the sqlparse_ Python library.
+split the SQL into individual statements prior to executing them.
 
 You can also pass a list of strings or 2-tuples. The latter is used for passing
 queries and parameters in the same way as :ref:`cursor.execute()
@@ -294,8 +293,6 @@ be removed (elided) when :ref:`squashing migrations <migration-squashing>`.
     want the operation not to do anything in the given direction. This is
     especially useful in making the operation reversible.
 
-.. _sqlparse: https://pypi.org/project/sqlparse/
-
 ``RunPython``
 -------------
 

+ 7 - 0
docs/releases/2.2.txt

@@ -330,6 +330,13 @@ properly (the database was empty at the end of the whole test suite). This
 change shouldn't have an impact on your tests unless you've customized
 :class:`~django.test.TransactionTestCase`'s internals.
 
+``sqlparse`` is required dependency
+-----------------------------------
+
+To simplify a few parts of Django's database handling, `sqlparse
+<https://pypi.org/project/sqlparse/>`_ is now a required dependency. It's
+automatically installed along with Django.
+
 Miscellaneous
 -------------
 

+ 1 - 1
setup.py

@@ -83,7 +83,7 @@ setup(
     entry_points={'console_scripts': [
         'django-admin = django.core.management:execute_from_command_line',
     ]},
-    install_requires=['pytz'],
+    install_requires=['pytz', 'sqlparse'],
     extras_require={
         "bcrypt": ["bcrypt"],
         "argon2": ["argon2-cffi >= 16.1.0"],

+ 13 - 21
tests/migrations/test_commands.py

@@ -20,11 +20,6 @@ from .models import UnicodeModel, UnserializableModel
 from .routers import TestRouter
 from .test_base import MigrationTestBase
 
-try:
-    import sqlparse
-except ImportError:
-    sqlparse = None
-
 
 class MigrateTests(MigrationTestBase):
     """
@@ -355,22 +350,19 @@ class MigrateTests(MigrationTestBase):
             out.getvalue()
         )
         # Show the plan when an operation is irreversible.
-        # Migration 0004's RunSQL uses a SQL string instead of a list, so
-        # sqlparse may be required for splitting.
-        if sqlparse or not connection.features.requires_sqlparse_for_splitting:
-            # Migrate to the fourth migration.
-            call_command('migrate', 'migrations', '0004', verbosity=0)
-            out = io.StringIO()
-            call_command('migrate', 'migrations', '0003', plan=True, stdout=out, no_color=True)
-            self.assertEqual(
-                'Planned operations:\n'
-                'migrations.0004_fourth\n'
-                '    Raw SQL operation -> IRREVERSIBLE\n',
-                out.getvalue()
-            )
-            # Cleanup by unmigrating everything: fake the irreversible, then
-            # migrate all to zero.
-            call_command('migrate', 'migrations', '0003', fake=True, verbosity=0)
+        # Migrate to the fourth migration.
+        call_command('migrate', 'migrations', '0004', verbosity=0)
+        out = io.StringIO()
+        call_command('migrate', 'migrations', '0003', plan=True, stdout=out, no_color=True)
+        self.assertEqual(
+            'Planned operations:\n'
+            'migrations.0004_fourth\n'
+            '    Raw SQL operation -> IRREVERSIBLE\n',
+            out.getvalue()
+        )
+        # Cleanup by unmigrating everything: fake the irreversible, then
+        # migrate all to zero.
+        call_command('migrate', 'migrations', '0003', fake=True, verbosity=0)
         call_command('migrate', 'migrations', 'zero', verbosity=0)
 
     @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_empty'})

+ 0 - 9
tests/migrations/test_multidb.py

@@ -1,16 +1,9 @@
-import unittest
-
 from django.db import connection, migrations, models
 from django.db.migrations.state import ProjectState
 from django.test import override_settings
 
 from .test_operations import OperationTestBase
 
-try:
-    import sqlparse
-except ImportError:
-    sqlparse = None
-
 
 class AgnosticRouter:
     """
@@ -128,12 +121,10 @@ class MultiDBOperationTests(OperationTestBase):
         else:
             self.assertEqual(Pony.objects.count(), 0)
 
-    @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
     @override_settings(DATABASE_ROUTERS=[MigrateNothingRouter()])
     def test_run_sql(self):
         self._test_run_sql("test_mltdb_runsql", should_run=False)
 
-    @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
     @override_settings(DATABASE_ROUTERS=[MigrateWhenFooRouter()])
     def test_run_sql2(self):
         self._test_run_sql("test_mltdb_runsql2", should_run=False)

+ 0 - 9
tests/migrations/test_operations.py

@@ -1,5 +1,3 @@
-import unittest
-
 from django.core.exceptions import FieldDoesNotExist
 from django.db import connection, migrations, models, transaction
 from django.db.migrations.migration import Migration
@@ -14,11 +12,6 @@ from django.test import SimpleTestCase, override_settings, skipUnlessDBFeature
 from .models import FoodManager, FoodQuerySet, UnicodeModel
 from .test_base import MigrationTestBase
 
-try:
-    import sqlparse
-except ImportError:
-    sqlparse = None
-
 
 class Mixin:
     pass
@@ -2051,7 +2044,6 @@ class OperationTests(OperationTestBase):
         self.assertColumnExists("test_afknfk_rider", "pony_id")
         self.assertColumnNotExists("test_afknfk_rider", "pony")
 
-    @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
     def test_run_sql(self):
         """
         Tests the RunSQL operation.
@@ -2561,7 +2553,6 @@ class OperationTests(OperationTestBase):
             operation.database_forwards("test_runpython", editor, project_state, new_state)
             operation.database_backwards("test_runpython", editor, new_state, project_state)
 
-    @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse")
     def test_separate_database_and_state(self):
         """
         Tests the SeparateDatabaseAndState operation.