Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/pyramid/router.py : 17%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from zope.interface import implementer, providedBy
3from pyramid.interfaces import (
4 IDebugLogger,
5 IExecutionPolicy,
6 IRequest,
7 IRequestExtensions,
8 IRootFactory,
9 IRouteRequest,
10 IRouter,
11 IRequestFactory,
12 IRoutesMapper,
13 ITraverser,
14 ITweens,
15)
17from pyramid.events import (
18 ContextFound,
19 NewRequest,
20 NewResponse,
21 BeforeTraversal,
22)
24from pyramid.httpexceptions import HTTPNotFound
25from pyramid.request import Request
26from pyramid.view import _call_view
27from pyramid.request import apply_request_extensions
28from pyramid.threadlocal import RequestContext
30from pyramid.traversal import DefaultRootFactory, ResourceTreeTraverser
33@implementer(IRouter)
34class Router(object):
36 debug_notfound = False
37 debug_routematch = False
39 def __init__(self, registry):
40 q = registry.queryUtility
41 self.logger = q(IDebugLogger)
42 self.root_factory = q(IRootFactory, default=DefaultRootFactory)
43 self.routes_mapper = q(IRoutesMapper)
44 self.request_factory = q(IRequestFactory, default=Request)
45 self.request_extensions = q(IRequestExtensions)
46 self.execution_policy = q(
47 IExecutionPolicy, default=default_execution_policy
48 )
49 self.orig_handle_request = self.handle_request
50 tweens = q(ITweens)
51 if tweens is not None:
52 self.handle_request = tweens(self.handle_request, registry)
53 self.root_policy = self.root_factory # b/w compat
54 self.registry = registry
55 settings = registry.settings
56 if settings is not None:
57 self.debug_notfound = settings['debug_notfound']
58 self.debug_routematch = settings['debug_routematch']
60 def handle_request(self, request):
61 attrs = request.__dict__
62 registry = attrs['registry']
64 request.request_iface = IRequest
65 context = None
66 routes_mapper = self.routes_mapper
67 debug_routematch = self.debug_routematch
68 adapters = registry.adapters
69 has_listeners = registry.has_listeners
70 notify = registry.notify
71 logger = self.logger
73 has_listeners and notify(NewRequest(request))
74 # find the root object
75 root_factory = self.root_factory
76 if routes_mapper is not None:
77 info = routes_mapper(request)
78 match, route = info['match'], info['route']
79 if route is None:
80 if debug_routematch:
81 msg = 'no route matched for url %s' % request.url
82 logger and logger.debug(msg)
83 else:
84 attrs['matchdict'] = match
85 attrs['matched_route'] = route
87 if debug_routematch:
88 msg = (
89 'route matched for url %s; '
90 'route_name: %r, '
91 'path_info: %r, '
92 'pattern: %r, '
93 'matchdict: %r, '
94 'predicates: %r'
95 % (
96 request.url,
97 route.name,
98 request.path_info,
99 route.pattern,
100 match,
101 ', '.join([p.text() for p in route.predicates]),
102 )
103 )
104 logger and logger.debug(msg)
106 request.request_iface = registry.queryUtility(
107 IRouteRequest, name=route.name, default=IRequest
108 )
110 root_factory = route.factory or self.root_factory
112 # Notify anyone listening that we are about to start traversal
113 #
114 # Notify before creating root_factory in case we want to do something
115 # special on a route we may have matched. See
116 # https://github.com/Pylons/pyramid/pull/1876 for ideas of what is
117 # possible.
118 has_listeners and notify(BeforeTraversal(request))
120 # Create the root factory
121 root = root_factory(request)
122 attrs['root'] = root
124 # We are about to traverse and find a context
125 traverser = adapters.queryAdapter(root, ITraverser)
126 if traverser is None:
127 traverser = ResourceTreeTraverser(root)
128 tdict = traverser(request)
130 context, view_name, subpath, traversed, vroot, vroot_path = (
131 tdict['context'],
132 tdict['view_name'],
133 tdict['subpath'],
134 tdict['traversed'],
135 tdict['virtual_root'],
136 tdict['virtual_root_path'],
137 )
139 attrs.update(tdict)
141 # Notify anyone listening that we have a context and traversal is
142 # complete
143 has_listeners and notify(ContextFound(request))
145 # find a view callable
146 context_iface = providedBy(context)
147 response = _call_view(
148 registry, request, context, context_iface, view_name
149 )
151 if response is None:
152 if self.debug_notfound:
153 msg = (
154 'debug_notfound of url %s; path_info: %r, '
155 'context: %r, view_name: %r, subpath: %r, '
156 'traversed: %r, root: %r, vroot: %r, '
157 'vroot_path: %r'
158 % (
159 request.url,
160 request.path_info,
161 context,
162 view_name,
163 subpath,
164 traversed,
165 root,
166 vroot,
167 vroot_path,
168 )
169 )
170 logger and logger.debug(msg)
171 else:
172 msg = request.path_info
173 raise HTTPNotFound(msg)
175 return response
177 def invoke_subrequest(self, request, use_tweens=False):
178 """Obtain a response object from the Pyramid application based on
179 information in the ``request`` object provided. The ``request``
180 object must be an object that implements the Pyramid request
181 interface (such as a :class:`pyramid.request.Request` instance). If
182 ``use_tweens`` is ``True``, the request will be sent to the
183 :term:`tween` in the tween stack closest to the request ingress. If
184 ``use_tweens`` is ``False``, the request will be sent to the main
185 router handler, and no tweens will be invoked.
187 See the API for pyramid.request for complete documentation.
188 """
189 request.registry = self.registry
190 request.invoke_subrequest = self.invoke_subrequest
191 extensions = self.request_extensions
192 if extensions is not None:
193 apply_request_extensions(request, extensions=extensions)
194 with RequestContext(request):
195 return self.invoke_request(request, _use_tweens=use_tweens)
197 def request_context(self, environ):
198 """
199 Create a new request context from a WSGI environ.
201 The request context is used to push/pop the threadlocals required
202 when processing the request. It also contains an initialized
203 :class:`pyramid.interfaces.IRequest` instance using the registered
204 :class:`pyramid.interfaces.IRequestFactory`. The context may be
205 used as a context manager to control the threadlocal lifecycle:
207 .. code-block:: python
209 with router.request_context(environ) as request:
210 ...
212 Alternatively, the context may be used without the ``with`` statement
213 by manually invoking its ``begin()`` and ``end()`` methods.
215 .. code-block:: python
217 ctx = router.request_context(environ)
218 request = ctx.begin()
219 try:
220 ...
221 finally:
222 ctx.end()
224 """
225 request = self.request_factory(environ)
226 request.registry = self.registry
227 request.invoke_subrequest = self.invoke_subrequest
228 extensions = self.request_extensions
229 if extensions is not None:
230 apply_request_extensions(request, extensions=extensions)
231 return RequestContext(request)
233 def invoke_request(self, request, _use_tweens=True):
234 """
235 Execute a request through the request processing pipeline and
236 return the generated response.
238 """
239 registry = self.registry
240 has_listeners = registry.has_listeners
241 notify = registry.notify
243 if _use_tweens:
244 handle_request = self.handle_request
245 else:
246 handle_request = self.orig_handle_request
248 try:
249 response = handle_request(request)
251 if request.response_callbacks:
252 request._process_response_callbacks(response)
254 has_listeners and notify(NewResponse(request, response))
256 return response
258 finally:
259 if request.finished_callbacks:
260 request._process_finished_callbacks()
262 def __call__(self, environ, start_response):
263 """
264 Accept ``environ`` and ``start_response``; create a
265 :term:`request` and route the request to a :app:`Pyramid`
266 view based on introspection of :term:`view configuration`
267 within the application registry; call ``start_response`` and
268 return an iterable.
269 """
270 response = self.execution_policy(environ, self)
271 return response(environ, start_response)
274def default_execution_policy(environ, router):
275 with router.request_context(environ) as request:
276 try:
277 return router.invoke_request(request)
278 except Exception:
279 return request.invoke_exception_view(reraise=True)