Signal Connection Decorators

7 views
Skip to first unread message

zvoase

unread,
Sep 10, 2008, 4:52:22 AM9/10/08
to Django developers
Hi Django developers,
Usually, signal receivers are defined as functions and then connected
to a specific signal via a function call outside of the defined
function. This can cause clutter, it violates DRY, and it is not very
Pythonic in style. Several examples of the current usage pattern are
included in the Django documentation, and I don't need to go into too
much detail because the majority of people on this list know what I'm
talking about.

I propose a decorator method, to be added to the Signal class, which
would allow you to decorate a signal receiver function and therefore
skip the explicit call to signal_instance.connect(...). The usage of
such a method would look something like this:

<code>
from django.db.models.signals import pre_save

@pre_save.deco_connect(sender=MyModel) # Could use another name for
the method...
def receiver(sender, instance, *args, **kwargs):
pass # Do something here.
</code>

I've already written a method like this, and it's very simple in
implementation. It also allows you to specify optional keyword
arguments, but works without them also. Please consider this for
inclusion into the Django trunk.

Regards,
Zack

Jeremy Dunck

unread,
Sep 10, 2008, 7:30:59 AM9/10/08
to django-d...@googlegroups.com, Django developers
Patch or ticket, please.

zvoase

unread,
Sep 10, 2008, 1:31:06 PM9/10/08
to Django developers
I've created a ticket: http://code.djangoproject.com/ticket/9015
I've also uploaded a patch with the suggested changes.

Regards,
Zack

On Sep 10, 1:30 pm, Jeremy Dunck <jdu...@gmail.com> wrote:
> Patch or ticket, please.
>

Justin Fagnani

unread,
Sep 11, 2008, 3:19:44 PM9/11/08
to django-d...@googlegroups.com
Hey Zack,

I just got a chance to look at this, and I like it, but have one
suggestion. From a usage standpoint, wouldn't it be simpler to have
the decorator just be the signal name, like @pre_save? I can't see any
situation where you'd use a decorator for anything but connecting, so
the ".connect" part just seems unnecessary.

This could be implemented easily by adding a __call__() method to Signal.

-Justin

Jeremy Dunck

unread,
Sep 11, 2008, 3:27:14 PM9/11/08
to django-d...@googlegroups.com
On Thu, Sep 11, 2008 at 2:19 PM, Justin Fagnani
<justin....@gmail.com> wrote:
> This could be implemented easily by adding a __call__() method to Signal.
>

That's a win. Anyone against?

Ludvig Ericson

unread,
Sep 11, 2008, 4:44:38 PM9/11/08
to django-d...@googlegroups.com
On Sep 11, 2008, at 21:19, Justin Fagnani wrote:
> I just got a chance to look at this, and I like it, but have one
> suggestion. From a usage standpoint, wouldn't it be simpler to have
> the decorator just be the signal name, like @pre_save? I can't see any
> situation where you'd use a decorator for anything but connecting, so
> the ".connect" part just seems unnecessary.

I just sat using the dispatcher from Django in a project of mine, and
was stunned at
__call__ not being *send*. So no, no __call__ decorator.

-- Ludvig

zvoase

unread,
Sep 12, 2008, 7:01:49 AM9/12/08
to Django developers
I think the principle of least surprise applies here. It would be very
easy just to implement __call__ as a decorator, but by the same token,
the signal needs to be used from both ends, and the addition of a
__call__ method may confuse some people. As with most problems in
programming, we just end up discussing the name :)
IMHO, I think the removal of ambiguity is worth the extra 8
characters. If we make a decision (by informal vote), then I'll just
go ahead and implement it, and then we just need someone to commit to
SVN.

Regards,
Zack

zvoase

unread,
Sep 13, 2008, 9:10:15 AM9/13/08
to Django developers
Couldn't we move this discussion to the ticket on Django's Trac?

http://code.djangoproject.com/ticket/9015

James Bennett

unread,
Sep 13, 2008, 11:07:53 AM9/13/08
to django-d...@googlegroups.com
On Sat, Sep 13, 2008 at 8:10 AM, zvoase <crac...@gmail.com> wrote:
> Couldn't we move this discussion to the ticket on Django's Trac?

Preferably not; it's far easier to keep track of a threaded discussion
here on the mailing list, as opposed to trying to follow it in the
ticket.


--
"Bureaucrat Conrad, you are technically correct -- the best kind of correct."

Ludvig Ericson

unread,
Sep 13, 2008, 6:19:45 PM9/13/08
to django-d...@googlegroups.com
On Sep 12, 2008, at 13:01, zvoase wrote:
> I think the principle of least surprise applies here. It would be very
> easy just to implement __call__ as a decorator, but by the same token,
> the signal needs to be used from both ends, and the addition of a
> __call__ method may confuse some people. As with most problems in
> programming, we just end up discussing the name :)
> IMHO, I think the removal of ambiguity is worth the extra 8
> characters. If we make a decision (by informal vote), then I'll just
> go ahead and implement it, and then we just need someone to commit to
> SVN.

Yes, so if we decide to go ahead and include decorator functionality, we
have two ways to go:

@signal.decorate
def f(...): ...

- or -

@signal_decorator(signal)
def f(...): ...

I'm not sure which is more Pythonic or which I prefer, considering
Python
mixes and matches these two styles. (math.sqrt, str.encode, etc.)

Ludvig Ericson
ludvig....@gmail.com

zvoase

unread,
Sep 13, 2008, 7:51:55 PM9/13/08
to Django developers
I think the "signal.decorate" form is nicer, but the name has to show
that there is some sort of connection going on; if you want to know
why I think this is, take a look at "The Zen of Python". Basically,
it's explicit (you know it refers to *that* signal), it's the obvious
way to do it (seeing as we can actually edit the "Signal" class's
source code, adding this as a method), and it's substantially more
beautiful and explicit. That's what I think, anyway.

Plus, we don't write it as signal_connect(signal, receiver). We write
it as signal.connect(receiver). It's more compact, explicit, beautiful
and obvious.

The thing is, can we actually change the 'connect' method, or are we
going to give this a new name?

Regards,
Zack
> ludvig.eric...@gmail.com

zvoase

unread,
Sep 13, 2008, 7:56:35 PM9/13/08
to Django developers
Oh, yeah, by the way, for those who haven't looked at the ticket, my
implementation changes the 'connect' method, so that it can be used in
the old way ("signal.connect(receiver)"), or as a decorator
("@signal.connect" with "def receiver").

The old 'connect' method is still used (by the new method), only it's
been renamed to '_connect'. This fits with Django's way of having the
raw methods prefixed by an underscore, and the nicer, more general
methods as the name on its own.

This is only in the patch, by the way, it hasn't yet been merged :)
Don't worry, I'm not messing with stuff!

Regards,
Zack

zvoase

unread,
Oct 27, 2008, 9:06:26 PM10/27/08
to Django developers
I just wanted to check if there was a consensus on this; it would be
nice to get it into the Django 1.1 featureset.

Regards,
Zack
Reply all
Reply to author
Forward
0 new messages