Browse Source

New autofinalize setting for apps

Ask Solem 11 years ago
parent
commit
79c46909c6
3 changed files with 37 additions and 3 deletions
  1. 9 3
      celery/app/base.py
  2. 25 0
      celery/tests/app/test_app.py
  3. 3 0
      docs/reference/celery.rst

+ 9 - 3
celery/app/base.py

@@ -94,7 +94,8 @@ class Celery(object):
                  amqp=None, events=None, log=None, control=None,
                  amqp=None, events=None, log=None, control=None,
                  set_as_current=True, accept_magic_kwargs=False,
                  set_as_current=True, accept_magic_kwargs=False,
                  tasks=None, broker=None, include=None, changes=None,
                  tasks=None, broker=None, include=None, changes=None,
-                 config_source=None, fixups=None, task_cls=None, **kwargs):
+                 config_source=None, fixups=None, task_cls=None,
+                 autofinalize=True, **kwargs):
         self.clock = LamportClock()
         self.clock = LamportClock()
         self.main = main
         self.main = main
         self.amqp_cls = amqp or self.amqp_cls
         self.amqp_cls = amqp or self.amqp_cls
@@ -109,6 +110,7 @@ class Celery(object):
         self.accept_magic_kwargs = accept_magic_kwargs
         self.accept_magic_kwargs = accept_magic_kwargs
         self.user_options = defaultdict(set)
         self.user_options = defaultdict(set)
         self.steps = defaultdict(set)
         self.steps = defaultdict(set)
+        self.autofinalize = autofinalize
 
 
         self.configured = False
         self.configured = False
         self._config_source = config_source
         self._config_source = config_source
@@ -220,6 +222,8 @@ class Celery(object):
         return inner_create_task_cls(**opts)
         return inner_create_task_cls(**opts)
 
 
     def _task_from_fun(self, fun, **options):
     def _task_from_fun(self, fun, **options):
+        if not self.finalized and not self.autofinalize:
+            raise RuntimeError('Contract breach: app not finalized')
         base = options.pop('base', None) or self.Task
         base = options.pop('base', None) or self.Task
         bind = options.pop('bind', False)
         bind = options.pop('bind', False)
 
 
@@ -233,9 +237,11 @@ class Celery(object):
         task = self._tasks[T.name]  # return global instance.
         task = self._tasks[T.name]  # return global instance.
         return task
         return task
 
 
-    def finalize(self):
+    def finalize(self, auto=False):
         with self._finalize_mutex:
         with self._finalize_mutex:
             if not self.finalized:
             if not self.finalized:
+                if auto and not self.autofinalize:
+                    raise RuntimeError('Contract breach: app not finalized')
                 self.finalized = True
                 self.finalized = True
                 load_shared_tasks(self)
                 load_shared_tasks(self)
 
 
@@ -626,7 +632,7 @@ class Celery(object):
 
 
     @cached_property
     @cached_property
     def tasks(self):
     def tasks(self):
-        self.finalize()
+        self.finalize(auto=True)
         return self._tasks
         return self._tasks
 
 
     @cached_property
     @cached_property

+ 25 - 0
celery/tests/app/test_app.py

@@ -81,6 +81,30 @@ class test_App(AppCase):
     def setup(self):
     def setup(self):
         self.app.add_defaults(test_config)
         self.app.add_defaults(test_config)
 
 
+    def test_task_autofinalize_disabled(self):
+        with self.Celery('xyzibari', autofinalize=False) as app:
+            @app.task
+            def ttafd():
+                return 42
+
+            with self.assertRaises(RuntimeError):
+                ttafd()
+
+        with self.Celery('xyzibari', autofinalize=False) as app:
+            @app.task
+            def ttafd2():
+                return 42
+
+            app.finalize()
+            self.assertEqual(ttafd2(), 42)
+
+    def test_registry_autofinalize_disabled(self):
+        with self.Celery('xyzibari', autofinalize=False) as app:
+            with self.assertRaises(RuntimeError):
+                app.tasks['celery.chain']
+            app.finalize()
+            self.assertTrue(app.tasks['celery.chain'])
+
     def test_task(self):
     def test_task(self):
         with self.Celery('foozibari') as app:
         with self.Celery('foozibari') as app:
 
 
@@ -391,6 +415,7 @@ class test_App(AppCase):
     def test_config_from_object__force(self):
     def test_config_from_object__force(self):
         self.app.config_from_object(ObjectConfig2(), force=True)
         self.app.config_from_object(ObjectConfig2(), force=True)
         self.assertTrue(self.app.loader._conf)
         self.assertTrue(self.app.loader._conf)
+
         self.assert_config2()
         self.assert_config2()
 
 
     def test_config_from_cmdline(self):
     def test_config_from_cmdline(self):

+ 3 - 0
docs/reference/celery.rst

@@ -48,6 +48,9 @@ and creating Celery applications.
     :keyword include: List of modules every worker should import.
     :keyword include: List of modules every worker should import.
     :keyword fixups: List of fixup plug-ins (see e.g.
     :keyword fixups: List of fixup plug-ins (see e.g.
         :mod:`celery.fixups.django`).
         :mod:`celery.fixups.django`).
+    :keyword autofinalize: If set to False a :exc:`RuntimeError`
+        will be raised if the task registry or tasks are used before
+        the app is finalized.
 
 
     .. attribute:: Celery.main
     .. attribute:: Celery.main