Browse Source

Reorganizes the app and app.base modules

Ask Solem 13 years ago
parent
commit
37c3240e61

+ 20 - 239
celery/app/__init__.py

@@ -9,253 +9,40 @@
     :license: BSD, see LICENSE for more details.
 
 """
-
 from __future__ import absolute_import
 
 import os
 
-from ..local import PromiseProxy
-from ..utils import cached_property
-from ..utils.imports import instantiate
-
-from . import annotations
-from . import base
-from .state import _tls
-from .state import current_task  # noqa
-
-
-class AppPickler(object):
-    """Default application pickler/unpickler."""
-
-    def __call__(self, cls, *args):
-        kwargs = self.build_kwargs(*args)
-        app = self.construct(cls, **kwargs)
-        self.prepare(app, **kwargs)
-        return app
-
-    def prepare(self, app, **kwargs):
-        app.conf.update(kwargs["changes"])
-
-    def build_kwargs(self, *args):
-        return self.build_standard_kwargs(*args)
-
-    def build_standard_kwargs(self, main, changes, loader, backend, amqp,
-            events, log, control, accept_magic_kwargs):
-        return dict(main=main, loader=loader, backend=backend, amqp=amqp,
-                    changes=changes, events=events, log=log, control=control,
-                    set_as_current=False,
-                    accept_magic_kwargs=accept_magic_kwargs)
-
-    def construct(self, cls, **kwargs):
-        return cls(**kwargs)
-
-
-def _unpickle_app(cls, pickler, *args):
-    return pickler()(cls, *args)
-
-
-class App(base.BaseApp):
-    """Celery Application.
-
-    :param main: Name of the main module if running as `__main__`.
-    :keyword loader: The loader class, or the name of the loader class to use.
-                     Default is :class:`celery.loaders.app.AppLoader`.
-    :keyword backend: The result store backend class, or the name of the
-                      backend class to use. Default is the value of the
-                      :setting:`CELERY_RESULT_BACKEND` setting.
-    :keyword amqp: AMQP object or class name.
-    :keyword events: Events object or class name.
-    :keyword log: Log object or class name.
-    :keyword control: Control object or class name.
-    :keyword set_as_current:  Make this the global current app.
-
-    """
-    Pickler = AppPickler
-
-    def set_current(self):
-        """Make this the current app for this thread."""
-        _tls.current_app = self
-
-    def on_init(self):
-        if self.set_as_current:
-            self.set_current()
-
-    def create_task_cls(self):
-        """Creates a base task class using default configuration
-        taken from this app."""
-        from .task import BaseTask
-
-        class Task(BaseTask):
-            app = self
-            abstract = True
-
-        Task.__doc__ = BaseTask.__doc__
-        Task.bind(self)
-
-        return Task
-
-    def Worker(self, **kwargs):
-        """Create new :class:`~celery.apps.worker.Worker` instance."""
-        return instantiate("celery.apps.worker:Worker", app=self, **kwargs)
-
-    def WorkController(self, **kwargs):
-        return instantiate("celery.worker:WorkController", app=self, **kwargs)
-
-    def Beat(self, **kwargs):
-        """Create new :class:`~celery.apps.beat.Beat` instance."""
-        return instantiate("celery.apps.beat:Beat", app=self, **kwargs)
-
-    def TaskSet(self, *args, **kwargs):
-        """Create new :class:`~celery.task.sets.TaskSet`."""
-        return instantiate("celery.task.sets:TaskSet",
-                           app=self, *args, **kwargs)
-
-    def start(self, argv=None):
-        """Run :program:`celery` using `argv`.  Uses :data:`sys.argv`
-        if `argv` is not specified."""
-        return instantiate("celery.bin.celery:CeleryCommand", app=self) \
-                    .execute_from_commandline(argv)
-
-    def worker_main(self, argv=None):
-        """Run :program:`celeryd` using `argv`.  Uses :data:`sys.argv`
-        if `argv` is not specified."""
-        return instantiate("celery.bin.celeryd:WorkerCommand", app=self) \
-                    .execute_from_commandline(argv)
-
-    def task(self, *args, **options):
-        """Decorator to create a task class out of any callable.
-
-        **Examples:**
-
-        .. code-block:: python
-
-            @task()
-            def refresh_feed(url):
-                return Feed.objects.get(url=url).refresh()
-
-        with setting extra options and using retry.
+from . import state
+from .base import App, AppPickler             # noqa
 
