Skip to content

Commit fca63ea

Browse files
authored
Add incr/decr support #6, use pytest and tox #5 (#7)
1 parent 6c8d3d7 commit fca63ea

File tree

7 files changed

+127
-136
lines changed

7 files changed

+127
-136
lines changed

cache_fallback/cache.py

+19-17
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ def get_cache(backend, **kwargs):
1414
from django.core import cache as dj_cache
1515

1616
if django.VERSION <= (1, 6):
17-
cache = dj_cache.get_cache(backend, **kwargs)
17+
cache_instance = dj_cache.get_cache(backend, **kwargs)
1818
elif django.VERSION >= (3, 2):
19-
cache = dj_cache.caches.create_connection(backend)
19+
cache_instance = dj_cache.caches.create_connection(backend)
2020
else: # Django 1.7 to 3.1
21-
cache = dj_cache._create_cache(backend, **kwargs)
21+
cache_instance = dj_cache._create_cache(backend, **kwargs)
2222

2323
# Some caches -- python-memcached in particular -- need to do a cleanup at the
2424
# end of a request cycle. If not implemented in a particular backend
2525
# cache.close is a no-op. Not available in Django 1.5
26-
if hasattr(cache, "close"):
27-
signals.request_finished.connect(cache.close)
28-
return cache
26+
if hasattr(cache_instance, "close"):
27+
signals.request_finished.connect(cache_instance.close)
28+
return cache_instance
2929

3030

3131
class FallbackCache(BaseCache):
@@ -38,34 +38,36 @@ def __init__(self, params=None, *args, **kwargs):
3838
self._cache_fallback = get_cache("fallback_cache")
3939

4040
def add(self, key, value, timeout=None, version=None):
41-
return self._call_with_fallback(
42-
"add", key, value, timeout=timeout, version=version
43-
)
41+
return self._call_with_fallback("add", key, value, timeout=timeout, version=version)
4442

4543
def get(self, key, default=None, version=None):
4644
return self._call_with_fallback("get", key, default=default, version=version)
4745

4846
def set(self, key, value, timeout=None, version=None, client=None):
49-
return self._call_with_fallback(
50-
"set", key, value, timeout=timeout, version=version
51-
)
47+
return self._call_with_fallback("set", key, value, timeout=timeout, version=version)
5248

5349
def delete(self, key, version=None):
5450
return self._call_with_fallback("delete", key, version=version)
5551

5652
def clear(self):
5753
return self._call_with_fallback("clear")
5854

55+
def incr(self, key, delta=1, version=None):
56+
return self._call_with_fallback("incr", key, delta=delta, version=version)
57+
58+
def decr(self, key, delta=1, version=None):
59+
return self._call_with_fallback("decr", key, delta=delta, version=version)
60+
5961
def _call_with_fallback(self, method, *args, **kwargs):
6062
try:
61-
return self._call_main_cache(args, kwargs, method)
63+
return self._call_main_cache(method, *args, **kwargs)
6264
except Exception as e:
6365
logger.warning("Switch to fallback cache")
6466
logger.exception(e)
65-
return self._call_fallback_cache(args, kwargs, method)
67+
return self._call_fallback_cache(method, *args, **kwargs)
6668

67-
def _call_main_cache(self, args, kwargs, method):
69+
def _call_main_cache(self, method, *args, **kwargs):
6870
return getattr(self._cache, method)(*args, **kwargs)
6971

70-
def _call_fallback_cache(self, args, kwargs, method):
71-
return getattr(self._cache_fallback, method)(*args, **kwargs)
72+
def _call_fallback_cache(self, method, *args, **kwargs):
73+
return getattr(self._cache_fallback, method)(*args, **kwargs)

runtests.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# just run: python setup.py test
1+
# just run: tox

setup.cfg

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
universal = 1
33

44
[tool:pytest]
5+
DJANGO_SETTINGS_MODULE = tests.settings
56
norecursedirs = .git .eggs
6-
addopts = --cov=cache_fallback --cov-report term-missing
77

