Skip to content

Commit

Permalink
Fixed the API to be a bit saner
Browse files Browse the repository at this point in the history
  • Loading branch information
flashingpumpkin committed Jun 29, 2012
1 parent 9452244 commit c879132
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 133 deletions.
45 changes: 29 additions & 16 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,63 @@ Pluggable notifications for your Python apps.
The full documentation is available `here <http://yell.readthedocs.org/en/latest/index.html>`_.


Using yelling decorators
------------------------
Using notification decorators
-----------------------------

::

from yell.decorators import yelling
from yell import notify
from yell.decorators import notification
@yelling(name = 'buffalo')
@notification(name = 'buffalo')
def buffalo_printer(message):
print message
@yelling(name = 'buffalo')
@notification(name = 'buffalo')
def buffalo_saver(message):
save(message)
yell("buffalo", _("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo"))
notify("buffalo", _("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo"))


Using yelling classes
---------------------
Using notification classes
--------------------------

::
::

from yell import Yell, yell
from yell import Notification, notify

class Buffalo(Yell):
class Buffalo(Notification):
name = "buffalo"
message = _("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
print self.message
class BuffaloEmail(Buffalo):
def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
send_mail("Buffalo", self.message, '[email protected]', [kwargs.get('user').email])

class BuffaloDatabase(Buffalo):
def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
BuffaloModel.objects.create(user = kwargs.get('user'))

# The default behaviour is to use every notification backend with the same
# name
yell("buffalo", user = User.objects.get(id=1))
notify("buffalo", user = User.objects.get(id=1))

# Only send emails
yell("buffalo", user = User.objects.get(id=1), backends = [BuffaloEmail])
notify("buffalo", user = User.objects.get(id=1), backends = [BuffaloEmail])


Changelog
---------

**v0.2**

* Made the API saner to use (*backwards incompatible*):
- ``yell.Yell`` became ``yell.Notification``
- ``yell.yell`` became ``yell.notify``
- ``yell.decorators.yelling`` became ``yell.decorators.notification``


49 changes: 20 additions & 29 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,65 +4,56 @@ yell

Pluggable notifications for your Python apps.

`yell` is not a notification storage or delivery backend but a set of APIs that make it easy to add your own delivery mechanisms.
`yell` is not a notification storage or delivery backend but a set of APIs that make it easy to add your own delivery mechanisms.

The full documentation is available `here <http://yell.readthedocs.org/en/latest/index.html>`_.

Using yelling decorators
------------------------

Using notification decorators
-----------------------------

::

from yell.decorators import yelling
from yell import notify
from yell.decorators import notification
@yelling(name = 'buffalo')
@notification(name = 'buffalo')
def buffalo_printer(message):
print message
@yelling(name = 'buffalo')
@notification(name = 'buffalo')
def buffalo_saver(message):
save(message)
yell("buffalo", _("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo"))
notify("buffalo", _("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo"))


Using yelling classes
---------------------
Using notification classes
--------------------------

::
::

from yell import Yell, yell
from yell import Notification, notify

class Buffalo(Yell):
class Buffalo(Notification):
name = "buffalo"
message = _("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
print self.message
class BuffaloEmail(Buffalo):
def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
send_mail("Buffalo", self.message, '[email protected]', [kwargs.get('user').email])

class BuffaloDatabase(Buffalo):
def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
BuffaloModel.objects.create(user = kwargs.get('user'))

# The default behaviour is to use every notification backend with the same
# name
yell("buffalo", user = User.objects.get(id=1))
notify("buffalo", user = User.objects.get(id=1))

# Only send emails
yell("buffalo", user = User.objects.get(id=1), backends = [BuffaloEmail])



API
===

.. toctree::
:maxdepth: 5

yell
yell.backends

notify("buffalo", user = User.objects.get(id=1), backends = [BuffaloEmail])

34 changes: 17 additions & 17 deletions yell/__init__.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,62 @@
__version__ = "0.1"
__version__ = "0.2"

import registry

class MetaYell(type):
class MetaNotification(type):
"""
Metaclass that stores all yells in the registry.
Metaclass that stores all notifications in the registry.
"""
def __new__(cls, name, bases, attrs):
Yell = super(MetaYell, cls).__new__(cls, name, bases, attrs)
Notification = super(MetaNotification, cls).__new__(cls, name, bases, attrs)

if Yell.name is not None:
registry.yells[Yell.name] = registry.yells.get(Yell.name, []) + [Yell]
if Notification.name is not None:
registry.notifications[Notification.name] = registry.notifications.get(Notification.name, []) + [Notification]

return Yell
return Notification


class Yell(object):
class Notification(object):
"""
Base class for any kind of notifications. Inherit from this class to create
your own notification types and backends.
Subclasses need to implement :meth:`yell`.
Subclasses need to implement :meth:`notify`.
"""
__metaclass__ = MetaYell
__metaclass__ = MetaNotification

name = None
"""
A name for this yell.
A name for this notification.
"""

def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
"""
A method that delivers a notification.
"""
raise NotImplementedError

def yell(name, *args, **kwargs):
def notify(name, *args, **kwargs):
"""
Send notifications. If ``backends==None``, all backends with the same name
will be used to deliver a notification.
If ``backends`` is a list, only the specified backends will be used.
:param name: The yell to send
:param name: The notification to send
:param backends: A list of backends to be used or ``None`` to use all associated backends
"""
assert name in registry.yells, "'{0}' is not a valid yell.".format(repr(name))
assert name in registry.notifications, "'{0}' is not a valid notification.".format(repr(name))

backends = kwargs.pop('backends', None)

if backends is None:
backends = registry.yells[name]
backends = registry.notifications[name]

results = []

for Backend in backends:
backend = Backend()
results.append(backend.yell(*args, **kwargs))
results.append(backend.notify(*args, **kwargs))

return results

Expand Down
52 changes: 26 additions & 26 deletions yell/backends/celery.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
from __future__ import absolute_import
from celery.task import Task
from yell import Yell, yell, registry
from yell import Notification, notify, registry

class CeleryYellingTask(Task):
""" Dispatch and run the yelling """
def run(self, name=None, yeller=None, *args, **kwargs):
class CeleryNotificationTask(Task):
""" Dispatch and run the notification. """
def run(self, name=None, backend=None, *args, **kwargs):
"""
The Celery task.
Delivers the notification via all backends returned by :param:`yeller`.
Delivers the notification via all backends returned by :param:`backend`.
"""
assert name is not None, "No 'name' specified to yell"
assert yeller is not None, "No 'yeller' specified to yell with"
assert name is not None, "No 'name' specified to notify"
assert backend is not None, "No 'backend' specified to notify with"

backends = yeller().get_backends(*args, **kwargs)
yell(name, backends=backends, *args, **kwargs)
backends = backend().get_backends(*args, **kwargs)
notify(name, backends=backends, *args, **kwargs)

class CeleryYell(Yell):
class CeleryNotification(Notification):
"""
Delivers notifications through Celery.
:example:
::
from yell import yell, Yell
from yell import notify, Notification
class EmailYell(Yell):
yell = 'async'
def yell(self, *args, **kwargs):
class EmailNotification(Notification):
name = 'async'
def notify(self, *args, **kwargs):
# Deliver email
class DBYell(Yell):
yell = 'async'
def yell(self, *args, **kwargs):
class DBNotification(Notification):
name = 'async'
def notify(self, *args, **kwargs):
# Save to database
class AsyncYell(CeleryYell):
yell = 'async'
class AsyncNotification(CeleryNotification):
name = 'async'
yell('async', backends = [AsyncYell],
notify('async', backends = [AsyncNotification],
text = "This notification is routed through Celery before being sent and saved")
In the above example when calling :attr:`yell.yell` will invoke ``EmailYell`` and
``DBYell`` once the task was delivered through Celery.
In the above example when calling :attr:`yell.notify` will invoke ``EmailNotification`` and
``DBNotification`` once the task was delivered through Celery.
"""
name = None
Expand All @@ -55,14 +55,14 @@ def get_backends(self, *args, **kwargs):
"""
Return all backends the task should use to deliver notifications.
By default all backends with the same :attr:`name` except for subclasses
of :class:`CeleryYell` will be used.
of :class:`CeleryNotifications` will be used.
"""
return filter(lambda cls: not isinstance(cls, self.__class__), registry.yells[self.yell])
return filter(lambda cls: not isinstance(cls, self.__class__), registry.notifications[self.name])

def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
"""
Dispatches the notification to Celery
"""
return CeleryYellingTask.delay(name=self.name, yeller=self.__class__, *args, **kwargs)
return CeleryNotificationTask.delay(name=self.name, backend=self.__class__, *args, **kwargs)


8 changes: 4 additions & 4 deletions yell/backends/django.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from django.conf import settings
from django import template
from django.core.mail import send_mail, EmailMultiAlternatives
from yell import Yell
from yell import Notification
import mimetypes


class EmailBackend(Yell):
class EmailBackend(Notification):
"""
Send emails via :attr:`django.core.mail.send_mail`
"""
Expand Down Expand Up @@ -36,7 +36,7 @@ def get_from(self, *args, **kwargs):
def get_to(self, *args, **kwargs):
return kwargs.get('to')

def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):

return send_mail(
self.get_subject(*args, **kwargs),
Expand Down Expand Up @@ -68,7 +68,7 @@ def get_body(self, *args, **kwargs):
def get_default_body(self, *args, **kwargs):
return self.get_body(*args, **kwargs)[self.default_content_type]

def yell(self, *args, **kwargs):
def notify(self, *args, **kwargs):
message = EmailMultiAlternatives(
self.get_subject(*args, **kwargs),
self.get_default_body(*args, **kwargs),
Expand Down
Loading

0 comments on commit c879132

Please sign in to comment.