-        .. code-block:: python
-
-            from celery.task import current
-
-            @task(exchange="feeds")
-            def refresh_feed(url):
-                try:
-                return Feed.objects.get(url=url).refresh()
-            except socket.error, exc:
-                current.retry(exc=exc)
-
-        Calling the resulting task::
-
-            >>> refresh_feed("http://example.com/rss") # Regular
-            <Feed: http://example.com/rss>
-            >>> refresh_feed.delay("http://example.com/rss") # Async
-            <AsyncResult: 8998d0f4-da0b-4669-ba03-d5ab5ac6ad5d>
-
-        .. admonition:: App Binding
-
-            For custom apps the task decorator returns proxy
-            objects, so that the act of creating the task is not performed
-            until the task is used or the task registry is accessed.
-
-            If you are depending on binding to be deferred, then you must
-            not access any attributes on the returned object until the
-            application is fully set up (finalized).
-
-        """
-
-        def inner_create_task_cls(**options):
-
-            def _create_task_cls(fun):
-                if self.accept_magic_kwargs:  # compat mode
-                    return self._task_from_fun(fun, **options)
-
-                # return a proxy object that is only evaluated when first used
-                promise = PromiseProxy(self._task_from_fun, (fun, ), options)
-                self._pending.append(promise)
-                return promise
-
-            return _create_task_cls
-
-        if len(args) == 1 and callable(args[0]):
-            return inner_create_task_cls(**options)(*args)
-        return inner_create_task_cls(**options)
-
-    def _task_from_fun(self, fun, **options):
-        base = options.pop("base", None) or self.Task
-
-        T = type(fun.__name__, (base, ), dict({
-                "app": self,
-                "accept_magic_kwargs": False,
-                "run": staticmethod(fun),
-                "__doc__": fun.__doc__,
-                "__module__": fun.__module__}, **options))()
-        return self._tasks[T.name]  # return global instance.
-
-    def annotate_task(self, task):
-        if self.annotations:
-            match = annotations._first_match(self.annotations, task)
-            for attr, value in (match or {}).iteritems():
-                setattr(task, attr, value)
-            match_any = annotations._first_match_any(self.annotations)
-            for attr, value in (match_any or {}).iteritems():
-                setattr(task, attr, value)
-
-    @cached_property
-    def Task(self):
-        """Default Task base class for this application."""
-        return self.create_task_cls()
-
-    @cached_property
-    def annotations(self):
-        return annotations.prepare(self.conf.CELERY_ANNOTATIONS)
-
-    def __repr__(self):
-        return "<Celery: %s:0x%x>" % (self.main or "__main__", id(self), )
-
-    def __reduce__(self):
-        # Reduce only pickles the configuration changes,
-        # so the default configuration doesn't have to be passed
-        # between processes.
-        return (_unpickle_app, (self.__class__, self.Pickler)
-                              + self.__reduce_args__())
-
-    def __reduce_args__(self):
-        return (self.main,
-                self.conf.changes,
-                self.loader_cls,
-                self.backend_cls,
-                self.amqp_cls,
-                self.events_cls,
-                self.log_cls,
-                self.control_cls,
-                self.accept_magic_kwargs)
+set_default_app = state.set_default_app
+current_app = state.current_app
+current_task = state.current_task
 
+#: Returns the app provided or the default app if none.
+#:
+#: The environment variable :envvar:`CELERY_TRACE_APP` is used to
+#: trace app leaks.  When enabled an exception is raised if there
+#: is no active app.
+app_or_default = None
 
 #: The "default" loader is the default loader used by old applications.
 default_loader = os.environ.get("CELERY_LOADER") or "default"
 
 #: Global fallback app instance.
-default_app = App("default", loader=default_loader,
-                             set_as_current=False,
-                             accept_magic_kwargs=True)
+set_default_app(App("default", loader=default_loader,
+                               set_as_current=False,
+                               accept_magic_kwargs=True))
 
 
-def current_app():
-    return getattr(_tls, "current_app", None) or default_app
+def bugreport():
+    return current_app().bugreport()
 
 
 def _app_or_default(app=None):
-    """Returns the app provided or the default app if none.
-
-    The environment variable :envvar:`CELERY_TRACE_APP` is used to
-    trace app leaks.  When enabled an exception is raised if there
-    is no active app.
-
-    """
     if app is None:
-        return getattr(_tls, "current_app", None) or default_app
+        return current_app()
     return app
 
 
@@ -271,10 +58,9 @@ def _app_or_default_trace(app=None):  # pragma: no cover
             raise Exception("DEFAULT APP")
         print("-- RETURNING TO DEFAULT APP --")      # noqa+
         print_stack()
-        return default_app
+        return state.default_app
     return app
 
-
 def enable_trace():
     global app_or_default
     app_or_default = _app_or_default_trace
@@ -284,12 +70,7 @@ def disable_trace():
     global app_or_default
     app_or_default = _app_or_default
 
-
-
-def bugreport():
-    return current_app().bugreport()
-
-
-app_or_default = _app_or_default
 if os.environ.get("CELERY_TRACE_APP"):  # pragma: no cover
     enable_trace()
+else:
+    disable_trace()

+ 171 - 81
celery/app/base.py

@@ -12,10 +12,6 @@
 from __future__ import absolute_import
 from __future__ import with_statement
 
-import celery
-import kombu
-import os
-import platform as _platform
 import warnings
 
 from collections import deque
@@ -25,82 +21,40 @@ from functools import wraps
 
 from kombu.clocks import LamportClock
 
-from .. import datastructures
 from .. import platforms
 from ..backends import get_backend_by_url
 from ..exceptions import AlwaysEagerIgnored
 from ..loaders import get_loader_cls
-from ..local import maybe_evaluate
-from ..utils import cached_property, lpmerge, register_after_fork
+from ..local import PromiseProxy, maybe_evaluate
+from ..utils import cached_property, register_after_fork
 from ..utils.functional import first
-from ..utils.imports import instantiate, qualname
-from ..utils.text import pretty
+from ..utils.imports import instantiate
 
+from . import annotations
 from .builtins import load_builtin_tasks
-from .defaults import DEFAULTS, find_deprecated_settings, find
+from .defaults import DEFAULTS, find_deprecated_settings
+from .state import _tls
+from .utils import AppPickler, Settings, bugreport, _unpickle_app
 
-import kombu
-if kombu.VERSION < (2, 0):
-    raise ImportError("Celery requires Kombu version 1.1.0 or higher.")
 
-SETTINGS_INFO = """%s %s"""
+class App(object):
+    """Celery Application.
 
