Source code for remoulade.generic

# This file is a part of Remoulade.
#
# Copyright (C) 2017,2018 CLEARTYPE SRL <bogdan@cleartype.io>
#
# Remoulade is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# Remoulade is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from . import actor


class generic_actor(type):
    """Meta for class-based actors."""

    def __new__(metacls, name, bases, attrs):
        clazz = super().__new__(metacls, name, bases, attrs)
        meta = getattr(clazz, "Meta", object())
        if not getattr(meta, "abstract", False):
            options = {name: getattr(meta, name) for name in dir(meta) if not name.startswith("_")}
            options.pop("abstract", False)

            clazz_instance = clazz()
            actor_instance = actor(clazz_instance, **options)  # type: ignore
            clazz.__getattr__ = generic_actor.__getattr__  # type: ignore
            clazz_instance.__actor__ = actor_instance
            return clazz_instance

        meta.abstract = False  # type: ignore
        clazz.__actor__ = None  # type: ignore
        return clazz

    def __getattr__(cls, name):
        return getattr(cls.__actor__, name)


[docs]class GenericActor(metaclass=generic_actor): """Base-class for class-based actors. Each subclass may define an inner class named ``Meta``. You can use the meta class to provide broker options for the actor. Classes that have ``abstract = True`` in their meta class are considered abstract base classes and are not converted into actors. You can't send these classes messages, you can only inherit from them. Actors that subclass abstract base classes inherit their parents' meta classes. You can also override meta in subclass using inheritance. Example: >>> class BaseTask(GenericActor): ... class Meta: ... abstract = True ... queue_name = "tasks" ... max_retries = 20 ... ... def get_task_name(self): ... raise NotImplementedError ... ... def perform(self): ... print(f"Hello from {self.get_task_name()}!") >>> class FooTask(BaseTask): ... def get_task_name(self): ... return "Foo" >>> class BarTask(BaseTask): ... class Meta(BaseTask.Meta): ... max_retries = 10 ... ... def get_task_name(self): ... return "Bar" >>> FooTask.send() >>> BarTask.send() Attributes: logger(Logger): The actor's logger. broker(Broker): The broker this actor is bound to. actor_name(str): The actor's name. queue_name(str): The actor's queue. priority(int): The actor's priority. options(dict): Arbitrary options that are passed to the broker and middleware. """ class Meta: abstract = True @property def __name__(self): """The default name of this actor.""" return type(self).__name__ def __call__(self, *args, **kwargs): return self.perform(*args, **kwargs)
[docs] def perform(self, *args, **kwargs): """This is the method that gets called when the actor receives a message. All non-abstract subclasses must implement this method. """ raise NotImplementedError("%s does not implement perform()" % self.__name__)