Drops Django 1.6 & Python 2.6 support.
This commit is contained in:
parent
9016c650ac
commit
16e14c9219
|
@ -261,8 +261,7 @@ def create_data(using):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if django.VERSION[:2] >= (1, 7):
|
django.setup()
|
||||||
django.setup()
|
|
||||||
|
|
||||||
write_conditions()
|
write_conditions()
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
__version__ = (1, 0, 0)
|
__version__ = (1, 0, 0)
|
||||||
version_string = '.'.join(str(n) for n in __version__)
|
version_string = '.'.join(str(n) for n in __version__)
|
||||||
|
|
||||||
|
default_app_config = 'cachalot.apps.CachalotConfig'
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
from .monkey_patch import patch
|
||||||
|
|
||||||
|
|
||||||
|
class CachalotConfig(AppConfig):
|
||||||
|
name = 'cachalot'
|
||||||
|
patched = False
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
if not self.patched:
|
||||||
|
patch()
|
||||||
|
self.patched = True
|
|
@ -3,8 +3,7 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from threading import local
|
from threading import local
|
||||||
|
|
||||||
# TODO: Replace with caches[CACHALOT_CACHE] when we drop Django 1.6 support.
|
from django.core.cache import caches
|
||||||
from django.core.cache import get_cache as get_django_cache
|
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
|
|
||||||
from .settings import cachalot_settings
|
from .settings import cachalot_settings
|
||||||
|
@ -31,7 +30,7 @@ class CacheHandler(local):
|
||||||
|
|
||||||
min_level = -len(self.atomic_caches)
|
min_level = -len(self.atomic_caches)
|
||||||
if atomic_level < min_level:
|
if atomic_level < min_level:
|
||||||
return get_django_cache(cache_alias)
|
return caches[cache_alias]
|
||||||
return self.get_atomic_cache(cache_alias, atomic_level)
|
return self.get_atomic_cache(cache_alias, atomic_level)
|
||||||
|
|
||||||
def enter_atomic(self):
|
def enter_atomic(self):
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
from .monkey_patch import is_patched, patch
|
|
||||||
|
|
||||||
|
|
||||||
if not is_patched():
|
|
||||||
patch()
|
|
|
@ -5,17 +5,9 @@ from collections import Iterable
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from django import VERSION as django_version
|
from django.db.backends.utils import CursorWrapper
|
||||||
from django.conf import settings
|
|
||||||
if django_version >= (1, 7):
|
|
||||||
from django.db.backends.utils import CursorWrapper
|
|
||||||
else:
|
|
||||||
from django.db.backends.util import CursorWrapper
|
|
||||||
from django.db.models.query import EmptyResultSet
|
from django.db.models.query import EmptyResultSet
|
||||||
if django_version >= (1, 7):
|
from django.db.models.signals import post_migrate
|
||||||
from django.db.models.signals import post_migrate
|
|
||||||
else:
|
|
||||||
from django.db.models.signals import post_syncdb as post_migrate
|
|
||||||
from django.db.models.sql.compiler import (
|
from django.db.models.sql.compiler import (
|
||||||
SQLCompiler, SQLInsertCompiler, SQLUpdateCompiler, SQLDeleteCompiler)
|
SQLCompiler, SQLInsertCompiler, SQLUpdateCompiler, SQLDeleteCompiler)
|
||||||
from django.db.transaction import Atomic, get_connection
|
from django.db.transaction import Atomic, get_connection
|
||||||
|
@ -32,13 +24,6 @@ from .utils import (
|
||||||
WRITE_COMPILERS = (SQLInsertCompiler, SQLUpdateCompiler, SQLDeleteCompiler)
|
WRITE_COMPILERS = (SQLInsertCompiler, SQLUpdateCompiler, SQLDeleteCompiler)
|
||||||
|
|
||||||
|
|
||||||
PATCHED = False
|
|
||||||
|
|
||||||
|
|
||||||
def is_patched():
|
|
||||||
return PATCHED
|
|
||||||
|
|
||||||
|
|
||||||
def _unset_raw_connection(original):
|
def _unset_raw_connection(original):
|
||||||
def inner(compiler, *args, **kwargs):
|
def inner(compiler, *args, **kwargs):
|
||||||
compiler.connection.raw = False
|
compiler.connection.raw = False
|
||||||
|
@ -178,21 +163,14 @@ def _patch_tests():
|
||||||
|
|
||||||
|
|
||||||
def _invalidate_on_migration(sender, **kwargs):
|
def _invalidate_on_migration(sender, **kwargs):
|
||||||
db_alias = kwargs['using'] if django_version >= (1, 7) else kwargs['db']
|
db_alias = kwargs['using']
|
||||||
invalidate_all(db_alias=db_alias)
|
invalidate_all(db_alias=db_alias)
|
||||||
|
|
||||||
|
|
||||||
def patch():
|
def patch():
|
||||||
global PATCHED
|
|
||||||
|
|
||||||
post_migrate.connect(_invalidate_on_migration)
|
post_migrate.connect(_invalidate_on_migration)
|
||||||
if 'south' in settings.INSTALLED_APPS:
|
|
||||||
from south.signals import post_migrate as south_post_migrate
|
|
||||||
south_post_migrate.connect(_invalidate_on_migration)
|
|
||||||
|
|
||||||
_patch_cursor()
|
_patch_cursor()
|
||||||
_patch_tests()
|
_patch_tests()
|
||||||
_patch_atomic()
|
_patch_atomic()
|
||||||
_patch_orm()
|
_patch_orm()
|
||||||
|
|
||||||
PATCHED = True
|
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
try:
|
from unittest import skipIf
|
||||||
from unittest import skipIf
|
|
||||||
except ImportError: # For Python 2.6
|
|
||||||
from unittest2 import skipIf
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
try:
|
from unittest import skipIf
|
||||||
from unittest import skipIf
|
|
||||||
except ImportError: # For Python 2.6
|
|
||||||
from unittest2 import skipIf
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import DEFAULT_DB_ALIAS, connections
|
from django.db import DEFAULT_DB_ALIAS, connections
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
try:
|
from unittest import skipIf
|
||||||
from unittest import skipIf
|
|
||||||
except ImportError: # For Python 2.6
|
|
||||||
from unittest2 import skipIf
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import DEFAULT_CACHE_ALIAS
|
from django.core.cache import DEFAULT_CACHE_ALIAS
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
try:
|
|
||||||
from unittest import skipIf
|
|
||||||
except ImportError: # For Python 2.6
|
|
||||||
from unittest2 import skipIf
|
|
||||||
|
|
||||||
from django import VERSION as django_version
|
|
||||||
from django.contrib.auth.models import User, Permission, Group
|
from django.contrib.auth.models import User, Permission, Group
|
||||||
from django.core.exceptions import MultipleObjectsReturned
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
|
@ -79,8 +74,6 @@ class WriteTestCase(TransactionTestCase):
|
||||||
data2 = list(Test.objects.all())
|
data2 = list(Test.objects.all())
|
||||||
self.assertListEqual(data2, [t])
|
self.assertListEqual(data2, [t])
|
||||||
|
|
||||||
@skipIf(django_version < (1, 7),
|
|
||||||
'QuerySet.update_or_create is not implemented in Django < 1.7')
|
|
||||||
def test_update_or_create(self):
|
def test_update_or_create(self):
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
self.assertListEqual(list(Test.objects.all()), [])
|
self.assertListEqual(list(Test.objects.all()), [])
|
||||||
|
@ -821,7 +814,7 @@ class DatabaseCommandTestCase(TransactionTestCase):
|
||||||
|
|
||||||
call_command('flush', verbosity=0, interactive=False)
|
call_command('flush', verbosity=0, interactive=False)
|
||||||
|
|
||||||
if django_version >= (1, 7) and connection.vendor == 'mysql':
|
if connection.vendor == 'mysql':
|
||||||
# We need to reopen the connection or Django
|
# We need to reopen the connection or Django
|
||||||
# will execute an extra SQL request below.
|
# will execute an extra SQL request below.
|
||||||
connection.cursor()
|
connection.cursor()
|
||||||
|
@ -836,7 +829,7 @@ class DatabaseCommandTestCase(TransactionTestCase):
|
||||||
call_command('loaddata', 'cachalot/tests/loaddata_fixture.json',
|
call_command('loaddata', 'cachalot/tests/loaddata_fixture.json',
|
||||||
verbosity=0, interactive=False)
|
verbosity=0, interactive=False)
|
||||||
|
|
||||||
if django_version >= (1, 7) and connection.vendor == 'mysql':
|
if connection.vendor == 'mysql':
|
||||||
# We need to reopen the connection or Django
|
# We need to reopen the connection or Django
|
||||||
# will execute an extra SQL request below.
|
# will execute an extra SQL request below.
|
||||||
connection.cursor()
|
connection.cursor()
|
||||||
|
|
|
@ -4,14 +4,9 @@ from __future__ import unicode_literals
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
import django
|
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
from django.db.models.sql.where import ExtraWhere, SubqueryConstraint
|
from django.db.models.sql.where import ExtraWhere, SubqueryConstraint
|
||||||
DJANGO_GTE_1_7 = django.VERSION[:2] >= (1, 7)
|
from django.utils.module_loading import import_string
|
||||||
if DJANGO_GTE_1_7:
|
|
||||||
from django.utils.module_loading import import_string
|
|
||||||
else:
|
|
||||||
from django.utils.module_loading import import_by_path as import_string
|
|
||||||
from django.utils.six import PY3
|
from django.utils.six import PY3
|
||||||
|
|
||||||
from .settings import cachalot_settings
|
from .settings import cachalot_settings
|
||||||
|
@ -87,9 +82,8 @@ def _find_subqueries(children):
|
||||||
yield child.query_object.query
|
yield child.query_object.query
|
||||||
else:
|
else:
|
||||||
rhs = None
|
rhs = None
|
||||||
if DJANGO_GTE_1_7:
|
if hasattr(child, 'rhs'):
|
||||||
if hasattr(child, 'rhs'):
|
rhs = child.rhs
|
||||||
rhs = child.rhs
|
|
||||||
elif isinstance(child, tuple):
|
elif isinstance(child, tuple):
|
||||||
rhs = child[-1]
|
rhs = child[-1]
|
||||||
if hasattr(rhs, 'query'):
|
if hasattr(rhs, 'query'):
|
||||||
|
|
|
@ -4,16 +4,14 @@ Quick start
|
||||||
Requirements
|
Requirements
|
||||||
............
|
............
|
||||||
|
|
||||||
- Django 1.6 or 1.7
|
- Django 1.7 or 1.8
|
||||||
- Python 2.6, 2.7, 3.2, 3.3, or 3.4
|
- Python 2.7, 3.2, 3.3, or 3.4
|
||||||
- a cache configured as ``'default'`` with one of these backends:
|
- a cache configured as ``'default'`` with one of these backends:
|
||||||
|
|
||||||
- `django-redis <https://github.com/niwibe/django-redis>`_
|
- `django-redis <https://github.com/niwibe/django-redis>`_
|
||||||
- `memcached <https://docs.djangoproject.com/en/1.7/topics/cache/#memcached>`_
|
- `memcached <https://docs.djangoproject.com/en/1.7/topics/cache/#memcached>`_
|
||||||
(using either python-memcached or pylibmc (but pylibmc is only supported
|
(using either python-memcached or pylibmc)
|
||||||
with Django >= 1.7))
|
|
||||||
- `filebased <https://docs.djangoproject.com/en/1.7/topics/cache/#filesystem-caching>`_
|
- `filebased <https://docs.djangoproject.com/en/1.7/topics/cache/#filesystem-caching>`_
|
||||||
(only with Django >= 1.7 as it was not thread-safe before)
|
|
||||||
- `locmem <https://docs.djangoproject.com/en/1.7/topics/cache/#local-memory-caching>`_
|
- `locmem <https://docs.djangoproject.com/en/1.7/topics/cache/#local-memory-caching>`_
|
||||||
(but it’s not shared between processes, see :ref:`Limits`)
|
(but it’s not shared between processes, see :ref:`Limits`)
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Django>=1.6
|
Django>=1.7
|
||||||
|
|
|
@ -9,8 +9,7 @@ import django
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
|
||||||
if django.VERSION[:2] >= (1, 7):
|
django.setup()
|
||||||
django.setup()
|
|
||||||
from django.test.runner import DiscoverRunner
|
from django.test.runner import DiscoverRunner
|
||||||
test_runner = DiscoverRunner(verbosity=2)
|
test_runner = DiscoverRunner(verbosity=2)
|
||||||
failures = test_runner.run_tests(['cachalot.tests'])
|
failures = test_runner.run_tests(['cachalot.tests'])
|
||||||
|
|
|
@ -5,6 +5,3 @@ MySQL-python
|
||||||
django-redis
|
django-redis
|
||||||
python-memcached
|
python-memcached
|
||||||
pylibmc
|
pylibmc
|
||||||
South
|
|
||||||
# For Python 2.6
|
|
||||||
unittest2
|
|
||||||
|
|
|
@ -4,4 +4,3 @@ psycopg2
|
||||||
https://github.com/clelland/MySQL-for-Python-3/tarball/master
|
https://github.com/clelland/MySQL-for-Python-3/tarball/master
|
||||||
django-redis
|
django-redis
|
||||||
python3-memcached
|
python3-memcached
|
||||||
South
|
|
||||||
|
|
55
settings.py
55
settings.py
|
@ -3,8 +3,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import django
|
|
||||||
|
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'sqlite3': {
|
'sqlite3': {
|
||||||
|
@ -26,26 +24,12 @@ DATABASES = {
|
||||||
}
|
}
|
||||||
for alias in DATABASES:
|
for alias in DATABASES:
|
||||||
test_db_name = 'test_' + DATABASES[alias]['NAME']
|
test_db_name = 'test_' + DATABASES[alias]['NAME']
|
||||||
if django.VERSION < (1, 7):
|
DATABASES[alias]['TEST'] = {'NAME': test_db_name}
|
||||||
DATABASES[alias]['TEST_NAME'] = test_db_name
|
|
||||||
else:
|
|
||||||
DATABASES[alias]['TEST'] = {'NAME': test_db_name}
|
|
||||||
|
|
||||||
DATABASES['default'] = DATABASES.pop(os.environ.get('DB_ENGINE', 'sqlite3'))
|
DATABASES['default'] = DATABASES.pop(os.environ.get('DB_ENGINE', 'sqlite3'))
|
||||||
|
|
||||||
|
|
||||||
CACHES = {
|
CACHES = {
|
||||||
'locmem': {
|
|
||||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
||||||
'OPTIONS': {
|
|
||||||
# We want that limit to be infinite, otherwise we can’t
|
|
||||||
# reliably count the number of SQL queries executed in tests.
|
|
||||||
|
|
||||||
# In this context, 10e9 is enough to be considered
|
|
||||||
# infinite.
|
|
||||||
'MAX_ENTRIES': 10e9,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'redis': {
|
'redis': {
|
||||||
'BACKEND': 'django_redis.cache.RedisCache',
|
'BACKEND': 'django_redis.cache.RedisCache',
|
||||||
'LOCATION': 'redis://127.0.0.1:6379/0',
|
'LOCATION': 'redis://127.0.0.1:6379/0',
|
||||||
|
@ -60,24 +44,35 @@ CACHES = {
|
||||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||||
'LOCATION': '127.0.0.1:11211',
|
'LOCATION': '127.0.0.1:11211',
|
||||||
},
|
},
|
||||||
}
|
'locmem': {
|
||||||
if django.VERSION >= (1, 7):
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||||
CACHES['filebased'] = {
|
'OPTIONS': {
|
||||||
|
# We want that limit to be infinite, otherwise we can’t
|
||||||
|
# reliably count the number of SQL queries executed in tests.
|
||||||
|
|
||||||
|
# In this context, 10e9 is enough to be considered
|
||||||
|
# infinite.
|
||||||
|
'MAX_ENTRIES': 10e9,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'filebased': {
|
||||||
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
|
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
|
||||||
'LOCATION': '/tmp/django_cache',
|
'LOCATION': '/tmp/django_cache',
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'MAX_ENTRIES': 10e9, # (See locmem)
|
'MAX_ENTRIES': 10e9, # (See locmem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try:
|
}
|
||||||
import pylibmc
|
|
||||||
except ImportError:
|
try:
|
||||||
pass
|
import pylibmc
|
||||||
else:
|
except ImportError:
|
||||||
CACHES['pylibmc'] = {
|
pass
|
||||||
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
|
else:
|
||||||
'LOCATION': '127.0.0.1:11211',
|
CACHES['pylibmc'] = {
|
||||||
}
|
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
|
||||||
|
'LOCATION': '127.0.0.1:11211',
|
||||||
|
}
|
||||||
|
|
||||||
DEFAULT_CACHE_ALIAS = os.environ.get('CACHE_BACKEND', 'locmem')
|
DEFAULT_CACHE_ALIAS = os.environ.get('CACHE_BACKEND', 'locmem')
|
||||||
CACHES['default'] = CACHES.pop(DEFAULT_CACHE_ALIAS)
|
CACHES['default'] = CACHES.pop(DEFAULT_CACHE_ALIAS)
|
||||||
|
@ -92,8 +87,6 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
]
|
]
|
||||||
if django.VERSION < (1, 7):
|
|
||||||
INSTALLED_APPS.append('south')
|
|
||||||
|
|
||||||
|
|
||||||
MIGRATION_MODULES = {
|
MIGRATION_MODULES = {
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -27,7 +27,6 @@ setup(
|
||||||
'License :: OSI Approved :: BSD License',
|
'License :: OSI Approved :: BSD License',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python :: 2',
|
'Programming Language :: Python :: 2',
|
||||||
'Programming Language :: Python :: 2.6',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.2',
|
'Programming Language :: Python :: 3.2',
|
||||||
|
|
Loading…
Reference in New Issue