From 579e5e7be4635bb1929f4e0ba3a7f029a475a870 Mon Sep 17 00:00:00 2001 From: Curtis Maloney Date: Mon, 13 Jul 2020 17:31:24 +1000 Subject: [PATCH 1/2] Add registry.Registry --- dramatiq/registry.py | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 dramatiq/registry.py diff --git a/dramatiq/registry.py b/dramatiq/registry.py new file mode 100644 index 00000000..9dbc595d --- /dev/null +++ b/dramatiq/registry.py @@ -0,0 +1,65 @@ +from .actor import Actor, _queue_name_re + + +class Registry: + ''' + A Registry allows defining a collection of Actors not directly bound to a Broker. + + This allows your code to declar Actors before configuring a Broker. + ''' + def __init__(self): + self.actors = {} + self.broker = None + + def actor(self, fn=None, *, actor_class=Actor, actor_name=None, queue_name="default", priority=0, **options): + ''' + Mimics `actor.actor` decorator, but skips the actor options check, and passes `self` as broker. + ''' + + def decorator(fn): + if not _queue_name_re.fullmatch(queue_name): + raise ValueError( + "Queue names must start with a letter or an underscore followed " + "by any number of letters, digits, dashes or underscores." + ) + + return actor_class( + fn, + actor_name=actor_name or fn.__name__, + queue_name=queue_name, + priority=priority, + broker=self, + options=options, + ) + + if fn is None: + return decorator + return decorator(fn) + + def __getattr__(self, name): + # Proxy everything else to our Broker, if set. + return getattr(self.broker, name) + + def declare_actor(self, actor): + ''' + Intercept when Actor class tries to register itself. + ''' + if self.broker: + self.broker.declare_actor(actor) + else: + self.actors[actor.actor_name] = actor + + def bind_broker(self, broker): + self.broker = broker + + for actor_name, actor in self.actors.items(): + invalid_options = set(actor.options) - broker.actor_options + if invalid_options: + invalid_options_list = ", ".join(invalid_options) + raise ValueError(( + "Actor %s specified the following options which are not " + "supported by this broker: %s. Did you forget to add a " + "middleware to your Broker?" + ) % (actor_name, invalid_options_list)) + + broker.declar_actor(actor) From 17f032f2a373be54f17a2945a5759ebd3e7edfc2 Mon Sep 17 00:00:00 2001 From: Curtis Maloney Date: Mon, 13 Jul 2020 17:31:48 +1000 Subject: [PATCH 2/2] Begin tests --- dramatiq/registry.py | 12 ++++++------ tests/test_registry.py | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 tests/test_registry.py diff --git a/dramatiq/registry.py b/dramatiq/registry.py index 9dbc595d..1eb15f7f 100644 --- a/dramatiq/registry.py +++ b/dramatiq/registry.py @@ -2,19 +2,19 @@ class Registry: - ''' + """ A Registry allows defining a collection of Actors not directly bound to a Broker. This allows your code to declar Actors before configuring a Broker. - ''' + """ def __init__(self): self.actors = {} self.broker = None def actor(self, fn=None, *, actor_class=Actor, actor_name=None, queue_name="default", priority=0, **options): - ''' + """ Mimics `actor.actor` decorator, but skips the actor options check, and passes `self` as broker. - ''' + """ def decorator(fn): if not _queue_name_re.fullmatch(queue_name): @@ -41,9 +41,9 @@ def __getattr__(self, name): return getattr(self.broker, name) def declare_actor(self, actor): - ''' + """ Intercept when Actor class tries to register itself. - ''' + """ if self.broker: self.broker.declare_actor(actor) else: diff --git a/tests/test_registry.py b/tests/test_registry.py new file mode 100644 index 00000000..de505195 --- /dev/null +++ b/tests/test_registry.py @@ -0,0 +1,22 @@ +import dramatiq +from dramatiq.registry import Registry + + +def test_registry_can_be_declared(): + + Registry() + + +def test_actor_can_be_declared_on_registry(): + # When I have a Registry + reg = Registry() + + # Given that I've decorated a function with @registry.actor + @reg.actor + def add(x, y): + return x + y + + # I expect that function to become an instance of Actor + assert isinstance(add, dramatiq.Actor) + assert add.broker is reg + assert len(reg.actors) == 1