Fixed #29934 -- Added sqlparse as a require dependency.
This commit is contained in:
parent
f9ff1df1da
commit
f82be9ebc7
|
@ -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 = ''
|
||||||
|
|
||||||
|
|
|
@ -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:
|
return [
|
||||||
import sqlparse
|
sqlparse.format(statement, strip_comments=True)
|
||||||
except ImportError:
|
for statement in sqlparse.split(sql) if statement
|
||||||
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]
|
|
||||||
|
|
||||||
def process_clob(self, value):
|
def process_clob(self, value):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
split the SQL into individual statements prior to executing them.
|
||||||
requires installing the sqlparse_ Python library.
|
|
||||||
|
|
||||||
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``
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
2
setup.py
2
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"],
|
||||||
|
|
|
@ -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
|
# Migrate to the fourth migration.
|
||||||
# sqlparse may be required for splitting.
|
call_command('migrate', 'migrations', '0004', verbosity=0)
|
||||||
if sqlparse or not connection.features.requires_sqlparse_for_splitting:
|
out = io.StringIO()
|
||||||
# Migrate to the fourth migration.
|
call_command('migrate', 'migrations', '0003', plan=True, stdout=out, no_color=True)
|
||||||
call_command('migrate', 'migrations', '0004', verbosity=0)
|
self.assertEqual(
|
||||||
out = io.StringIO()
|
'Planned operations:\n'
|
||||||
call_command('migrate', 'migrations', '0003', plan=True, stdout=out, no_color=True)
|
'migrations.0004_fourth\n'
|
||||||
self.assertEqual(
|
' Raw SQL operation -> IRREVERSIBLE\n',
|
||||||
'Planned operations:\n'
|
out.getvalue()
|
||||||
'migrations.0004_fourth\n'
|
)
|
||||||
' Raw SQL operation -> IRREVERSIBLE\n',
|
# Cleanup by unmigrating everything: fake the irreversible, then
|
||||||
out.getvalue()
|
# migrate all to zero.
|
||||||
)
|
call_command('migrate', 'migrations', '0003', fake=True, verbosity=0)
|
||||||
# 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'})
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue