diff options
| -rw-r--r-- | CHANGES.txt | 107 | ||||
| -rw-r--r-- | docs/api/request.rst | 2 | ||||
| -rw-r--r-- | pyramid/config.py | 2 | ||||
| -rw-r--r-- | pyramid/request.py | 64 | ||||
| -rw-r--r-- | pyramid/router.py | 7 | ||||
| -rw-r--r-- | pyramid/tests/test_request.py | 30 | ||||
| -rw-r--r-- | pyramid/tests/test_router.py | 91 |
7 files changed, 32 insertions, 271 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index b1979347a..c9c95fd7f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -8,71 +8,28 @@ Features ``rendering_val``. This can be used to introspect the value returned by a view in a BeforeRender subscriber. -- New method: ``pyramid.request.Request.add_view_wrapper``. A view wrapper - is used to wrap the found view callable before it is called by Pyramid's - router. This is a feature usually only used by framework extensions, to - provide, for example, view timing support. - - A view wrapper factory must be a callable which accepts three arguments: - ``view_callable``, ``request``, and ``exc``. It must return a view - callable. The view callable returned by the factory must implement the - ``context, request`` view callable calling convention. For example:: - - import time - - def wrapper_factory(view_callable, request, exc): - def wrapper(context, request): - start = time.time() - result = view_callable(context, request) - end = time.time() - request.view_timing = end - start - return result - return wrapper - - The ``view_callable`` argument to the factory will be the view callable - found by Pyramid via view lookup. The ``request`` argument to the factory - will be the current request. The ``exc`` argument to the factory will be - an Exception object if the found view is an exception view; it will be - ``None`` otherwise. - - View wrappers only last for the duration of a single request. You can add - such a factory for every request by using the - ``pyramid.events.NewRequest`` subscriber:: - - from pyramid.events import subscriber, NewRequest - - @subscriber(NewRequest) - def newrequest(event): - event.request.add_view_wrapper(wrapper_factory) - - If more than one view wrapper is registered during a single request, - a 'later' view wrapper factory will be called with the result of its - directly former view wrapper factory as its ``view_callable`` - argument; this chain will be returned to Pyramid as a single view - callable. - - New configurator directive: - ``pyramid.config.Configurator.add_request_handler``. This directive adds - a request handler factory. + ``pyramid.config.Configurator.add_request_handler``. This directive adds + a request handler factory. - A request handler factory is used to wrap the Pyramid router's primary - request handling function. This is a feature usually only used by - framework extensions, to provide, for example, view timing support and as - a convenient place to hang bookkeeping code that examines exceptions - before they are returned to the server. + A request handler factory is used to wrap the Pyramid router's primary + request handling function. This is a feature may be used by framework + extensions, to provide, for example, view timing support and as a + convenient place to hang bookkeeping code that examines exceptions before + they are returned to the server. - A request handler factory (passed as ``handler_factory``) must be a - callable which accepts two arguments: ``handler`` and ``registry``. - ``handler`` will be the request handler being wrapped. ``registry`` will - be the Pyramid application registry represented by this Configurator. A - request handler factory must return a request handler when it is called. + A request handler factory (passed as ``handler_factory``) must be a + callable which accepts two arguments: ``handler`` and ``registry``. + ``handler`` will be the request handler being wrapped. ``registry`` will + be the Pyramid application registry represented by this Configurator. A + request handler factory must return a request handler when it is called. - A request handler accepts a request object and returns a response object. + A request handler accepts a request object and returns a response object. - Here's an example of creating both a handler factory and a handler, and - registering the handler factory: + Here's an example of creating both a handler factory and a handler, and + registering the handler factory: - .. code-block:: python + .. code-block:: python import time @@ -93,23 +50,21 @@ Features config.add_request_handler(timing_handler_factory, 'timing') - The ``request`` argument to the handler will be the request created by - Pyramid's router when it receives a WSGI request. - - If more than one request handler factory is registered into a single - configuration, the request handlers will be chained together. The first - request handler factory added (in code execution order) will be called - with the default Pyramid request handler, the second handler factory added - will be called with the result of the first handler factory, ad - infinitum. The Pyramid router will use the outermost wrapper in this chain - (which is a bit like a WSGI middleware "pipeline") as its handler - function. - - The ``name`` argument to this function is required. The name is used as a - key for conflict detection. No two request handler factories may share - the same name in the same configuration (unless - automatic_conflict_resolution is able to resolve the conflict or - this is an autocommitting configurator). + The ``request`` argument to the handler will be the request created by + Pyramid's router when it receives a WSGI request. + + If more than one request handler factory is registered into a single + configuration, the request handlers will be chained together. The first + request handler factory added (in code execution order) will be called with + the default Pyramid request handler, the second handler factory added will + be called with the result of the first handler factory, ad infinitum. The + Pyramid router will use the outermost wrapper in this chain (which is a bit + like a WSGI middleware "pipeline") as its handler function. + + The ``name`` argument to this function is required. The name is used as a + key for conflict detection. No two request handler factories may share the + same name in the same configuration (unless automatic_conflict_resolution + is able to resolve the conflict or this is an autocommitting configurator). 1.1 (2011-07-22) ================ diff --git a/docs/api/request.rst b/docs/api/request.rst index 58532bbd1..404825d1b 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -154,8 +154,6 @@ .. automethod:: add_finished_callback - .. automethod:: add_view_wrapper - .. automethod:: route_url .. automethod:: route_path diff --git a/pyramid/config.py b/pyramid/config.py index 6c47e7871..d6a87c7ad 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -892,7 +892,7 @@ class Configurator(object): """ Add a request handler factory. A request handler factory is used to wrap the Pyramid router's primary request handling function. This is - a feature usually only used by framework extensions, to provide, for + a feature that may be used by framework extensions, to provide, for example, view timing support and as a convenient place to hang bookkeeping code that examines exceptions before they are returned to the server. diff --git a/pyramid/request.py b/pyramid/request.py index 927319479..8df204681 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -203,7 +203,6 @@ class Request(BaseRequest, DeprecatedRequestMethods): implements(IRequest) response_callbacks = () finished_callbacks = () - view_wrappers = () exception = None matchdict = None matched_route = None @@ -213,69 +212,6 @@ class Request(BaseRequest, DeprecatedRequestMethods): """ Template context (for Pylons apps) """ return TemplateContext() - def add_view_wrapper(self, wrapper): - """ - Add a view wrapper factory. A view wrapper is used to wrap the found - view callable before it is called by Pyramid's router. This is a - feature usually only used by framework extensions, to provide, for - example, view timing support. - - A view wrapper factory must be a callable which accepts three - arguments: ``view_callable``, ``request``, and ``exc``. It must - return a view callable. The view callable returned by the factory - must implement the ``context, request`` view callable calling - convention. For example: - - .. code-block:: python - - import time - - def wrapper_factory(view_callable, request, exc): - def wrapper(context, request): - start = time.time() - result = view_callable(context, request) - end = time.time() - request.view_timing = end - start - return result - return wrapper - - The ``view_callable`` argument to the factory will be the view - callable found by Pyramid via :term:`view lookup`. The ``request`` - argument to the factory will be the current request. The ``exc`` - argument to the factory will be an Exception object if the found view - is a :term:`exception view`; it will be ``None`` otherwise. - - View wrappers only last for the duration of a single request. You - can add such a factory for every request by using the - :class:`pyramid.events.NewRequest` subscriber: - - .. code-block:: python - - from pyramid.events import subscriber, NewRequest - - @subscriber(NewRequest) - def newrequest(event): - event.request.add_view_wrapper(wrapper_factory) - - If more than one view wrapper is registered during a single request, - a 'later' view wrapper factory will be called with the result of its - directly former view wrapper factory as its ``view_callable`` - argument; this chain will be returned to Pyramid as a single view - callable. - - .. note:: This feature is new as of Pyramid 1.1.1. - """ - wrappers = self.view_wrappers - if not wrappers: - wrappers = [] - wrappers.append(wrapper) - self.view_wrappers = wrappers - - def _wrap_view(self, view, exc=None): - for wrapper in self.view_wrappers: - view = wrapper(view, self, exc) - return view - def add_response_callback(self, callback): """ Add a callback to the set of callbacks to be called by the diff --git a/pyramid/router.py b/pyramid/router.py index dcf257beb..e8c19fca0 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -160,9 +160,6 @@ class Router(object): else: # if there were any view wrappers for the current # request, use them to wrap the view - if request.view_wrappers: - view_callable = request._wrap_view( - view_callable) response = view_callable(context, request) @@ -185,10 +182,6 @@ class Router(object): if view_callable is None: raise - if request.view_wrappers: - view_callable = request._wrap_view(view_callable, - exc=why) - response = view_callable(why, request) has_listeners and notify(NewResponse(request, response)) diff --git a/pyramid/tests/test_request.py b/pyramid/tests/test_request.py index 3c24c8f58..066aa9207 100644 --- a/pyramid/tests/test_request.py +++ b/pyramid/tests/test_request.py @@ -145,36 +145,6 @@ class TestRequest(unittest.TestCase): self.assertEqual(inst.called2, True) self.assertEqual(inst.finished_callbacks, []) - def test_add_view_wrapper(self): - inst = self._makeOne({}) - wrapper = object() - inst.add_view_wrapper(wrapper) - self.assertEqual(inst.view_wrappers, [wrapper]) - - def test_add_view_wrapper_wrappers_exist(self): - inst = self._makeOne({}) - inst.view_wrappers = [123] - wrapper = object() - inst.add_view_wrapper(wrapper) - self.assertEqual(inst.view_wrappers, [123, wrapper]) - - def test__wrap_view_no_wrappers(self): - inst = self._makeOne({}) - wrapped = inst._wrap_view(lambda *arg: 'OK') - self.assertEqual(wrapped(), 'OK') - - def test__wrap_view_with_wrappers_no_exc(self): - inst = self._makeOne({}) - def view(*arg): return 'OK' - def view_wrapper(_view, request, exc): - self.assertEqual(_view, view) - self.assertEqual(request, inst) - self.assertEqual(exc, '123') - return _view - inst.view_wrappers = [view_wrapper] - wrapped = inst._wrap_view(view, exc='123') - self.assertEqual(wrapped(), 'OK') - def test_resource_url(self): self._registerContextURL() inst = self._makeOne({}) diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py index a1e7252e9..4d44de5c0 100644 --- a/pyramid/tests/test_router.py +++ b/pyramid/tests/test_router.py @@ -546,97 +546,6 @@ class TestRouter(unittest.TestCase): exc_raised(NotImplementedError, router, environ, start_response) self.assertEqual(environ['called_back'], True) - def test_call_request_has_view_wrappers(self): - from zope.interface import Interface - from zope.interface import directlyProvides - class IContext(Interface): - pass - from pyramid.interfaces import IRequest - from pyramid.interfaces import IViewClassifier - from pyramid.interfaces import INewRequest - wrappers = [] - class ViewWrapper(object): - def __call__(self, view, request, exc): - self.view = view - self.exc = exc - wrappers.append(self) - return self.wrap - def wrap(self, context, request): - return self.view(context, request) - wrapper1 = ViewWrapper() - wrapper2 = ViewWrapper() - def newrequest(event): - event.request.view_wrappers = [wrapper1, wrapper2] - self.registry.registerHandler(newrequest, (INewRequest,)) - context = DummyContext() - directlyProvides(context, IContext) - self._registerTraverserFactory(context, subpath=['']) - response = DummyResponse('200 OK') - response.app_iter = ['OK'] - def view(context, request): - return response - environ = self._makeEnviron() - self._registerView(view, '', IViewClassifier, IRequest, IContext) - router = self._makeOne() - start_response = DummyStartResponse() - itera = router(environ, start_response) - wrapper1, wrapper2 = wrappers - self.assertEqual(wrapper1.view, view) - self.assertEqual(wrapper2.view, wrapper1.wrap) - self.assertEqual(wrapper1.exc, None) - self.assertEqual(wrapper2.exc, None) - self.assertEqual(itera, ['OK']) - - def test_call_request_has_view_wrappers_in_exception(self): - from zope.interface import Interface - from zope.interface import directlyProvides - class IContext(Interface): - pass - from pyramid.interfaces import IRequest - from pyramid.interfaces import IViewClassifier - from pyramid.interfaces import INewRequest - from pyramid.interfaces import IExceptionViewClassifier - wrappers = [] - class ViewWrapper(object): - def __init__(self): - self.views = [] - self.exc = [] - def __call__(self, view, request, exc): - self.views.append(view) - self.exc.append(exc) - wrappers.append(self) - return self.wrap - def wrap(self, context, request): - return self.views[-1](context, request) - wrapper1 = ViewWrapper() - wrapper2 = ViewWrapper() - def newrequest(event): - event.request.view_wrappers = [wrapper1, wrapper2] - self.registry.registerHandler(newrequest, (INewRequest,)) - context = DummyContext() - directlyProvides(context, IContext) - self._registerTraverserFactory(context, subpath=['']) - error = NotImplementedError() - def view(context, request): - raise error - environ = self._makeEnviron() - self._registerView(view, '', IViewClassifier, IRequest, IContext) - exception_response = DummyResponse('404 Not Found') - exception_response.app_iter = ['Not Found'] - exception_view = DummyView(exception_response) - environ = self._makeEnviron() - self._registerView(exception_view, '', IExceptionViewClassifier, - IRequest, NotImplementedError) - router = self._makeOne() - start_response = DummyStartResponse() - itera = router(environ, start_response) - wrapper1, wrapper2, wrapper3, wrapper4 = wrappers - self.assertEqual(wrapper1.views, [view, exception_view]) - self.assertEqual(wrapper2.views, [wrapper1.wrap, wrapper1.wrap]) - self.assertEqual(wrapper1.exc, [None, error]) - self.assertEqual(wrapper2.exc, [None, error]) - self.assertEqual(itera, ['Not Found']) - def test_call_request_factory_raises(self): # making sure finally doesnt barf when a request cannot be created environ = self._makeEnviron() |
