mirror of
https://github.com/jazzband/django-constance.git
synced 2026-03-16 22:40:24 +00:00
Add memory backend (#394)
* Add simple backend * Add test case for simple backend * Add tests for mget backend method * Fix redis mock mget implementation * Make sure memory backend is thread safe * Add docs section for memory backend * Add test usage examples to docs * Update docs for memory backend in testing * Share memory storage between threads
This commit is contained in:
parent
6b44a52933
commit
9eccfe0386
10 changed files with 99 additions and 7 deletions
38
constance/backends/memory.py
Normal file
38
constance/backends/memory.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
from threading import Lock
|
||||
|
||||
from . import Backend
|
||||
from .. import signals, config
|
||||
|
||||
|
||||
class MemoryBackend(Backend):
|
||||
"""
|
||||
Simple in-memory backend that should be mostly used for testing purposes
|
||||
"""
|
||||
_storage = {}
|
||||
_lock = Lock()
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get(self, key):
|
||||
with self._lock:
|
||||
return self._storage.get(key)
|
||||
|
||||
def mget(self, keys):
|
||||
if not keys:
|
||||
return
|
||||
result = []
|
||||
with self._lock:
|
||||
for key in keys:
|
||||
value = self._storage.get(key)
|
||||
if value is not None:
|
||||
result.append((key, value))
|
||||
return result
|
||||
|
||||
def set(self, key, value):
|
||||
with self._lock:
|
||||
old_value = self._storage.get(key)
|
||||
self._storage[key] = value
|
||||
signals.config_updated.send(
|
||||
sender=config, key=key, old_value=old_value, new_value=value
|
||||
)
|
||||
|
|
@ -144,3 +144,15 @@ configured cache backend to enable this feature, e.g. "default"::
|
|||
setting to ``None``.
|
||||
|
||||
.. _django-picklefield: http://pypi.python.org/pypi/django-picklefield/
|
||||
|
||||
Memory
|
||||
------
|
||||
|
||||
The configuration values are stored in a memory and do not persist between process
|
||||
restarts. In order to use this backend you must set the ``CONSTANCE_BACKEND``
|
||||
Django setting to::
|
||||
|
||||
CONSTANCE_BACKEND = 'constance.backends.memory.MemoryBackend'
|
||||
|
||||
The main purpose of this one is to be used mostly for testing/developing means,
|
||||
so make sure you intentionally use it on production environments.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ method level and also as a
|
|||
|
||||
|
||||
Pytest usage
|
||||
~~~~~
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Django-constance provides pytest plugin that adds marker
|
||||
:class:`@pytest.mark.override_config()`. It handles config override for
|
||||
|
|
@ -108,3 +108,16 @@ Any scope, auto-used fixture alternative can also be implemented like this
|
|||
with override_config(API_URL="/awesome/url/"):
|
||||
yield
|
||||
|
||||
|
||||
Memory backend
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
If you don't want to rely on any external services such as Redis or database when
|
||||
running your unittests you can select :class:`MemoryBackend` for a test Django settings file
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
CONSTANCE_BACKEND = 'constance.backends.memory.MemoryBackend'
|
||||
|
||||
It will provide simple thread-safe backend which will reset to default values after each
|
||||
test run.
|
||||
|
|
|
|||
0
test_threads.py
Normal file
0
test_threads.py
Normal file
0
tests/backends/__init__.py
Normal file
0
tests/backends/__init__.py
Normal file
18
tests/backends/test_memory.py
Normal file
18
tests/backends/test_memory.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from constance import settings
|
||||
|
||||
from tests.storage import StorageTestsMixin
|
||||
|
||||
|
||||
class TestMemory(StorageTestsMixin, TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.old_backend = settings.BACKEND
|
||||
settings.BACKEND = 'constance.backends.memory.MemoryBackend'
|
||||
super().setUp()
|
||||
self.config._backend._storage = {}
|
||||
|
||||
def tearDown(self):
|
||||
self.config._backend._storage = {}
|
||||
settings.BACKEND = self.old_backend
|
||||
|
|
@ -3,9 +3,4 @@ class Connection(dict):
|
|||
self[key] = value
|
||||
|
||||
def mget(self, keys):
|
||||
values = []
|
||||
for key in keys:
|
||||
value = self.get(key, None)
|
||||
if value is not None:
|
||||
values.append(value)
|
||||
return values
|
||||
return [self.get(key) for key in keys]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from datetime import datetime, date, time, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
from constance import settings
|
||||
from constance.base import Config
|
||||
|
||||
|
||||
|
|
@ -77,3 +78,18 @@ class StorageTestsMixin:
|
|||
self.assertEqual(self.config.DATE_VALUE, date(2001, 12, 20))
|
||||
self.assertEqual(self.config.TIME_VALUE, time(1, 59, 0))
|
||||
self.assertEqual(self.config.TIMEDELTA_VALUE, timedelta(days=1, hours=2, minutes=3))
|
||||
|
||||
def test_backend_retrieves_multiple_values(self):
|
||||
# Check corner cases such as falsy values
|
||||
self.config.INT_VALUE = 0
|
||||
self.config.BOOL_VALUE = False
|
||||
self.config.STRING_VALUE = ''
|
||||
|
||||
values = dict(self.config._backend.mget(settings.CONFIG))
|
||||
self.assertEqual(values['INT_VALUE'], 0)
|
||||
self.assertEqual(values['BOOL_VALUE'], False)
|
||||
self.assertEqual(values['STRING_VALUE'], '')
|
||||
|
||||
def test_backend_does_not_return_none_values(self):
|
||||
result = dict(self.config._backend.mget(settings.CONFIG))
|
||||
self.assertEqual(result, {})
|
||||
|
|
|
|||
Loading…
Reference in a new issue