88
[testenv:flake8]
99
commands = flake8
@@ -12,6 +12,12 @@ commands = flake8
1212
branch = True
1313
omit = tests/*
1414

15+
[coverage:report]
16+
precision = 2
17+
show_missing = True
18+
skip_covered = True
19+
skip_empty = True
20+
1521
[flake8]
1622
ignore = E721,E203,W503
1723
max-line-length = 120

setup.py

+26-81
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,42 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33
import io
4-
import sys
54
from setuptools import setup, find_packages
6-
from setuptools.command.test import test as TestCommand
75

6+
with io.open("requirements.txt", encoding="utf-8") as f:
7+
requirements = [line.strip() for line in f if line.strip()]
88

9-
with open("requirements.txt") as f:
10-
requirements = [line.strip() for line in f.readlines()]
11-
12-
13-
class PyTest(TestCommand):
14-
user_options = [("pytest-args=", "a", "Arguments to pass to py.test")]
15-
16-
def initialize_options(self):
17-
TestCommand.initialize_options(self)
18-
self.pytest_args = []
19-
20-
def finalize_options(self):
21-
TestCommand.finalize_options(self)
22-
self.test_args = []
23-
self.test_suite = True
24-
25-
def run_tests(self):
26-
import pytest
27-
import django
28-
from django.conf import settings
29-
30-
settings.configure(
31-
TESTING=True,
32-
DATABASES={
33-
"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": "test.db"},
34-
},
35-
CACHES={
36-
"default": {"BACKEND": "cache_fallback.FallbackCache"},
37-
"fallback_cache": {
38-
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
39-
"LOCATION": "unique",
40-
},
41-
"main_cache": {
42-
"BACKEND": "django.core.cache.backends.dummy.DummyCache",
43-
},
44-
},
45-
INSTALLED_APPS=(
46-
"django.contrib.auth",
47-
"django.contrib.contenttypes",
48-
"django.contrib.sessions",
49-
"cache_fallback",
50-
"tests.testapp",
51-
),
52-
MIDDLEWARE_CLASSES=("django.middleware.common.CommonMiddleware",),
53-
)
54-
55-
if django.VERSION[:2] >= (1, 7):
56-
django.setup()
57-
58-
errno = pytest.main(self.pytest_args)
59-
sys.exit(errno)
60-
9+
with io.open("README.rst", encoding="utf-8") as f:
10+
long_description = f.read()
6111

6212
setup(
6313
name="django-cache-fallback",
64-
version="0.3.0",
14+
version="0.4.0",
6515
description="Django Cache Fallback",
66-
keywords="django-cache-fallback, django cache, multiple cache, fallback cache",
16+
long_description=long_description,
17+
long_description_content_type="text/x-rst",
6718
author="Jakub Stawowy",
6819
author_email="[email protected]",
6920
url="https://github.com/Kub-AT/django-cache-fallback",
7021
license="3-clause BSD",
71-
long_description=io.open("./README.rst", "r", encoding="utf-8").read(),
7222
platforms="any",
7323
zip_safe=False,
24+
packages=find_packages(exclude=("tests",)),
25+
include_package_data=True,
26+
install_requires=requirements,
27+
extras_require={
28+
"tests": [
29+
"pytest",
30+
"coverage",
31+
"pytest-cov",
32+
"flake8",
33+
"python-memcached",
34+
"mock",
35+
"django",
36+
]
37+
},
7438
classifiers=[
7539
"Programming Language :: Python",
76-
"Programming Language :: Python :: 2",
7740
"Programming Language :: Python :: 2.7",
7841
"Programming Language :: Python :: 3",
7942
"Programming Language :: Python :: 3.4",
@@ -82,30 +45,12 @@ def run_tests(self):
8245
"Programming Language :: Python :: 3.7",
8346
"Programming Language :: Python :: 3.8",
8447
"Programming Language :: Python :: 3.9",
48+
"Programming Language :: Python :: 3.10",
49+
"Programming Language :: Python :: 3.11",
50+
"Programming Language :: Python :: 3.12",
8551
"Development Status :: 5 - Production/Stable",
8652
"Environment :: Web Environment",
8753
"Framework :: Django",
88-
"Framework :: Django :: 3.2",
89-
"Framework :: Django :: 3.2",
90-
"Framework :: Django :: 3.1",
91-
"Framework :: Django :: 2.2",
92-
"Framework :: Django :: 1.11",
93-
"Framework :: Django :: 1.10",
94-
"Framework :: Django :: 1.9",
95-
"Framework :: Django :: 1.8",
96-
"Intended Audience :: Developers",
97-
],
98-
packages=find_packages(exclude=("tests",)),
99-
include_package_data=True,
100-
install_requires=requirements,
101-
tests_require=[
102-
"flake8",
103-
"pytest",
104-
"coverage",
105-
"pytest-cov",
106-
"python-memcached",
107-
"mock",
10854
],
109-
setup_requires=["pytest-runner"],
110-
cmdclass={"test": PyTest},
111-
)
55+
setup_requires=["tox"],
56+
)

tests/settings.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import os
2+
3+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4+
5+
SECRET_KEY = "test-secret-key"
6+
DEBUG = True
7+
USE_TZ = False
8+
9+
INSTALLED_APPS = [
10+
"django.contrib.auth",
11+
"django.contrib.contenttypes",
12+
"django.contrib.sessions",
13+
"cache_fallback",
14+
"tests.testapp",
15+
]
16+
17+
DATABASES = {
18+
"default": {
19+
"ENGINE": "django.db.backends.sqlite3",
20+
"NAME": ":memory:",
21+
}
22+
}
23+
24+
CACHES = {
25+
"default": {"BACKEND": "cache_fallback.FallbackCache"},
26+
"fallback_cache": {
27+
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
28+
"LOCATION": "unique",
29+
},
30+
"main_cache": {
31+
"BACKEND": "django.core.cache.backends.dummy.DummyCache",
32+
},
33+
}
34+
35+
MIDDLEWARE = [
36+
"django.middleware.common.CommonMiddleware",
37+
]

tests/test_basic.py

+19-33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
from mock import patch
2+
from unittest.mock import patch
33

44
from django.core.cache import BaseCache
55
from django import test
@@ -12,81 +12,67 @@ def get_client(**kwargs):
1212

1313

1414
class CacheFallbackBasicTestCase(test.TestCase):
15+
def setUp(self):
16+
self._sut = get_client()
17+
1518
def test_client(self):
16-
client = get_client()
17-
self.assertIsInstance(client, FallbackCache)
18-
self.assertIsInstance(client._cache, BaseCache)
19-
self.assertIsInstance(client._cache_fallback, BaseCache)
19+
self.assertIsInstance(self._sut, FallbackCache)
20+
self.assertIsInstance(self._sut._cache, BaseCache)
21+
self.assertIsInstance(self._sut._cache_fallback, BaseCache)
2022

2123
@patch.object(FallbackCache, "_call_fallback_cache")
2224
@patch.object(FallbackCache, "_call_main_cache")
2325
def test_get_maincache(self, maincache_mock, fallback_cache_mock):
24-
client = get_client()
25-
client.get("irrelevent")
26-
26+
self._sut.get("irrelevent")
2727
maincache_mock.assert_called_once()
2828
fallback_cache_mock.assert_not_called()
2929

3030
@patch.object(FallbackCache, "_call_fallback_cache")
3131
@patch.object(FallbackCache, "_call_main_cache")
3232
def test_set_maincache(self, maincache_mock, fallback_cache_mock):
33-
client = get_client()
34-
client.set("irrelevent", "123", 5)
35-
33+
self._sut.set("irrelevent", "123", 5)
3634
maincache_mock.assert_called_once()
3735
fallback_cache_mock.assert_not_called()
3836

3937
@patch.object(FallbackCache, "_call_fallback_cache")
4038
@patch.object(FallbackCache, "_call_main_cache")
4139
def test_get_fallbackcache(self, maincache_mock, fallback_cache_mock):
42-
client = get_client()
43-
client.get("irrelevent")
44-
40+
self._sut.get("irrelevent")
4541
maincache_mock.assert_called_once()
4642
fallback_cache_mock.assert_not_called()
4743

4844
maincache_mock.side_effect = Exception()
49-
client.get("irrelevent")
50-
45+
self._sut.get("irrelevent")
5146
fallback_cache_mock.assert_called_once()
5247

5348
@patch.object(FallbackCache, "_call_fallback_cache")
5449
@patch.object(FallbackCache, "_call_main_cache")
5550
def test_multiple_get_fallbackcache(self, maincache_mock, fallback_cache_mock):
56-
client = get_client()
57-
client.get("irrelevent")
58-
51+
self._sut.get("irrelevent")
5952
maincache_mock.assert_called_once()
6053
fallback_cache_mock.assert_not_called()
6154

6255
maincache_mock.side_effect = Exception()
63-
to_get = ["irrelevent1", "irrelevent2", "irrelevent3"]
64-
for key in to_get:
65-
client.get(key)
66-
67-
fallback_cache_mock.assert_called()
68-
self.assertEqual(fallback_cache_mock.call_count, len(to_get))
56+
keys = ["irrelevent1", "irrelevent2", "irrelevent3"]
57+
for key in keys:
58+
self._sut.get(key)
59+
self.assertEqual(fallback_cache_mock.call_count, len(keys))
6960

7061
@patch.object(FallbackCache, "_call_fallback_cache")
7162
@patch.object(FallbackCache, "_call_main_cache")
7263
def test_set_fallbackcache(self, maincache_mock, fallback_cache_mock):
73-
client = get_client()
74-
client.set("irrelevent", "123", 5)
75-
64+
self._sut.set("irrelevent", "123", 5)
7665
maincache_mock.assert_called_once()
7766
fallback_cache_mock.assert_not_called()
7867

7968
maincache_mock.side_effect = Exception()
80-
client.set("irrelevent", "123", 5)
81-
69+
self._sut.set("irrelevent", "123", 5)
8270
fallback_cache_mock.assert_called_once()
8371

8472
@patch("cache_fallback.cache.logger")
8573
@patch.object(FallbackCache, "_call_main_cache")
8674
def test_get_fallbackcache_logger(self, maincache_mock, logger_mock):
87-
client = get_client()
8875
maincache_mock.side_effect = Exception()
89-
client.get("irrelevent")
90-
76+
self._sut.get("irrelevent")
9177
logger_mock.warning.assert_called_with("Switch to fallback cache")
9278
logger_mock.exception.assert_called_once()

0 commit comments

Comments
 (0)