diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..92b366f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +dist: xenial +sudo: false + +language: python +python: +- 2.7 +- 3.4 +- 3.5 +- 3.6 +- 3.7 + +cache: pip + +env: +- DJANGO=1.11 +- DJANGO=2.0 +- DJANGO=2.1 +- DJANGO=master + +matrix: + fast_finish: true + include: + - python: 3.7 + env: TOXENV=flake8 + exclude: + - python: 2.7 + env: DJANGO=2.0 + - python: 2.7 + env: DJANGO=2.1 + - python: 3.4 + env: DJANGO=2.1 + allow_failures: + - env: DJANGO=master +install: +- travis_retry pip install -U tox-travis + +script: +- tox diff --git a/flash/base.py b/flash/base.py index c65d161..5b576e7 100644 --- a/flash/base.py +++ b/flash/base.py @@ -1,7 +1,7 @@ -import six import time import copy +from django.utils import six from distutils.version import StrictVersion from abc import ABCMeta, abstractmethod, abstractproperty from collections import defaultdict @@ -639,10 +639,10 @@ def get_key(self, *args, **kwargs): value = field_dict[field.attname] if isinstance(value, models.Model): # get the pk value on instance - if field.rel: - rel_model = field.rel.to + if field.remote_field: + rel_model = field.remote_field.model else: - # In very rare cases, field.rel is found to be None + # In very rare cases, field.remote_field is found to be None # that I do not know why. # fallback method to get rel_model rel_model = value.__class__ @@ -869,7 +869,7 @@ def remove_fk_instances(self, instance): delattr(instance, attr) for field in instance._meta.fields: - if field.rel: + if field.remote_field: attr = '_%s_cache' % field.name if hasattr(instance, attr): delattr(instance, attr) @@ -959,7 +959,7 @@ def __new__(cls, *args, **kwargs): relation_splits = ncls.relation.split('__') relation_str = '' for field_name in relation_splits: - rel_model = rel_model._meta.get_field(field_name).rel.to + rel_model = rel_model._meta.get_field(field_name).remote_field.model if relation_str: relation_str += '__%s' % field_name else: @@ -975,7 +975,7 @@ class RelatedModelInvalidationCache(object): """ Mixin class used in RelatedInstanceCache, RelatedQuerysetCache """ def _get_invalidation_models(self): - return [self.model] + self.rel_models.keys() + return [self.model] + list(self.rel_models) def _get_keys_to_be_invalidated(self, instance, signal, using): keys = [] @@ -1173,7 +1173,7 @@ def __new__(cls, *args, **kwargs): relation_splits = ncls.relation.split('__') relation_str = '' for field_name in relation_splits: - rel_model = rel_model._meta.get_field(field_name).rel.to + rel_model = rel_model._meta.get_field(field_name).remote_field.model if relation_str: relation_str += '__%s' % field_name else: @@ -1267,7 +1267,7 @@ def __get__(self, instance, instance_type=None): # If NULL is an allowed value, return it. if self.field.null: return None - raise self.field.rel.to.DoesNotExist + raise self.field.remote_field.model.DoesNotExist rel_obj = self.cache_class.get(val) setattr(instance, self.cache_name, rel_obj) return rel_obj @@ -1385,7 +1385,7 @@ def patch_cached_foreignkeys(cls): for model, cached_foreignkeys in cls.model_cached_foreignkeys.items(): for key in cached_foreignkeys: try: - rel_model = model._meta.get_field(key).rel.to + rel_model = model._meta.get_field(key).remote_field.model rel_model_pk_name = rel_model._meta.pk.name cache_class = rel_model.cache.get_cache_class_for( rel_model_pk_name) @@ -1395,7 +1395,7 @@ def patch_cached_foreignkeys(cls): assert False, ("Cached foreignkey can't be made on field "+ "`%s` of %s. Because %s is not cached on "+ "it's primary key") % ( - key, model, model._meta.get_field(key).rel.to) + key, model, model._meta.get_field(key).remote_field.model) @classmethod diff --git a/flash/collector.py b/flash/collector.py index 6c2dc04..d3f4a01 100644 --- a/flash/collector.py +++ b/flash/collector.py @@ -1,5 +1,4 @@ -import six - +from django.utils import six from collections import defaultdict from functools import wraps diff --git a/flash/tests/__init__.py b/flash/tests/__init__.py deleted file mode 100644 index 56f12fb..0000000 --- a/flash/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .test_flash import * diff --git a/flash/tests/utils.py b/flash/tests/utils.py deleted file mode 100644 index 770a226..0000000 --- a/flash/tests/utils.py +++ /dev/null @@ -1,33 +0,0 @@ -from django.conf import settings -from django.core.management import call_command -from django.db.models import loading -from django import test - - -class TestCase(test.TestCase): - apps = ('flash.tests',) - tables_created = False - - def _pre_setup(self): - cls = TestCase - if not cls.tables_created: - # Add the models to the db. - cls._original_installed_apps = list(settings.INSTALLED_APPS) - for app in cls.apps: - if isinstance(settings.INSTALLED_APPS, tuple): - settings.INSTALLED_APPS = list(settings.INSTALLED_APPS) - settings.INSTALLED_APPS.append(app) - loading.cache.loaded = False - call_command('syncdb', interactive=False, verbosity=0) - TestCase.tables_created = True - - # Call the original method that does the fixtures etc. - super(TestCase, self)._pre_setup() - - def _post_teardown(self): - # Call the original method. - super(TestCase, self)._post_teardown() - cls = TestCase - # Restore the settings. - settings.INSTALLED_APPS = cls._original_installed_apps - loading.cache.loaded = False diff --git a/runtests.py b/runtests.py new file mode 100644 index 0000000..77ab310 --- /dev/null +++ b/runtests.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +import os +import sys + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'tests.settings') + + +def runtests(): + import django + from django.conf import settings + from django.test.utils import get_runner + + if hasattr(django, 'setup'): + django.setup() + + TestRunner = get_runner(settings) + test_runner = TestRunner(verbosity=2, interactive=True) + failures = test_runner.run_tests(['tests']) + sys.exit(bool(failures)) + + +if __name__ == "__main__": + runtests() + diff --git a/setup.py b/setup.py index 792ebaf..ee49bcb 100644 --- a/setup.py +++ b/setup.py @@ -14,4 +14,5 @@ 'flash', ], zip_safe=False, + test_suite='runtests.runtests', ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flash/tests/caches.py b/tests/caches.py similarity index 100% rename from flash/tests/caches.py rename to tests/caches.py diff --git a/flash/tests/models.py b/tests/models.py similarity index 69% rename from flash/tests/models.py rename to tests/models.py index 98a5d01..8c0be6b 100644 --- a/flash/tests/models.py +++ b/tests/models.py @@ -9,12 +9,12 @@ class ModelA(models.Model): class ModelB(models.Model): num = models.IntegerField() text = models.CharField(max_length=50) - a = models.ForeignKey(ModelA) + a = models.ForeignKey(ModelA, on_delete=models.CASCADE) class ModelC(models.Model): - a = models.ForeignKey(ModelA) - b = models.ForeignKey(ModelB) + a = models.ForeignKey(ModelA, on_delete=models.CASCADE) + b = models.ForeignKey(ModelB, on_delete=models.CASCADE) num = models.IntegerField() diff --git a/tests/settings.py b/tests/settings.py new file mode 100644 index 0000000..49cebd1 --- /dev/null +++ b/tests/settings.py @@ -0,0 +1,12 @@ +SECRET_KEY = 's3cr3t' +INSTALLED_APPS = [ + 'django.contrib.contenttypes', + 'flash', + 'tests', +] +DATABASES = { + 'default': { + 'NAME': 'default', + 'ENGINE': 'django.db.backends.sqlite3', + }, +} diff --git a/flash/tests/test_flash.py b/tests/test_flash.py similarity index 98% rename from flash/tests/test_flash.py rename to tests/test_flash.py index e06f03f..f143284 100644 --- a/flash/tests/test_flash.py +++ b/tests/test_flash.py @@ -1,8 +1,9 @@ import time +from django.test import TestCase + from flash.base import cache, BatchCacheQuery -from .utils import TestCase from .models import ModelA, ModelB, ModelC, ModelD from .caches import BCacheOnNum, AListCacheOnD @@ -166,7 +167,7 @@ def test_basic1(self): 2: BCacheOnNum(num=2), }).get(only_cache=True) - self.assertTrue(result.keys() == [1]) + self.assertEqual(list(result), [1]) result = BatchCacheQuery({ 1: ModelA.cache.get_query(num=1), diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..80e2066 --- /dev/null +++ b/tox.ini @@ -0,0 +1,43 @@ +[tox] +envlist = + py{27,34,35,36}-django111, + py{34,35,36,37}-django20, + py{35,36,37}-django21, + py{35,36,37}-djangomaster, + flake8 + +[travis] +python = + 2.7: py27 + 3.4: py34 + 3.5: py35 + 3.6: py36 + 3.7: py37 + +[travis:env] +DJANGO = + 1.11: django111 + 2.0: django20 + 2.1: django21 + master: djangomaster + +[testenv] +deps = + django111: django>=1.11,<2.0 + django20: django>=2.0,<2.1 + django21: django>=2.1,<2.2 + djangomaster: https://github.com/django/django/archive/master.tar.gz +usedevelop = True +ignore_outcome = + djangomaster: True +commands = + python setup.py test +setenv = + PYTHONDONTWRITEBYTECODE=1 + +[testenv:flake8] +deps = flake8 +commands = flake8 + +[flake8] +ignore = D203