Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Subscriber predicates:

- Add ``add_subscriber_predicate`` method to Configurator.

- Allow ``add_subscriber`` and ``subscriber`` venusian decorator to accept ``**predicates`` arguments.

- Document subscriber predicate feature.

- Share more code between view, route, and subscriber related method wrt predicates.
  • Loading branch information...
commit 95f766bc7c380797c569da464f1f41d12b05bdbe 1 parent bf64f1e
@mcdonc mcdonc authored
View
13 CHANGES.txt
@@ -40,9 +40,11 @@ Bug Fixes
Features
--------
-- Third-party custom view and route predicates can now be added for use by
- view authors via ``pyramid.config.Configurator.add_view_predicate`` and
- ``pyramid.config.Configurator.add_route_predicate``. So, for example,
+- Third-party custom view, route, and subscriber predicates can now be added
+ for use by view authors via
+ ``pyramid.config.Configurator.add_view_predicate``,
+ ``pyramid.config.Configurator.add_route_predicate`` and
+ ``pyramid.config.Configurator.add_subscriber_predicate``. So, for example,
doing this::
config.add_view_predicate('abc', my.package.ABCPredicate)
@@ -52,8 +54,9 @@ Features
@view_config(abc=1)
- See "Adding A Third Party View or Route Predicate" in the Hooks chapter for
- more information.
+ Similar features exist for ``add_route``, and ``add_subscriber``. See
+ "Adding A Third Party View, Route, or Subscriber Predicate" in the Hooks
+ chapter for more information.
Note that changes made to support the above feature now means that only
actions registered using the same "order" can conflict with one another.
View
3  docs/glossary.rst
@@ -997,6 +997,7 @@ Glossary
predicate factory
A callable which is used by a third party during the registration of a
- route or view predicates to extend the view and route configuration
+ route, view, or subscriber predicates to extend the configuration
system. See :ref:`registering_thirdparty_predicates` for more
information.
+
View
122 docs/narr/hooks.rst
@@ -1235,17 +1235,23 @@ implict and explicit tween chains used by an application. See
.. _registering_thirdparty_predicates:
-Adding A Third Party View or Route Predicate
---------------------------------------------
+Adding A Third Party View, Route, or Subscriber Predicate
+---------------------------------------------------------
.. note::
- Third-party predicates are a feature new as of Pyramid 1.4.
+ Third-party view, route, and subscriber predicates are a feature new as of
+ Pyramid 1.4.
-View and route predicates used during view configuration allow you to narrow
-the set of circumstances under which a view or route will match. For
-example, the ``request_method`` view predicate can be used to ensure a view
-callable is only invoked when the request's method is ``POST``:
+.. _view_and_route_predicates:
+
+View and Route Predicates
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+View and route predicates used during configuration allow you to narrow the
+set of circumstances under which a view or route will match. For example,
+the ``request_method`` view predicate can be used to ensure a view callable
+is only invoked when the request's method is ``POST``:
.. code-block:: python
@@ -1286,9 +1292,9 @@ The first argument to :meth:`pyramid.config.Configurator.add_view_predicate`,
the name, is a string representing the name that is expected to be passed to
``view_config`` (or its imperative analogue ``add_view``).
-The second argument is a predicate factory. A predicate factory is most
-often a class with a constructor (``__init__``), a ``text`` method, a
-``phash`` method and a ``__call__`` method. For example:
+The second argument is a view or route predicate factory. A view or route
+predicate factory is most often a class with a constructor (``__init__``), a
+``text`` method, a ``phash`` method and a ``__call__`` method. For example:
.. code-block:: python
:linenos:
@@ -1330,3 +1336,99 @@ You can use the same predicate factory as both a view predicate and as a
route predicate, but you'll need to call ``add_view_predicate`` and
``add_route_predicate`` separately with the same factory.
+.. _subscriber_predicates:
+
+Subscriber Predicates
+~~~~~~~~~~~~~~~~~~~~~
+
+Subscriber predicates work almost exactly like view and route predicates.
+They narrow the set of circumstances in which a subscriber will be called.
+There are several minor differences between a subscriber predicate and a
+view/route predicate:
+
+- There are no default subscriber predicates. You must register one to use
+ one.
+
+- The ``__call__`` method of a subscriber predicate accepts a single
+ ``event`` object instead of a ``context`` and a ``request``.
+
+- Not every subscriber predicate can be used with every event type. Some
+ subscriber predicates will assume a certain event type.
+
+Here's an example of a subscriber predicate that can be used in conjunction
+with a subscriber that subscribes to the :class:`pyramid.events.NewReqest`
+event type.
+
+.. code-block:: python
+ :linenos:
+
+ 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)
+
+Once you've created a subscriber predicate, it may registered via
+:meth:`pyramid.config.Configurator.add_subscriber_predicate`. For example:
+
+.. code-block:: python
+
+ config.add_subscriber_predicate(
+ 'request_path_startswith', RequestPathStartsWith)
+
+Once a subscriber predicate is registered, you can use it in a call to
+:meth:`pyramid.config.Configurator.add_subscriber` or to
+:class:`pyramid.events.subscriber`. Here's an example of using the
+previously registered ``request_path_startswith`` predicate in a call to
+:meth:`~pyramid.config.Configurator.add_subscriber`:
+
+.. code-block:: python
+ :linenos:
+
+ # define a subscriber in your code
+
+ def yosubscriber(event):
+ event.request.yo = 'YO!'
+
+ # and at configuration time
+
+ config.add_subscriber(yosubscriber, NewRequest,
+ request_path_startswith='/add_yo')
+
+Here's the same subscriber/predicate/event-type combination used via
+:class:`~pyramid.events.subscriber`.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.events import subscriber
+
+ @subscriber(NewRequest, request_path_startswith='/add_yo')
+ def yosubscriber(event):
+ event.request.yo = 'YO!'
+
+In either of the above configurations, the ``yosubscriber`` callable will
+only be called if the request path starts with ``/add_yo``. Otherwise the
+event subscriber will not be called.
+
+Note that the ``request_path_startswith`` subscriber you defined can be used
+with events that have a ``request`` attribute, but not ones that do not. So,
+for example, the predicate can be used with subscribers registered for
+:class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound`
+events, but it cannot be used with subscribers registered for
+:class:`pyramid.events.ApplicationCreated` because the latter type of event
+has no ``request`` attribute. The point being: unlike route and view
+predicates, not every type of subscriber predicate will necessarily be
+applicable for use in every subscriber registration. It is not the
+responsibility of the predicate author to make every predicate make sense for
+every event type; it is the responsibility of the predicate consumer to use
+predicates that make sense for a particular event type registration.
+
+
+
View
29 pyramid/config/__init__.py
@@ -12,6 +12,8 @@
from pyramid.interfaces import (
IDebugLogger,
IExceptionResponse,
+ IPredicateList,
+ PHASE1_CONFIG,
)
from pyramid.asset import resolve_asset_spec
@@ -71,6 +73,7 @@
from pyramid.config.util import (
action_method,
ActionInfo,
+ PredicateList,
)
from pyramid.config.views import ViewsConfiguratorMixin
from pyramid.config.zca import ZCAConfiguratorMixin
@@ -489,6 +492,32 @@ def _del_introspector(self):
_get_introspector, _set_introspector, _del_introspector
)
+ def _get_predlist(self, name):
+ predlist = self.registry.queryUtility(IPredicateList, name=name)
+ if predlist is None:
+ predlist = PredicateList()
+ self.registry.registerUtility(predlist, IPredicateList, name=name)
+ return predlist
+
+ def _add_predicate(self, type, name, factory, weighs_more_than=None,
+ weighs_less_than=None):
+ discriminator = ('%s predicate' % type, name)
+ intr = self.introspectable(
+ '%s predicates' % type,
+ discriminator,
+ '%s predicate named %s' % (type, name),
+ '%s predicate' % type)
+ intr['name'] = name
+ intr['factory'] = factory
+ intr['weighs_more_than'] = weighs_more_than
+ intr['weighs_less_than'] = weighs_less_than
+ def register():
+ predlist = self._get_predlist(type)
+ predlist.add(name, factory, weighs_more_than=weighs_more_than,
+ weighs_less_than=weighs_less_than)
+ self.action(discriminator, register, introspectables=(intr,),
+ order=PHASE1_CONFIG) # must be registered early
+
@property
def action_info(self):
info = self.info # usually a ZCML action (ParserInfo) if self.info
View
94 pyramid/config/adapters.py
@@ -1,3 +1,5 @@
+from functools import update_wrapper
+
from zope.interface import Interface
from pyramid.interfaces import (
@@ -6,40 +8,103 @@
IResourceURL,
)
-from pyramid.config.util import action_method
+from pyramid.config.util import (
+ action_method,
+ )
+
class AdaptersConfiguratorMixin(object):
@action_method
- def add_subscriber(self, subscriber, iface=None):
+ def add_subscriber(self, subscriber, iface=None, **predicates):
"""Add an event :term:`subscriber` for the event stream
- implied by the supplied ``iface`` interface. The
- ``subscriber`` argument represents a callable object (or a
- :term:`dotted Python name` which identifies a callable); it
- will be called with a single object ``event`` whenever
- :app:`Pyramid` emits an :term:`event` associated with the
- ``iface``, which may be an :term:`interface` or a class or a
- :term:`dotted Python name` to a global object representing an
- interface or a class. Using the default ``iface`` value,
- ``None`` will cause the subscriber to be registered for all
- event types. See :ref:`events_chapter` for more information
- about events and subscribers."""
+ implied by the supplied ``iface`` interface.
+
+ The ``subscriber`` argument represents a callable object (or a
+ :term:`dotted Python name` which identifies a callable); it will be
+ called with a single object ``event`` whenever :app:`Pyramid` emits
+ an :term:`event` associated with the ``iface``, which may be an
+ :term:`interface` or a class or a :term:`dotted Python name` to a
+ global object representing an interface or a class.
+
+ Using the default ``iface`` value, ``None`` will cause the subscriber
+ to be registered for all event types. See :ref:`events_chapter` for
+ more information about events and subscribers.
+
+ Any number of predicate keyword arguments may be passed in
+ ``**predicates``. Each predicate named will narrow the set of
+ circumstances that the subscriber will be invoked. Each named
+ predicate must have been registered via
+ :meth:`pyramid.config.Configurator.add_subscriber_predicate` before it
+ can be used. See :ref:`subscriber_predicates` for more information.
+
+ .. note::
+
+ THe ``**predicates`` argument is new as of Pyramid 1.4.
+ """
dotted = self.maybe_dotted
subscriber, iface = dotted(subscriber), dotted(iface)
if iface is None:
iface = (Interface,)
if not isinstance(iface, (tuple, list)):
iface = (iface,)
+
def register():
- self.registry.registerHandler(subscriber, iface)
+ predlist = self._get_predlist('subscriber')
+ order, preds, phash = predlist.make(self, **predicates)
+ intr.update({'phash':phash, 'order':order, 'predicates':preds})
+ derived_subscriber = self._derive_subscriber(subscriber, preds)
+ self.registry.registerHandler(derived_subscriber, iface)
+
intr = self.introspectable('subscribers',
id(subscriber),
self.object_description(subscriber),
'subscriber')
+
intr['subscriber'] = subscriber
intr['interfaces'] = iface
+
self.action(None, register, introspectables=(intr,))
return subscriber
+ def _derive_subscriber(self, subscriber, predicates):
+ if not predicates:
+ return subscriber
+ def subscriber_wrapper(event):
+ if all((predicate(event) for predicate in predicates)):
+ subscriber(event)
+ if hasattr(subscriber, '__name__'):
+ update_wrapper(subscriber_wrapper, subscriber)
+ return subscriber_wrapper
+
+ @action_method
+ def add_subscriber_predicate(self, name, factory, weighs_more_than=None,
+ weighs_less_than=None):
+ """
+ Adds a subscriber predicate factory. The associated subscriber
+ predicate can later be named as a keyword argument to
+ :meth:`pyramid.config.Configurator.add_subscriber` in the
+ ``**predicates`` anonyous keyword argument dictionary.
+
+ ``name`` should be the name of the predicate. It must be a valid
+ Python identifier (it will be used as a ``**predicates`` keyword
+ argument to :meth:`~pyramid.config.Configurator.add_subscriber`).
+
+ ``factory`` should be a :term:`predicate factory`.
+
+ See :ref:`subscriber_predicates` for more information.
+
+ .. note::
+
+ This method is new as of Pyramid 1.4.
+ """
+ self._add_predicate(
+ 'subscriber',
+ name,
+ factory,
+ weighs_more_than=weighs_more_than,
+ weighs_less_than=weighs_less_than
+ )
+
@action_method
def add_response_adapter(self, adapter, type_or_iface):
""" When an object of type (or interface) ``type_or_iface`` is
@@ -203,4 +268,3 @@ def register(resource_iface=resource_iface):
intr['resource_iface'] = resource_iface
self.action(discriminator, register, introspectables=(intr,))
-
View
41 pyramid/config/routes.py
@@ -1,7 +1,6 @@
import warnings
from pyramid.interfaces import (
- IPredicateList,
IRequest,
IRouteRequest,
IRoutesMapper,
@@ -17,7 +16,6 @@
from pyramid.config.util import (
action_method,
as_sorted_tuple,
- PredicateList,
)
import pyramid.config.predicates
@@ -265,7 +263,7 @@ def add_route(self,
registered via
:meth:`pyramid.config.Configurator.add_view_predicate`. More than
one key/value pair can be used at the same time. See
- :ref:`registering_thirdparty_predicates` for more information about
+ :ref:`view_and_route_predicates` for more information about
third-party predicates. This argument is new as of Pyramid 1.4.
View-Related Arguments
@@ -434,7 +432,7 @@ def register_connect():
)
)
- predlist = self.route_predlist
+ predlist = self._get_predlist('route')
_, preds, _ = predlist.make(self, **pvals)
route = mapper.connect(
name, pattern, factory, predicates=preds,
@@ -466,15 +464,6 @@ def register_connect():
attr=view_attr,
)
- @property
- def route_predlist(self):
- predlist = self.registry.queryUtility(IPredicateList, name='route')
- if predlist is None:
- predlist = PredicateList()
- self.registry.registerUtility(predlist, IPredicateList,
- name='route')
- return predlist
-
@action_method
def add_route_predicate(self, name, factory, weighs_more_than=None,
weighs_less_than=None):
@@ -488,29 +477,19 @@ def add_route_predicate(self, name, factory, weighs_more_than=None,
``factory`` should be a :term:`predicate factory`.
- See :ref:`registering_thirdparty_predicates` for more information.
+ See :ref:`view_and_route_predicates` for more information.
.. note::
This method is new as of Pyramid 1.4.
"""
- discriminator = ('route predicate', name)
- intr = self.introspectable(
- 'route predicates',
- discriminator,
- 'route predicate named %s' % name,
- 'route predicate')
- intr['name'] = name
- intr['factory'] = factory
- intr['weighs_more_than'] = weighs_more_than
- intr['weighs_less_than'] = weighs_less_than
- def register():
- predlist = self.route_predlist
- predlist.add(name, factory, weighs_more_than=weighs_more_than,
- weighs_less_than=weighs_less_than)
- # must be registered before routes connected
- self.action(discriminator, register, introspectables=(intr,),
- order=PHASE1_CONFIG)
+ self._add_predicate(
+ 'route',
+ name,
+ factory,
+ weighs_more_than=weighs_more_than,
+ weighs_less_than=weighs_less_than
+ )
def add_default_route_predicates(self):
p = pyramid.config.predicates
View
39 pyramid/config/views.py
@@ -20,7 +20,6 @@
IException,
IExceptionViewClassifier,
IMultiView,
- IPredicateList,
IRendererFactory,
IRequest,
IResponse,
@@ -79,7 +78,6 @@
DEFAULT_PHASH,
MAX_ORDER,
action_method,
- PredicateList,
)
urljoin = urlparse.urljoin
@@ -1008,7 +1006,7 @@ def add_view(
registered via
:meth:`pyramid.config.Configurator.add_view_predicate`. More than
one key/value pair can be used at the same time. See
- :ref:`registering_thirdparty_predicates` for more information about
+ :ref:`view_and_route_predicates` for more information about
third-party predicates. This argument is new as of Pyramid 1.4.
"""
@@ -1107,7 +1105,7 @@ def discrim_func():
)
view_intr.update(**predicates)
introspectables.append(view_intr)
- predlist = self.view_predlist
+ predlist = self._get_predlist('view')
def register(permission=permission, renderer=renderer):
# the discrim_func above is guaranteed to have been called already
@@ -1302,14 +1300,6 @@ def regclosure():
introspectables.append(perm_intr)
self.action(discriminator, register, introspectables=introspectables)
- @property
- def view_predlist(self):
- predlist = self.registry.queryUtility(IPredicateList, name='view')
- if predlist is None:
- predlist = PredicateList()
- self.registry.registerUtility(predlist, IPredicateList, name='view')
- return predlist
-
@action_method
def add_view_predicate(self, name, factory, weighs_more_than=None,
weighs_less_than=None):
@@ -1324,28 +1314,19 @@ def add_view_predicate(self, name, factory, weighs_more_than=None,
``factory`` should be a :term:`predicate factory`.
- See :ref:`registering_thirdparty_predicates` for more information.
+ See :ref:`view_and_route_predicates` for more information.
.. note::
This method is new as of Pyramid 1.4.
"""
- discriminator = ('view predicate', name)
- intr = self.introspectable(
- 'view predicates',
- discriminator,
- 'view predicate named %s' % name,
- 'view predicate')
- intr['name'] = name
- intr['factory'] = factory
- intr['weighs_more_than'] = weighs_more_than
- intr['weighs_less_than'] = weighs_less_than
- def register():
- predlist = self.view_predlist
- predlist.add(name, factory, weighs_more_than=weighs_more_than,
- weighs_less_than=weighs_less_than)
- self.action(discriminator, register, introspectables=(intr,),
- order=PHASE1_CONFIG) # must be registered before views added
+ self._add_predicate(
+ 'view',
+ name,
+ factory,
+ weighs_more_than=weighs_more_than,
+ weighs_less_than=weighs_less_than
+ )
def add_default_view_predicates(self):
p = pyramid.config.predicates
View
17 pyramid/events.py
@@ -14,9 +14,10 @@
)
class subscriber(object):
- """ Decorator activated via a :term:`scan` which treats the
- function being decorated as an event subscriber for the set of
- interfaces passed as ``*ifaces`` to the decorator constructor.
+ """ Decorator activated via a :term:`scan` which treats the function
+ being decorated as an event subscriber for the set of interfaces passed
+ as ``*ifaces`` and the set of predicate terms passed as ``**predicates``
+ to the decorator constructor.
For example:
@@ -61,16 +62,22 @@ def mysubscriber(event):
config = Configurator()
config.scan('somepackage_containing_subscribers')
+ Any ``**predicate`` arguments will be passed along to
+ :meth:`pyramid.config.Configurator.add_subscriber`. See
+ :ref:`subscriber_predicates` for a description of how predicates can
+ narrow the set of circumstances in which a subscriber will be called.
+
"""
venusian = venusian # for unit testing
- def __init__(self, *ifaces):
+ def __init__(self, *ifaces, **predicates):
self.ifaces = ifaces
+ self.predicates = predicates
def register(self, scanner, name, wrapped):
config = scanner.config
for iface in self.ifaces or (Interface,):
- config.add_subscriber(wrapped, iface)
+ config.add_subscriber(wrapped, iface, **self.predicates)
def __call__(self, wrapped):
self.venusian.attach(wrapped, self.register, category='pyramid')
View
127 pyramid/tests/test_config/test_adapters.py
@@ -81,6 +81,121 @@ def subscriber(object, event):
config.registry.subscribers((event.object, IDummy), None)
self.assertEqual(len(L), 1)
+ def test_add_subscriber_with_specific_type_and_predicates_True(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+ class IEvent(Interface):
+ pass
+ @implementer(IEvent)
+ class Event:
+ pass
+ L = []
+ def subscriber(event):
+ L.append(event)
+ config = self._makeOne(autocommit=True)
+ predlist = config._get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, IEvent, jam=True, jim=True)
+ event = Event()
+ event.jam = True
+ event.jim = True
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_add_subscriber_with_default_type_predicates_True(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+ class IEvent(Interface):
+ pass
+ @implementer(IEvent)
+ class Event:
+ pass
+ L = []
+ def subscriber(event):
+ L.append(event)
+ config = self._makeOne(autocommit=True)
+ predlist = config._get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, jam=True, jim=True)
+ event = Event()
+ event.jam = True
+ event.jim = True
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_add_subscriber_with_specific_type_and_predicates_False(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+ class IEvent(Interface):
+ pass
+ @implementer(IEvent)
+ class Event:
+ pass
+ L = []
+ def subscriber(event): L.append(event)
+ config = self._makeOne(autocommit=True)
+ predlist = config._get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, IEvent, jam=True, jim=True)
+ event = Event()
+ event.jam = True
+ event.jim = False
+ config.registry.notify(event)
+ self.assertEqual(len(L), 0)
+
+ def test_add_subscriber_with_default_type_predicates_False(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+ class IEvent(Interface):
+ pass
+ @implementer(IEvent)
+ class Event:
+ pass
+ L = []
+ def subscriber(event): L.append(event)
+ config = self._makeOne(autocommit=True)
+ predlist = config._get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, jam=True, jim=True)
+ event = Event()
+ event.jam = False
+ event.jim = True
+ config.registry.notify(event)
+ self.assertEqual(len(L), 0)
+
+ def test_add_subscriber_predicate(self):
+ config = self._makeOne()
+ L = []
+ def add_predicate(type, name, factory, weighs_less_than=None,
+ weighs_more_than=None):
+ self.assertEqual(type, 'subscriber')
+ self.assertEqual(name, 'name')
+ self.assertEqual(factory, 'factory')
+ self.assertEqual(weighs_more_than, 1)
+ self.assertEqual(weighs_less_than, 2)
+ L.append(1)
+ config._add_predicate = add_predicate
+ config.add_subscriber_predicate('name', 'factory', 1, 2)
+ self.assertTrue(L)
+
def test_add_response_adapter(self):
from pyramid.interfaces import IResponse
config = self._makeOne(autocommit=True)
@@ -228,4 +343,14 @@ def __init__(self, resource, request):
self.resource = resource
self.request = request
-
+def predicate_maker(name):
+ class Predicate(object):
+ def __init__(self, val, config):
+ self.val = val
+ def phash(self):
+ return 'phash'
+ text = phash
+ def __call__(self, event):
+ return getattr(event, name, None) == self.val
+ return Predicate
+
View
21 pyramid/tests/test_events.py
@@ -131,9 +131,9 @@ def setUp(self):
def tearDown(self):
testing.tearDown()
- def _makeOne(self, *ifaces):
+ def _makeOne(self, *ifaces, **predicates):
from pyramid.events import subscriber
- return subscriber(*ifaces)
+ return subscriber(*ifaces, **predicates)
def test_register_single(self):
from zope.interface import Interface
@@ -190,6 +190,16 @@ def foo(): pass
self.assertEqual(dummy_venusian.attached,
[(foo, dec.register, 'pyramid')])
+ def test_regsister_with_predicates(self):
+ from zope.interface import Interface
+ dec = self._makeOne(a=1)
+ def foo(): pass
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.subscribed, [(foo, Interface, {'a':1})])
+
class TestBeforeRender(unittest.TestCase):
def _makeOne(self, system, val=None):
from pyramid.events import BeforeRender
@@ -264,8 +274,11 @@ class DummyConfigurator(object):
def __init__(self):
self.subscribed = []
- def add_subscriber(self, wrapped, ifaces):
- self.subscribed.append((wrapped, ifaces))
+ def add_subscriber(self, wrapped, ifaces, **predicates):
+ if not predicates:
+ self.subscribed.append((wrapped, ifaces))
+ else:
+ self.subscribed.append((wrapped, ifaces, predicates))
class DummyRegistry(object):
pass
Please sign in to comment.
Something went wrong with that request. Please try again.