Procházet zdrojové kódy

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

Tim Graham před 6 roky
rodič
revize
f82be9ebc7

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

@@ -194,10 +194,6 @@ class BaseDatabaseFeatures:
     # Does 'a' LIKE 'A' match?
     # Does 'a' LIKE 'A' match?
     has_case_insensitive_like = True
     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.
     # Suffix for backends that don't support "SELECT xxx;" queries.
     bare_select_suffix = ''
     bare_select_suffix = ''
 
 

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

@@ -2,8 +2,9 @@ import datetime
 import decimal
 import decimal
 from importlib import import_module
 from importlib import import_module
 
 
+import sqlparse
+
 from django.conf import settings
 from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
 from django.db import NotSupportedError, transaction
 from django.db import NotSupportedError, transaction
 from django.db.backends import utils
 from django.db.backends import utils
 from django.utils import timezone
 from django.utils import timezone
@@ -298,16 +299,10 @@ class BaseDatabaseOperations:
         cursor.execute() call and PEP 249 doesn't talk about this use case,
         cursor.execute() call and PEP 249 doesn't talk about this use case,
         the default implementation is conservative.
         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):
     def process_clob(self, value):
         """
         """

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

@@ -26,7 +26,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     nulls_order_largest = True
     nulls_order_largest = True
     closed_cursor_error_class = InterfaceError
     closed_cursor_error_class = InterfaceError
     has_case_insensitive_like = False
     has_case_insensitive_like = False
-    requires_sqlparse_for_splitting = False
     greatest_least_ignores_nulls = True
     greatest_least_ignores_nulls = True
     can_clone_databases = True
     can_clone_databases = True
     supports_temporal_subtraction = 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>`
 *  memcached_, plus a :ref:`supported Python binding <memcached>`
 *  gettext_ (:ref:`gettext_on_windows`)
 *  gettext_ (:ref:`gettext_on_windows`)
 *  selenium_
 *  selenium_
-*  sqlparse_
+*  sqlparse_ (required)
 
 
 You can find these dependencies in `pip requirements files`_ inside the
 You can find these dependencies in `pip requirements files`_ inside the
 ``tests/requirements`` directory of the Django source tree and install them
 ``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
 ``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
 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
 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()
 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
     want the operation not to do anything in the given direction. This is
     especially useful in making the operation reversible.
     especially useful in making the operation reversible.
 
 
-.. _sqlparse: https://pypi.org/project/sqlparse/
-
 ``RunPython``
 ``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
 change shouldn't have an impact on your tests unless you've customized
 :class:`~django.test.TransactionTestCase`'s internals.
 :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
 Miscellaneous
 -------------
 -------------
 
 

+ 1 - 1
setup.py

@@ -83,7 +83,7 @@ setup(
     entry_points={'console_scripts': [
     entry_points={'console_scripts': [
         'django-admin = django.core.management:execute_from_command_line',
         'django-admin = django.core.management:execute_from_command_line',
     ]},
     ]},
-    install_requires=['pytz'],
+    install_requires=['pytz', 'sqlparse'],
     extras_require={
     extras_require={
         "bcrypt": ["bcrypt"],
         "bcrypt": ["bcrypt"],
         "argon2": ["argon2-cffi >= 16.1.0"],
         "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 .routers import TestRouter
 from .test_base import MigrationTestBase
 from .test_base import MigrationTestBase
 
 
-try:
-    import sqlparse
-except ImportError:
-    sqlparse = None
-
 
 
 class MigrateTests(MigrationTestBase):
 class MigrateTests(MigrationTestBase):
     """
     """
@@ -355,22 +350,19 @@ class MigrateTests(MigrationTestBase):
             out.getvalue()
             out.getvalue()
         )
         )
         # Show the plan when an operation is irreversible.
         # 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)
         call_command('migrate', 'migrations', 'zero', verbosity=0)
 
 
     @override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations_empty'})
     @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 import connection, migrations, models
 from django.db.migrations.state import ProjectState
 from django.db.migrations.state import ProjectState
 from django.test import override_settings
 from django.test import override_settings
 
 
 from .test_operations import OperationTestBase
 from .test_operations import OperationTestBase
 
 
-try:
-    import sqlparse
-except ImportError:
-    sqlparse = None
-
 
 
 class AgnosticRouter:
 class AgnosticRouter:
     """
     """
@@ -128,12 +121,10 @@ class MultiDBOperationTests(OperationTestBase):
         else:
         else:
             self.assertEqual(Pony.objects.count(), 0)
             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()])
     @override_settings(DATABASE_ROUTERS=[MigrateNothingRouter()])
     def test_run_sql(self):
     def test_run_sql(self):
         self._test_run_sql("test_mltdb_runsql", should_run=False)
         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()])
     @override_settings(DATABASE_ROUTERS=[MigrateWhenFooRouter()])
     def test_run_sql2(self):
     def test_run_sql2(self):
         self._test_run_sql("test_mltdb_runsql2", should_run=False)
         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.core.exceptions import FieldDoesNotExist
 from django.db import connection, migrations, models, transaction
 from django.db import connection, migrations, models, transaction
 from django.db.migrations.migration import Migration
 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 .models import FoodManager, FoodQuerySet, UnicodeModel
 from .test_base import MigrationTestBase
 from .test_base import MigrationTestBase
 
 
-try:
-    import sqlparse
-except ImportError:
-    sqlparse = None
-
 
 
 class Mixin:
 class Mixin:
     pass
     pass
@@ -2051,7 +2044,6 @@ class OperationTests(OperationTestBase):
         self.assertColumnExists("test_afknfk_rider", "pony_id")
         self.assertColumnExists("test_afknfk_rider", "pony_id")
         self.assertColumnNotExists("test_afknfk_rider", "pony")
         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):
     def test_run_sql(self):
         """
         """
         Tests the RunSQL operation.
         Tests the RunSQL operation.
@@ -2561,7 +2553,6 @@ class OperationTests(OperationTestBase):
             operation.database_forwards("test_runpython", editor, project_state, new_state)
             operation.database_forwards("test_runpython", editor, project_state, new_state)
             operation.database_backwards("test_runpython", editor, new_state, project_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):
     def test_separate_database_and_state(self):
         """
         """
         Tests the SeparateDatabaseAndState operation.
         Tests the SeparateDatabaseAndState operation.