-BUGREPORT_INFO = """
-software -> celery:%(celery_v)s kombu:%(kombu_v)s py:%(py_v)s
-platform -> system:%(system)s arch:%(arch)s imp:%(py_i)s
-loader   -> %(loader)s
-settings -> transport:%(transport)s results:%(results)s
+    :param main: Name of the main module if running as `__main__`.
+    :keyword loader: The loader class, or the name of the loader class to use.
+                     Default is :class:`celery.loaders.app.AppLoader`.
+    :keyword backend: The result store backend class, or the name of the
+                      backend class to use. Default is the value of the
+                      :setting:`CELERY_RESULT_BACKEND` setting.
+    :keyword amqp: AMQP object or class name.
+    :keyword events: Events object or class name.
+    :keyword log: Log object or class name.
+    :keyword control: Control object or class name.
+    :keyword set_as_current:  Make this the global current app.
 
-%(human_settings)s
+    """
+    Pickler = AppPickler
 
-"""
-
-
-class Settings(datastructures.ConfigurationView):
-
-    @property
-    def CELERY_RESULT_BACKEND(self):
-        """Resolves deprecated alias ``CELERY_BACKEND``."""
-        return self.first("CELERY_RESULT_BACKEND", "CELERY_BACKEND")
-
-    @property
-    def BROKER_TRANSPORT(self):
-        """Resolves compat aliases :setting:`BROKER_BACKEND`
-        and :setting:`CARROT_BACKEND`."""
-        return self.first("BROKER_TRANSPORT",
-                          "BROKER_BACKEND", "CARROT_BACKEND")
-
-    @property
-    def BROKER_BACKEND(self):
-        """Deprecated compat alias to :attr:`BROKER_TRANSPORT`."""
-        return self.BROKER_TRANSPORT
-
-    @property
-    def BROKER_HOST(self):
-        return (os.environ.get("CELERY_BROKER_URL") or
-                self.first("BROKER_URL", "BROKER_HOST"))
-
-    def without_defaults(self):
-        # the last stash is the default settings, so just skip that
-        return Settings({}, self._order[:-1])
-
-    def find_value_for_key(self, name, namespace="celery"):
-        return self.get_by_parts(*self.find_option(name, namespace)[:-1])
-
-    def find_option(self, name, namespace="celery"):
-        return find(name, namespace)
-
-    def get_by_parts(self, *parts):
-        return self["_".join(filter(None, parts))]
-
-    def humanize(self):
-        return "\n".join(SETTINGS_INFO % (key + ':', pretty(value, width=50))
-                    for key, value in self.without_defaults().iteritems())
-
-
-
-class BaseApp(object):
-    """Base class for apps."""
     SYSTEM = platforms.SYSTEM
     IS_OSX, IS_WINDOWS = platforms.IS_OSX, platforms.IS_WINDOWS
 
@@ -139,12 +93,157 @@ class BaseApp(object):
         if broker:
             self._preconf["BROKER_URL"] = broker
 
+        if self.set_as_current:
+            self.set_current()
         self.on_init()
 
+    def set_current(self):
+        """Make this the current app for this thread."""
+        _tls.current_app = self
+
     def on_init(self):
-        """Called at the end of the constructor."""
         pass
 
+    def create_task_cls(self):
+        """Creates a base task class using default configuration
+        taken from this app."""
+        from .task import BaseTask
+
+        class Task(BaseTask):
+            app = self
+            abstract = True
+
+        Task.__doc__ = BaseTask.__doc__
+        Task.bind(self)
+
+        return Task
+
+    def Worker(self, **kwargs):
+        """Create new :class:`~celery.apps.worker.Worker` instance."""
+        return instantiate("celery.apps.worker:Worker", app=self, **kwargs)
+
+    def WorkController(self, **kwargs):
+        return instantiate("celery.worker:WorkController", app=self, **kwargs)
+
+    def Beat(self, **kwargs):
+        """Create new :class:`~celery.apps.beat.Beat` instance."""
+        return instantiate("celery.apps.beat:Beat", app=self, **kwargs)
+
+    def TaskSet(self, *args, **kwargs):
+        """Create new :class:`~celery.task.sets.TaskSet`."""
+        return instantiate("celery.task.sets:TaskSet",
+                           app=self, *args, **kwargs)
+
+    def start(self, argv=None):
+        """Run :program:`celery` using `argv`.  Uses :data:`sys.argv`
+        if `argv` is not specified."""
+        return instantiate("celery.bin.celery:CeleryCommand", app=self) \
+                    .execute_from_commandline(argv)
+
+    def worker_main(self, argv=None):
+        """Run :program:`celeryd` using `argv`.  Uses :data:`sys.argv`
+        if `argv` is not specified."""
+        return instantiate("celery.bin.celeryd:WorkerCommand", app=self) \
+                    .execute_from_commandline(argv)
+
+    def task(self, *args, **options):
+        """Decorator to create a task class out of any callable.
+
+        **Examples:**
+
+        .. code-block:: python
+
+            @task
+            def refresh_feed(url):
+                return ...
+
+        with setting extra options:
+
+        .. code-block:: python
+
+            @task(exchange="feeds")
+            def refresh_feed(url):
+                return ...
+
+        .. admonition:: App Binding
+
+            For custom apps the task decorator returns proxy
+            objects, so that the act of creating the task is not performed
+            until the task is used or the task registry is accessed.
+
+            If you are depending on binding to be deferred, then you must
+            not access any attributes on the returned object until the
+            application is fully set up (finalized).
+
+        """
+
+        def inner_create_task_cls(**options):
+
+            def _create_task_cls(fun):
+                if self.accept_magic_kwargs:  # compat mode
+                    return self._task_from_fun(fun, **options)
+
+                # return a proxy object that is only evaluated when first used
+                promise = PromiseProxy(self._task_from_fun, (fun, ), options)
+                self._pending.append(promise)
+                return promise
+
+            return _create_task_cls
+
+        if len(args) == 1 and callable(args[0]):
+            return inner_create_task_cls(**options)(*args)
+        return inner_create_task_cls(**options)
+
+    def _task_from_fun(self, fun, **options):
+        base = options.pop("base", None) or self.Task
+
+        T = type(fun.__name__, (base, ), dict({
+                "app": self,
+                "accept_magic_kwargs": False,
+                "run": staticmethod(fun),
+                "__doc__": fun.__doc__,
+                "__module__": fun.__module__}, **options))()
+        return self._tasks[T.name]  # return global instance.
+
+    def annotate_task(self, task):
+        if self.annotations:
+            match = annotations._first_match(self.annotations, task)
+            for attr, value in (match or {}).iteritems():
+                setattr(task, attr, value)
+            match_any = annotations._first_match_any(self.annotations)
+            for attr, value in (match_any or {}).iteritems():
+                setattr(task, attr, value)
+
+    @cached_property
+    def Task(self):
+        """Default Task base class for this application."""
+        return self.create_task_cls()
+
+    @cached_property
+    def annotations(self):
+        return annotations.prepare(self.conf.CELERY_ANNOTATIONS)
+
+    def __repr__(self):
+        return "<Celery: %s:0x%x>" % (self.main or "__main__", id(self), )
+
+    def __reduce__(self):
+        # Reduce only pickles the configuration changes,
+        # so the default configuration doesn't have to be passed
+        # between processes.
+        return (_unpickle_app, (self.__class__, self.Pickler)
+                              + self.__reduce_args__())
+
+    def __reduce_args__(self):
+        return (self.main,
+                self.conf.changes,
+                self.loader_cls,
+                self.backend_cls,
+                self.amqp_cls,
+                self.events_cls,
+                self.log_cls,
+                self.control_cls,
+                self.accept_magic_kwargs)
+
     def finalize(self):
         if not self.finalized:
             load_builtin_tasks(self)
@@ -340,6 +439,9 @@ class BaseApp(object):
         `*values` are true."""
         return first(None, values) or self.conf.get(default_key)
 
