Michael Merickel
2012-01-11 74d50369d99ce75d91aa73ee5d2ac336a94c44e1
Added config.set_request_property().

This is a wrapper around request.set_property() which provides conflict
detection for addons.
3 files modified
136 ■■■■■ changed files
pyramid/config/factories.py 57 ●●●●● patch | view | raw | blame | history
pyramid/interfaces.py 4 ●●●● patch | view | raw | blame | history
pyramid/tests/test_config/test_factories.py 75 ●●●●● patch | view | raw | blame | history
pyramid/config/factories.py
@@ -2,7 +2,9 @@
from pyramid.interfaces import (
    IDefaultRootFactory,
    INewRequest,
    IRequestFactory,
    IRequestProperties,
    IRootFactory,
    ISessionFactory,
    )
@@ -85,3 +87,58 @@
        intr['factory'] = factory
        self.action(IRequestFactory, register, introspectables=(intr,))
    @action_method
    def set_request_property(self, callable, name=None, reify=False):
        """ Add a property to the request object.
        ``callable`` can either be a callable that accepts the request
        as its single positional parameter, or it can be a property
        descriptor. It may also be a :term:`dotted Python name` which
        refers to either a callable or a property descriptor.
        If the ``callable`` is a property descriptor a ``ValueError``
        will be raised if ``name`` is ``None`` or ``reify`` is ``True``.
        If ``name`` is None, the name of the property will be computed
        from the name of the ``callable``.
        See :meth:`pyramid.request.Request.set_property` for more
        information on its usage.
        This is the recommended method for extending the request object
        and should be used in favor of providing a custom request
        factory via
        :meth:`pyramid.config.Configurator.set_request_factory`.
        .. versionadded:: 1.3
        """
        callable = self.maybe_dotted(callable)
        if name is None:
            name = callable.__name__
        def register():
            plist = self.registry.queryUtility(IRequestProperties)
            if plist is None:
                plist = []
                self.registry.registerUtility(plist, IRequestProperties)
                self.registry.registerHandler(_set_request_properties,
                                              (INewRequest,))
            plist.append((name, callable, reify))
        intr = self.introspectable('request properties', name,
                                   self.object_description(callable),
                                   'request property')
        intr['callable'] = callable
        intr['reify'] = reify
        self.action(('request properties', name), register,
                    introspectables=(intr,))
def _set_request_properties(event):
    request = event.request
    plist = request.registry.queryUtility(IRequestProperties)
    for prop in plist:
        name, callable, reify = prop
        request.set_property(callable, name=name, reify=reify)
pyramid/interfaces.py
@@ -511,6 +511,10 @@
IRequest.combined = IRequest # for exception view lookups
class IRequestProperties(Interface):
    """ Marker interface for storing a list of request properties which
    will be added to the request object."""
class IRouteRequest(Interface):
    """ *internal only* interface used as in a utility lookup to find
    route-specific interfaces.  Not an API."""
pyramid/tests/test_config/test_factories.py
@@ -40,7 +40,7 @@
        config.commit()
        self.assertEqual(config.registry.getUtility(IRootFactory),
                         DefaultRootFactory)
    def test_set_root_factory_dottedname(self):
        from pyramid.interfaces import IRootFactory
        config = self._makeOne()
@@ -48,7 +48,7 @@
        self.assertEqual(config.registry.queryUtility(IRootFactory), None)
        config.commit()
        self.assertEqual(config.registry.getUtility(IRootFactory), dummyfactory)
    def test_set_session_factory(self):
        from pyramid.interfaces import ISessionFactory
        config = self._makeOne()
@@ -67,4 +67,75 @@
        self.assertEqual(config.registry.getUtility(ISessionFactory),
                         dummyfactory)
    def test_set_request_property_with_callable(self):
        from pyramid.interfaces import IRequestProperties
        config = self._makeOne(autocommit=True)
        callable = lambda x: None
        config.set_request_property(callable, name='foo')
        plist = config.registry.getUtility(IRequestProperties)
        self.assertEqual(plist, [('foo', callable, False)])
    def test_set_request_property_with_unnamed_callable(self):
        from pyramid.interfaces import IRequestProperties
        config = self._makeOne(autocommit=True)
        def foo(self): pass
        config.set_request_property(foo, reify=True)
        plist = config.registry.getUtility(IRequestProperties)
        self.assertEqual(plist, [('foo', foo, True)])
    def test_set_request_property_with_property(self):
        from pyramid.interfaces import IRequestProperties
        config = self._makeOne(autocommit=True)
        callable = property(lambda x: None)
        config.set_request_property(callable, name='foo')
        plist = config.registry.getUtility(IRequestProperties)
        self.assertEqual(plist, [('foo', callable, False)])
    def test_set_multiple_request_properties(self):
        from pyramid.interfaces import IRequestProperties
        config = self._makeOne()
        def foo(self): pass
        bar = property(lambda x: None)
        config.set_request_property(foo, reify=True)
        config.set_request_property(bar, name='bar')
        config.commit()
        plist = config.registry.getUtility(IRequestProperties)
        self.assertEqual(plist, [('foo', foo, True),
                                 ('bar', bar, False)])
    def test_set_multiple_request_properties_conflict(self):
        from pyramid.exceptions import ConfigurationConflictError
        config = self._makeOne()
        def foo(self): pass
        bar = property(lambda x: None)
        config.set_request_property(foo, name='bar', reify=True)
        config.set_request_property(bar, name='bar')
        self.assertRaises(ConfigurationConflictError, config.commit)
    def test_set_request_property_subscriber(self):
        from zope.interface import implementer
        from pyramid.interfaces import INewRequest
        config = self._makeOne()
        def foo(r): pass
        config.set_request_property(foo, name='foo')
        config.set_request_property(foo, name='bar', reify=True)
        config.commit()
        @implementer(INewRequest)
        class Event(object):
            request = DummyRequest(config.registry)
        event = Event()
        config.registry.notify(event)
        callables = event.request.callables
        self.assertEqual(callables, [('foo', foo, False),
                                     ('bar', foo, True)])
class DummyRequest(object):
    callables = None
    def __init__(self, registry):
        self.registry = registry
    def set_property(self, callable, name, reify):
        if self.callables is None:
            self.callables = []
        self.callables.append((name, callable, reify))