diff --git a/constance/backends/__init__.py b/constance/backends/__init__.py index 3d5f8b6..69e0fe9 100644 --- a/constance/backends/__init__.py +++ b/constance/backends/__init__.py @@ -24,16 +24,18 @@ class Backend(ABC): @abstractmethod def mget(self, keys): """ - Get the keys from the backend store and return a list of the values. - Return an empty list if not found. + Get the keys from the backend store and return a dict mapping + each found key to its value. Return an empty dict if no keys + are provided or none are found. """ ... @abstractmethod async def amget(self, keys): """ - Get the keys from the backend store and return a list of the values. - Return an empty list if not found. + Get the keys from the backend store and return a dict mapping + each found key to its value. Return an empty dict if no keys + are provided or none are found. """ ... diff --git a/constance/backends/database.py b/constance/backends/database.py index 9849266..86d876a 100644 --- a/constance/backends/database.py +++ b/constance/backends/database.py @@ -54,20 +54,22 @@ class DatabaseBackend(Backend): if self._cache.get(full_cachekey): return autofill_values = {full_cachekey: 1} - for key, value in self.mget(settings.CONFIG): + for key, value in self.mget(settings.CONFIG).items(): autofill_values[self.add_prefix(key)] = value self._cache.set_many(autofill_values, timeout=self._autofill_timeout) def mget(self, keys): + result = {} if not keys: - return + return result keys = {self.add_prefix(key): key for key in keys} try: stored = self._model._default_manager.filter(key__in=keys) for const in stored: - yield keys[const.key], loads(const.value) + result[keys[const.key]] = loads(const.value) except (OperationalError, ProgrammingError): pass + return result def get(self, key): key = self.add_prefix(key) diff --git a/constance/backends/memory.py b/constance/backends/memory.py index c6d9c0e..b09d964 100644 --- a/constance/backends/memory.py +++ b/constance/backends/memory.py @@ -25,14 +25,9 @@ class MemoryBackend(Backend): def mget(self, keys): if not keys: - return None - result = [] + return {} with self._lock: - for key in keys: - value = self._storage.get(key) - if value is not None: - result.append((key, value)) - return result + return {key: self._storage[key] for key in keys if key in self._storage} async def amget(self, keys): if not keys: diff --git a/constance/backends/redisd.py b/constance/backends/redisd.py index 0870257..0add462 100644 --- a/constance/backends/redisd.py +++ b/constance/backends/redisd.py @@ -73,11 +73,9 @@ class RedisBackend(Backend): def mget(self, keys): if not keys: - return + return {} prefixed_keys = [self.add_prefix(key) for key in keys] - for key, value in zip(keys, self._rd.mget(prefixed_keys)): - if value: - yield key, loads(value) + return {key: loads(value) for key, value in zip(keys, self._rd.mget(prefixed_keys)) if value} async def amget(self, keys): if not keys: @@ -177,11 +175,13 @@ class CachingRedisBackend(RedisBackend): def mget(self, keys): if not keys: - return + return {} + result = {} for key in keys: value = self.get(key) if value is not None: - yield key, value + result[key] = value + return result async def amget(self, keys): if not keys: diff --git a/constance/utils.py b/constance/utils.py index 0fabe16..32bf7aa 100644 --- a/constance/utils.py +++ b/constance/utils.py @@ -19,7 +19,7 @@ def get_values(): # First load a mapping between config name and default value default_initial = ((name, options[0]) for name, options in settings.CONFIG.items()) # Then update the mapping with actually values from the backend - return dict(default_initial, **dict(config._backend.mget(settings.CONFIG))) + return dict(default_initial, **config._backend.mget(settings.CONFIG)) async def aget_values(): @@ -52,7 +52,7 @@ def get_values_for_keys(keys): raise AttributeError(f'"{", ".join(missing_keys)}" keys not found in configuration.') # Merge default values and backend values, prioritizing backend values - return dict(default_initial, **dict(config._backend.mget(keys))) + return dict(default_initial, **config._backend.mget(keys)) async def aget_values_for_keys(keys): diff --git a/tests/backends/test_memory.py b/tests/backends/test_memory.py index d8bbfff..b61d237 100644 --- a/tests/backends/test_memory.py +++ b/tests/backends/test_memory.py @@ -19,7 +19,7 @@ class TestMemory(StorageTestsMixin, TestCase): def test_mget_empty_keys(self): result = self.config._backend.mget([]) - self.assertIsNone(result) + self.assertEqual(result, {}) class TestMemoryAsync(TransactionTestCase): diff --git a/tests/backends/test_redis.py b/tests/backends/test_redis.py index bbc1a7e..d250c66 100644 --- a/tests/backends/test_redis.py +++ b/tests/backends/test_redis.py @@ -24,18 +24,16 @@ class TestRedis(StorageTestsMixin, TestCase): settings.BACKEND = self.old_backend def test_mget_empty_keys(self): - # Test that mget returns None for empty keys - result = list(self.config._backend.mget([]) or []) - self.assertEqual(result, []) + result = self.config._backend.mget([]) + self.assertEqual(result, {}) class TestCachingRedis(TestRedis): _BACKEND = "constance.backends.redisd.CachingRedisBackend" def test_mget_empty_keys(self): - # Test that mget returns None for empty keys - result = list(self.config._backend.mget([]) or []) - self.assertEqual(result, []) + result = self.config._backend.mget([]) + self.assertEqual(result, {}) class TestRedisAsync(TransactionTestCase): diff --git a/tests/storage.py b/tests/storage.py index 932f252..3b20971 100644 --- a/tests/storage.py +++ b/tests/storage.py @@ -98,11 +98,11 @@ class StorageTestsMixin: self.config.BOOL_VALUE = False self.config.STRING_VALUE = "" - values = dict(self.config._backend.mget(settings.CONFIG)) + values = 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)) + result = self.config._backend.mget(settings.CONFIG) self.assertEqual(result, {})