Quellcode durchsuchen

Fixes bug with configuration key prefix

Ask Solem vor 9 Jahren
Ursprung
Commit
7b87698992

+ 23 - 15
celery/datastructures.py

@@ -22,6 +22,7 @@ from kombu.utils.limits import TokenBucket  # noqa
 
 from celery.five import items
 from celery.utils.functional import LRUCache, first, uniq  # noqa
+from celery.utils.text import match_case
 
 try:
     from django.utils.functional import LazyObject, LazySettings
@@ -462,14 +463,17 @@ class ConfigurationView(AttributeDictMixin):
             defaults=defaults,
             key_t=key_t,
             _order=[changes] + defaults,
-            prefix=prefix,
+            prefix=prefix.rstrip('_') + '_' if prefix else prefix,
         )
 
+    def _to_keys(self, key):
+        prefix = self.prefix
+        if prefix:
+            pkey = prefix + key if not key.startswith(prefix) else key
+            return match_case(pkey, prefix), self._key(key)
+        return self._key(key),
+
     def _key(self, key):
-        if self.prefix:
-            key = self.prefix + key
-            if self.prefix.isupper():
-                key = key.upper()
         return self.key_t(key) if self.key_t is not None else key
 
     def add_defaults(self, d):
@@ -478,23 +482,27 @@ class ConfigurationView(AttributeDictMixin):
         self._order.insert(1, d)
 
     def __getitem__(self, key):
-        key = self._key(key)
-        for d in self._order:
-            try:
-                return d[key]
-            except KeyError:
-                pass
+        keys = self._to_keys(key)
+        for k in keys:
+            for d in self._order:
+                try:
+                    return d[k]
+                except KeyError:
+                    pass
+        if len(keys) > 1:
+            raise KeyError(
+                'Key not found: {0!r} (with prefix: {0!r})'.format(*keys))
         raise KeyError(key)
 
     def __setitem__(self, key, value):
         self.changes[self._key(key)] = value
 
     def first(self, *keys):
-        return first(None, (self.get(self._key(key)) for key in keys))
+        return first(None, (self.get(key) for key in keys))
 
     def get(self, key, default=None):
         try:
-            return self[self._key(key)]
+            return self[key]
         except KeyError:
             return default
 
@@ -511,8 +519,8 @@ class ConfigurationView(AttributeDictMixin):
         return self.changes.update(*args, **kwargs)
 
     def __contains__(self, key):
-        key = self._key(key)
-        return any(key in m for m in self._order)
+        keys = self._to_keys(key)
+        return any(any(k in m for k in keys) for m in self._order)
 
     def __bool__(self):
         return any(self._order)

+ 2 - 2
celery/tests/app/test_app.py

@@ -599,7 +599,7 @@ class test_App(AppCase):
             CELERY_TASK_ALWAYS_EAGER = 44
             CELERY_TASK_DEFAULT_DELIVERY_MODE = 301
 
-        self.app.config_from_object(Config(), namespace='CELERY_')
+        self.app.config_from_object(Config(), namespace='CELERY')
         self.assertEqual(self.app.conf.task_always_eager, 44)
 
     def test_config_from_object__namespace_lowercase(self):
@@ -608,7 +608,7 @@ class test_App(AppCase):
             celery_task_always_eager = 44
             celery_task_default_delivery_mode = 301
 
-        self.app.config_from_object(Config(), namespace='celery_')
+        self.app.config_from_object(Config(), namespace='celery')
         self.assertEqual(self.app.conf.task_always_eager, 44)
 
     def test_config_from_object__mixing_new_and_old(self):

+ 4 - 0
celery/utils/text.py

@@ -90,3 +90,7 @@ def pretty(value, width=80, nl_width=80, sep='\n', **kw):
         )
     else:
         return pformat(value, width=width, **kw)
+
+
+def match_case(s, other):
+    return s.upper() if other.isupper() else s.lower()

+ 1 - 1
docs/django/first-steps-with-django.rst

@@ -90,7 +90,7 @@ or execv:
 
 .. code-block:: python
 
-    app.config_from_object('django.conf:settings', namespace='CELERY_')
+    app.config_from_object('django.conf:settings', namespace='CELERY')
 
 Next, a common practice for reusable apps is to define all tasks
 in a separate ``tasks.py`` module, and Celery does have a way to

+ 1 - 1
examples/django/proj/celery.py

@@ -11,7 +11,7 @@ app = Celery('proj')
 
 # Using a string here means the worker will not have to
 # pickle the object when using Windows.
-app.config_from_object('django.conf:settings', namespace='CELERY_')
+app.config_from_object('django.conf:settings', namespace='CELERY')
 
 # load task modules from all registered Django app configs.
 app.autodiscover_tasks()