|
@@ -17,6 +17,16 @@ class MultiDictView(AttributeDictMixin):
|
|
|
* When getting a key, the dicts are searched in order.
|
|
|
* When setting a key, the key is added to the first dict.
|
|
|
|
|
|
+ >>> d1 = {"x": 3"}
|
|
|
+ >>> d2 = {"x": 1, "y": 2, "z": 3}
|
|
|
+ >>> x = MultiDictView([d1, d2])
|
|
|
+
|
|
|
+ >>> x["x"]
|
|
|
+ 3
|
|
|
+
|
|
|
+ >>> x["y"]
|
|
|
+ 2
|
|
|
+
|
|
|
"""
|
|
|
dicts = None
|
|
|
|
|
@@ -64,29 +74,63 @@ class MultiDictView(AttributeDictMixin):
|
|
|
|
|
|
|
|
|
class BaseApp(object):
|
|
|
- _amqp = None
|
|
|
- _backend = None
|
|
|
- _conf = None
|
|
|
- _control = None
|
|
|
- _loader = None
|
|
|
- _log = None
|
|
|
-
|
|
|
- def __init__(self, loader=None, backend_cls=None):
|
|
|
+ """Base class for apps."""
|
|
|
+
|
|
|
+ def __init__(self, loader=None, backend=None, set_as_current=True):
|
|
|
self.loader_cls = loader or "app"
|
|
|
- self.backend_cls = backend_cls
|
|
|
+ self.backend_cls = backend
|
|
|
+ self._amqp = None
|
|
|
+ self._backend = None
|
|
|
+ self._conf = None
|
|
|
+ self._control = None
|
|
|
+ self._loader = None
|
|
|
+ self._log = None
|
|
|
+ self.set_as_current = set_as_current
|
|
|
+ self.on_init()
|
|
|
+
|
|
|
+ def on_init(self):
|
|
|
+ """Called at the end of the constructor."""
|
|
|
+ pass
|
|
|
|
|
|
def config_from_object(self, obj, silent=False):
|
|
|
+ """Read configuration from object, where object is either
|
|
|
+ a real object, or the name of an object to import.
|
|
|
+
|
|
|
+ >>> celery.config_from_object("myapp.celeryconfig")
|
|
|
+
|
|
|
+ >>> from myapp import celeryconfig
|
|
|
+ >>> celery.config_from_object(celeryconfig)
|
|
|
+
|
|
|
+ """
|
|
|
self._conf = None
|
|
|
return self.loader.config_from_object(obj, silent=silent)
|
|
|
|
|
|
def config_from_envvar(self, variable_name, silent=False):
|
|
|
+ """Read configuration from environment variable.
|
|
|
+
|
|
|
+ The value of the environment variable must be the name
|
|
|
+ of an object to import.
|
|
|
+
|
|
|
+ >>> os.environ["CELERY_CONFIG_MODULE"] = "myapp.celeryconfig"
|
|
|
+ >>> celery.config_from_envvar("CELERY_CONFIG_MODULE")
|
|
|
+
|
|
|
+ """
|
|
|
self._conf = None
|
|
|
return self.loader.config_from_envvar(variable_name, silent=silent)
|
|
|
|
|
|
def config_from_cmdline(self, argv, namespace="celery"):
|
|
|
- return self.loader.config_from_cmdline(argv, namespace)
|
|
|
+ """Read configuration from argv.
|
|
|
+
|
|
|
+ The config
|
|
|
+
|
|
|
+ """
|
|
|
+ config = self.loader.cmdline_config_parser(argv, namespace)
|
|
|
+ for key, value in config.items():
|
|
|
+ self.conf[key] = value
|
|
|
|
|
|
def either(self, default_key, *values):
|
|
|
+ """Fallback to the value of a configuration key if none of the
|
|
|
+ ``*values`` are true."""
|
|
|
for value in values:
|
|
|
if value is not None:
|
|
|
return value
|
|
@@ -101,24 +145,15 @@ class BaseApp(object):
|
|
|
b[key] = value
|
|
|
return b
|
|
|
|
|
|
- def AsyncResult(self, task_id, backend=None):
|
|
|
- from celery.result import BaseAsyncResult
|
|
|
- return BaseAsyncResult(task_id, app=self,
|
|
|
- backend=backend or self.backend)
|
|
|
-
|
|
|
- def TaskSetResult(self, taskset_id, results, **kwargs):
|
|
|
- from celery.result import TaskSetResult
|
|
|
- return TaskSetResult(taskset_id, results, app=self)
|
|
|
-
|
|
|
def send_task(self, name, args=None, kwargs=None, countdown=None,
|
|
|
eta=None, task_id=None, publisher=None, connection=None,
|
|
|
connect_timeout=None, result_cls=None, expires=None,
|
|
|
**options):
|
|
|
"""Send task by name.
|
|
|
|
|
|
- Useful if you don't have access to the task class.
|
|
|
-
|
|
|
- :param name: Name of task to execute.
|
|
|
+ :param name: Name of task to execute (e.g. ``"tasks.add"``).
|
|
|
+ :keyword result_cls: Specify custom result class. Default is
|
|
|
+ using :meth:`AsyncResult`.
|
|
|
|
|
|
Supports the same arguments as
|
|
|
:meth:`~celery.task.base.BaseTask.apply_async`.
|
|
@@ -148,7 +183,22 @@ class BaseApp(object):
|
|
|
def broker_connection(self, hostname=None, userid=None,
|
|
|
password=None, virtual_host=None, port=None, ssl=None,
|
|
|
insist=None, connect_timeout=None, backend_cls=None):
|
|
|
- """Establish a connection to the message broker."""
|
|
|
+ """Establish a connection to the message broker.
|
|
|
+
|
|
|
+ :keyword hostname: defaults to the ``BROKER_HOST`` setting.
|
|
|
+ :keyword userid: defaults to the ``BROKER_USER`` setting.
|
|
|
+ :keyword password: defaults to the ``BROKER_PASSWORD`` setting.
|
|
|
+ :keyword virtual_host: defaults to the ``BROKER_VHOST`` setting.
|
|
|
+ :keyword port: defaults to the ``BROKER_PORT`` setting.
|
|
|
+ :keyword ssl: defaults to the ``BROKER_USE_SSL`` setting.
|
|
|
+ :keyword insist: defaults to the ``BROKER_INSIST`` setting.
|
|
|
+ :keyword connect_timeout: defaults to the
|
|
|
+ ``BROKER_CONNECTION_TIMEOUT`` setting.
|
|
|
+ :keyword backend_cls: defaults to the ``BROKER_BACKEND`` setting.
|
|
|
+
|
|
|
+ :returns :class:`carrot.connection.BrokerConnection`:
|
|
|
+
|
|
|
+ """
|
|
|
return self.amqp.BrokerConnection(
|
|
|
hostname or self.conf.BROKER_HOST,
|
|
|
userid or self.conf.BROKER_USER,
|
|
@@ -162,6 +212,14 @@ class BaseApp(object):
|
|
|
"BROKER_CONNECTION_TIMEOUT", connect_timeout))
|
|
|
|
|
|
def with_default_connection(self, fun):
|
|
|
+ """With any function accepting ``connection`` and ``connect_timeout``
|
|
|
+ keyword arguments, establishes a default connection if one is
|
|
|
+ not already passed to it.
|
|
|
+
|
|
|
+ Any automatically established connection will be closed after
|
|
|
+ the function returns.
|
|
|
+
|
|
|
+ """
|
|
|
|
|
|
@wraps(fun)
|
|
|
def _inner(*args, **kwargs):
|
|
@@ -178,6 +236,7 @@ class BaseApp(object):
|
|
|
return _inner
|
|
|
|
|
|
def pre_config_merge(self, c):
|
|
|
+ """Prepare configuration before it is merged with the defaults."""
|
|
|
if not c.get("CELERY_RESULT_BACKEND"):
|
|
|
rbackend = c.get("CELERY_BACKEND")
|
|
|
if rbackend:
|
|
@@ -189,11 +248,14 @@ class BaseApp(object):
|
|
|
return c
|
|
|
|
|
|
def post_config_merge(self, c):
|
|
|
+ """Prepare configuration after it has been merged with the
|
|
|
+ defaults."""
|
|
|
if not c.get("CELERY_QUEUES"):
|
|
|
- c["CELERY_QUEUES"] = {c.CELERY_DEFAULT_QUEUE: {
|
|
|
- "exchange": c.CELERY_DEFAULT_EXCHANGE,
|
|
|
- "exchange_type": c.CELERY_DEFAULT_EXCHANGE_TYPE,
|
|
|
- "binding_key": c.CELERY_DEFAULT_ROUTING_KEY}}
|
|
|
+ c["CELERY_QUEUES"] = {
|
|
|
+ c.CELERY_DEFAULT_QUEUE: {
|
|
|
+ "exchange": c.CELERY_DEFAULT_EXCHANGE,
|
|
|
+ "exchange_type": c.CELERY_DEFAULT_EXCHANGE_TYPE,
|
|
|
+ "binding_key": c.CELERY_DEFAULT_ROUTING_KEY}}
|
|
|
c["CELERY_ROUTES"] = routes.prepare(c.get("CELERY_ROUTES") or {})
|
|
|
if c.get("CELERYD_LOG_COLOR") is None:
|
|
|
c["CELERYD_LOG_COLOR"] = not c.CELERYD_LOG_FILE and \
|
|
@@ -220,6 +282,27 @@ class BaseApp(object):
|
|
|
self.conf.EMAIL_HOST_PASSWORD)
|
|
|
mailer.send(message, fail_silently=fail_silently)
|
|
|
|
|
|
+ def AsyncResult(self, task_id, backend=None):
|
|
|
+ """Create :class:`celery.result.BaseAsyncResult` instance."""
|
|
|
+ from celery.result import BaseAsyncResult
|
|
|
+ return BaseAsyncResult(task_id, app=self,
|
|
|
+ backend=backend or self.backend)
|
|
|
+
|
|
|
+ def TaskSetResult(self, taskset_id, results, **kwargs):
|
|
|
+ """Create :class:`celery.result.TaskSetResult` instance."""
|
|
|
+ from celery.result import TaskSetResult
|
|
|
+ return TaskSetResult(taskset_id, results, app=self)
|
|
|
+
|
|
|
+ def _get_backend(self):
|
|
|
+ from celery.backends import get_backend_cls
|
|
|
+ backend_cls = self.backend_cls or self.conf.CELERY_RESULT_BACKEND
|
|
|
+ backend_cls = get_backend_cls(backend_cls, loader=self.loader)
|
|
|
+ return backend_cls(app=self)
|
|
|
+
|
|
|
+ def _get_config(self):
|
|
|
+ return self.post_config_merge(MultiDictView(
|
|
|
+ self.pre_config_merge(self.loader.conf), DEFAULTS))
|
|
|
+
|
|
|
@property
|
|
|
def amqp(self):
|
|
|
if self._amqp is None:
|
|
@@ -230,10 +313,7 @@ class BaseApp(object):
|
|
|
@property
|
|
|
def backend(self):
|
|
|
if self._backend is None:
|
|
|
- from celery.backends import get_backend_cls
|
|
|
- backend_cls = self.backend_cls or self.conf.CELERY_RESULT_BACKEND
|
|
|
- backend_cls = get_backend_cls(backend_cls, loader=self.loader)
|
|
|
- self._backend = backend_cls(app=self)
|
|
|
+ self._backend = self._get_backend()
|
|
|
return self._backend
|
|
|
|
|
|
@property
|
|
@@ -246,9 +326,7 @@ class BaseApp(object):
|
|
|
@property
|
|
|
def conf(self):
|
|
|
if self._conf is None:
|
|
|
- config = self.pre_config_merge(self.loader.conf)
|
|
|
- self._conf = self.post_config_merge(
|
|
|
- MultiDictView(config, DEFAULTS))
|
|
|
+ self._conf = self._get_config()
|
|
|
return self._conf
|
|
|
|
|
|
@property
|