summaryrefslogtreecommitdiff
path: root/CHANGES.txt
diff options
context:
space:
mode:
Diffstat (limited to 'CHANGES.txt')
-rw-r--r--CHANGES.txt98
1 files changed, 98 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 5344cb7d1..a625af3f9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -15,6 +15,104 @@ Features
values in parameterized ``.ini`` file, e.g. ``pshell etc/development.ini
http_port=8080``. See https://github.com/Pylons/pyramid/pull/714
+- In order to normalize the relationship between event subscribers and
+ subscriber predicates, we now allow both subscribers and subscriber
+ predicates to accept only a single ``event`` argument even if they've been
+ subscribed for notifications that involve multiple interfaces. Subscribers
+ and subscriber predicates that accept only one argument will receive the
+ first object passed to ``notify``; this is typically (but not always) the
+ event object. The other objects involved in the subscription lookup will be
+ discarded.
+
+ For instance, if an event is sent by code like this::
+
+ registry.notify(event, context)
+
+ In the past, in order to catch such an event, you were obligated to write and
+ register an event subscriber that mentioned both the event and the context in
+ its argument list::
+
+ @subscriber([SomeEvent, SomeContextType])
+ def subscriber(event, context):
+ pass
+
+ With the event-only feature you can now write an event subscriber that
+ accepts only ``event`` even if it subscribes to multiple interfaces::
+
+ @subscriber([SomeEvent, SomeContextType])
+ def subscriber(event):
+ # this will work!
+
+ Note, however, that if the event object is not the first object in the call
+ to ``notify``, you'll run into trouble. For example, if notify is called
+ with the context argument first::
+
+ registry.notify(context, event)
+
+ You won't be able to take advantage of the feature. It will "work", but the
+ object received by your event handler won't be the event object, it will be
+ the context object, which won't be very useful::
+
+ @subscriber([SomeContextType, SomeEvent])
+ def subscriber(event):
+ # bzzt! you'll be getting the context here as ``event``, and it'll
+ # be useless
+
+ Existing multiple-argument subscribers continue to work without issue, so you
+ should continue use those if your system notifies using multiple interfaces
+ and the first interface is not the event interface. For example::
+
+ @subscriber([SomeContextType, SomeEvent])
+ def subscriber(context, event):
+ # this will still work!
+
+ The event-only feature makes it possible to use a subscriber predicate that
+ accepts only a request argument within both multiple-interface subscriber
+ registrations and single-interface subscriber registrations. In the past, if
+ you had a subscriber predicate like this::
+
+ class RequestPathStartsWith(object):
+ def __init__(self, val, config):
+ self.val = val
+
+ def text(self):
+ return 'path_startswith = %s' % (self.val,)
+
+ phash = text
+
+ def __call__(self, event):
+ return event.request.path.startswith(self.val)
+
+ If you attempted to use the above predicate to condition a subscription that
+ involved multiple interfaces, it would not work. You had to change it to
+ accept the same arguments as the subscription itself. For example, you might
+ have had to change its ``__call__`` method like so, adding a ``context``
+ argument::
+
+ def __call__(self, event, context):
+ return event.request.path.startswith(self.val)
+
+ With the event-only feature, you needn't make the change. Instead, you can
+ write all predicates so they only accept ``event`` in their ``__call__`` and
+ they'll be useful across all registrations for subscriptions that use an
+ event as their first argument, even ones which accept more than just
+ ``event``. However, the same caveat applies to predicates as to
+ subscriptions: if you're subscribing to a multi-interface event, and the
+ first interface is not the event interface, the predicate won't work
+ properly. In such a case, you'll need to match the predicate ``__call__``
+ argument ordering and composition to the ordering of the interfaces. For
+ example::
+
+ def __call__(self, context, event):
+ return event.request.path.startswith(self.val)
+
+ tl;dr: 1) Always use the event as the first argument to a multi-interface
+ subscription and 2) Use only ``event`` in your subscriber and subscriber
+ predicate parameter lists, no matter how many interfaces the subscriber is
+ notified with, as long as the event object is the first argument passed to
+ ``registry.notify``. This will result in the maximum amount of reusability
+ of subscriber predicates.
+
Bug Fixes
---------