+    def bugreport(self):
+        return bugreport(self)
+
     def _get_backend(self):
         backend, url = get_backend_by_url(
                 self.backend_cls or self.conf.CELERY_RESULT_BACKEND,
@@ -355,18 +457,6 @@ class BaseApp(object):
             self._pool.force_close_all()
             self._pool = None
 
-    def bugreport(self):
-        return BUGREPORT_INFO % {"system": _platform.system(),
-                                 "arch": _platform.architecture(),
-                                 "py_i": platforms.pyimplementation(),
-                                 "celery_v": celery.__version__,
-                                 "kombu_v": kombu.__version__,
-                                 "py_v": _platform.python_version(),
-                                 "transport": self.conf.BROKER_TRANSPORT,
-                                 "results": self.conf.CELERY_RESULT_BACKEND,
-                                 "human_settings": self.conf.humanize(),
-                                 "loader": qualname(self.loader.__class__)}
-
     @property
     def pool(self):
         if self._pool is None:

+ 51 - 0
celery/app/state.py

@@ -14,5 +14,56 @@ class _TLS(threading.local):
 _tls = _TLS()
 
 
+default_app = None
+
+
+def set_default_app(app):
+    global default_app
+    default_app = app
+
+
+def current_app():
+    return getattr(_tls, "current_app", None) or default_app
+
+
 def current_task():
     return getattr(_tls, "current_task", None)
+
+
+def _app_or_default(app=None):
+    """Returns the app provided or the default app if none.
+
+    The environment variable :envvar:`CELERY_TRACE_APP` is used to
+    trace app leaks.  When enabled an exception is raised if there
+    is no active app.
+
+    """
+    if app is None:
+        return getattr(_tls, "current_app", None) or default_app
+    return app
+
+
+def _app_or_default_trace(app=None):  # pragma: no cover
+    from traceback import print_stack
+    from multiprocessing import current_process
+    if app is None:
+        if getattr(_tls, "current_app", None):
+            print("-- RETURNING TO CURRENT APP --")  # noqa+
+            print_stack()
+            return _tls.current_app
+        if current_process()._name == "MainProcess":
+            raise Exception("DEFAULT APP")
+        print("-- RETURNING TO DEFAULT APP --")      # noqa+
+        print_stack()
+        return default_app
+    return app
+
+app_or_default = None
+def enable_trace():
+    global app_or_default
+    app_or_default = _app_or_default_trace
+
+
+def disable_trace():
+    global app_or_default
+    app_or_default = _app_or_default

+ 2 - 2
celery/app/task/__init__.py

@@ -828,12 +828,12 @@ class BaseTask(object):
         """`repr(task)`"""
         return "<@task: %s>" % (self.name, )
 
-    def subtask(cls, *args, **kwargs):
+    def subtask(self, *args, **kwargs):
         """Returns :class:`~celery.task.sets.subtask` object for
         this task, wrapping arguments and execution options
         for a single task invocation."""
         from ...task.sets import subtask
-        return subtask(cls, *args, **kwargs)
+        return subtask(self, *args, **kwargs)
 
     @property
     def __name__(self):

+ 110 - 0
celery/app/utils.py

@@ -0,0 +1,110 @@
+from __future__ import absolute_import
+
+import celery
+import kombu
+import os
+import platform as _platform
+
+from .. import datastructures
+from .. import platforms
+from ..utils.text import pretty
+from ..utils.imports import qualname
+
+from .defaults import find
+
+SETTINGS_INFO = """%s %s"""
+
+BUGREPORT_INFO = """
+software -> celery:%(celery_v)s kombu:%(kombu_v)s py:%(py_v)s
+platform -> system:%(system)s arch:%(arch)s imp:%(py_i)s
+loader   -> %(loader)s
+settings -> transport:%(transport)s results:%(results)s
+
+%(human_settings)s
+
+"""
+
+
+class Settings(datastructures.ConfigurationView):
+
+    @property
+    def CELERY_RESULT_BACKEND(self):
+        """Resolves deprecated alias ``CELERY_BACKEND``."""
+        return self.first("CELERY_RESULT_BACKEND", "CELERY_BACKEND")
+
+    @property
+    def BROKER_TRANSPORT(self):
+        """Resolves compat aliases :setting:`BROKER_BACKEND`
+        and :setting:`CARROT_BACKEND`."""
+        return self.first("BROKER_TRANSPORT",
+                          "BROKER_BACKEND", "CARROT_BACKEND")
+
+    @property
+    def BROKER_BACKEND(self):
+        """Deprecated compat alias to :attr:`BROKER_TRANSPORT`."""
+        return self.BROKER_TRANSPORT
+
+    @property
+    def BROKER_HOST(self):
+        return (os.environ.get("CELERY_BROKER_URL") or
+                self.first("BROKER_URL", "BROKER_HOST"))
+
+    def without_defaults(self):
+        # the last stash is the default settings, so just skip that
+        return Settings({}, self._order[:-1])
+
+    def find_value_for_key(self, name, namespace="celery"):
+        return self.get_by_parts(*self.find_option(name, namespace)[:-1])
+
+    def find_option(self, name, namespace="celery"):
+        return find(name, namespace)
+
+    def get_by_parts(self, *parts):
+        return self["_".join(filter(None, parts))]
+
+    def humanize(self):
+        return "\n".join(SETTINGS_INFO % (key + ':', pretty(value, width=50))
+                    for key, value in self.without_defaults().iteritems())
+
+
+class AppPickler(object):
+    """Default application pickler/unpickler."""
+
+    def __call__(self, cls, *args):
+        kwargs = self.build_kwargs(*args)
+        app = self.construct(cls, **kwargs)
+        self.prepare(app, **kwargs)
+        return app
+
+    def prepare(self, app, **kwargs):
+        app.conf.update(kwargs["changes"])
+
+    def build_kwargs(self, *args):
+        return self.build_standard_kwargs(*args)
+
+    def build_standard_kwargs(self, main, changes, loader, backend, amqp,
+            events, log, control, accept_magic_kwargs):
+        return dict(main=main, loader=loader, backend=backend, amqp=amqp,
+                    changes=changes, events=events, log=log, control=control,
+                    set_as_current=False,
+                    accept_magic_kwargs=accept_magic_kwargs)
+
+    def construct(self, cls, **kwargs):
+        return cls(**kwargs)
+
+
+def _unpickle_app(cls, pickler, *args):
+    return pickler()(cls, *args)
+
+
+def bugreport(app):
+    return BUGREPORT_INFO % {"system": _platform.system(),
+                            "arch": _platform.architecture(),
+                            "py_i": platforms.pyimplementation(),
+                            "celery_v": celery.__version__,
+                            "kombu_v": kombu.__version__,
+                            "py_v": _platform.python_version(),
+                            "transport": app.conf.BROKER_TRANSPORT,
+                            "results": app.conf.CELERY_RESULT_BACKEND,
+                            "human_settings": app.conf.humanize(),
+                            "loader": qualname(app.loader.__class__)}

+ 1 - 2
celery/execute/trace.py

@@ -25,9 +25,9 @@ import traceback
 
 from warnings import warn
 
-from .. import app as app_module
 from .. import current_app
 from .. import states, signals
+from ..app.state import _tls
 from ..app.task import BaseTask
 from ..datastructures import ExceptionInfo
 from ..exceptions import RetryTaskError
@@ -148,7 +148,6 @@ def build_tracer(name, task, loader=None, hostname=None, store_errors=True,
     task_on_success = task.on_success
     task_after_return = task.after_return
     task_request = task.request
-    _tls = app_module._tls
 
     store_result = backend.store_result
     backend_cleanup = backend.process_cleanup

+ 0 - 23
celery/tests/test_app/__init__.py

@@ -9,7 +9,6 @@ from mock import Mock
 from celery import Celery
 from celery import app as _app
 from celery.app import defaults
-from celery.app.base import BaseApp
 from celery.loaders.base import BaseLoader
 from celery.platforms import pyimplementation
 from celery.utils.serialization import pickle
@@ -254,12 +253,6 @@ class test_App(Case):
         self.assertTrue(x)
 
 
-class test_BaseApp(Case):
-
-    def test_on_init(self):
-        BaseApp()
-
-
 class test_defaults(Case):
 
     def test_str_to_bool(self):
@@ -283,22 +276,6 @@ class test_debugging_utils(Case):
             _app.disable_trace()
 
 
-class test_compilation(Case):
-    _clean = ("celery.app.base", )
-
-    def setUp(self):
-        self._prev = dict((k, sys.modules.pop(k, None)) for k in self._clean)
-
-    def tearDown(self):
-        sys.modules.update(self._prev)
-
-    def test_kombu_version_check(self):
-        import kombu
-        kombu.VERSION = (0, 9, 9)
-        with self.assertRaises(ImportError):
-            __import__("celery.app.base")
-
-
 class test_pyimplementation(Case):
 
     def test_platform_python_implementation(self):

+ 1 - 1
celery/tests/test_worker/__init__.py

@@ -742,7 +742,7 @@ class test_WorkController(AppCase):
     def test_process_initializer(self, set_mp_process_title, _signals):
         from celery import Celery
         from celery import signals
-        from celery.app import _tls
+        from celery.app.state import _tls
         from celery.concurrency.processes import process_initializer
         from celery.concurrency.processes import (WORKER_SIGRESET,
                                                   WORKER_SIGIGNORE)