commit | author | age
|
efd61e
|
1 |
import contextlib |
b01f1d
|
2 |
import warnings |
CM |
3 |
|
84367e
|
4 |
from pyramid.compat import urlparse |
ee117e
|
5 |
from pyramid.interfaces import ( |
CM |
6 |
IRequest, |
|
7 |
IRouteRequest, |
|
8 |
IRoutesMapper, |
|
9 |
PHASE2_CONFIG, |
0c29cf
|
10 |
) |
5bf23f
|
11 |
|
CM |
12 |
from pyramid.exceptions import ConfigurationError |
d579f2
|
13 |
import pyramid.predicates |
5bf23f
|
14 |
from pyramid.request import route_request_iface |
CM |
15 |
from pyramid.urldispatch import RoutesMapper |
|
16 |
|
0c29cf
|
17 |
from pyramid.util import as_sorted_tuple, is_nonstr_iter |
9c8ec5
|
18 |
|
d579f2
|
19 |
from pyramid.config.actions import action_method |
MM |
20 |
from pyramid.config.predicates import normalize_accept_offer, predvalseq |
52fde9
|
21 |
|
0c29cf
|
22 |
|
5bf23f
|
23 |
class RoutesConfiguratorMixin(object): |
CM |
24 |
@action_method |
0c29cf
|
25 |
def add_route( |
MM |
26 |
self, |
|
27 |
name, |
|
28 |
pattern=None, |
|
29 |
factory=None, |
|
30 |
for_=None, |
|
31 |
header=None, |
|
32 |
xhr=None, |
|
33 |
accept=None, |
|
34 |
path_info=None, |
|
35 |
request_method=None, |
|
36 |
request_param=None, |
|
37 |
traverse=None, |
|
38 |
custom_predicates=(), |
|
39 |
use_global_views=False, |
|
40 |
path=None, |
|
41 |
pregenerator=None, |
|
42 |
static=False, |
|
43 |
**predicates |
|
44 |
): |
5bf23f
|
45 |
""" Add a :term:`route configuration` to the current |
CM |
46 |
configuration state, as well as possibly a :term:`view |
|
47 |
configuration` to be used to specify a :term:`view callable` |
|
48 |
that will be invoked when this route matches. The arguments |
|
49 |
to this method are divided into *predicate*, *non-predicate*, |
|
50 |
and *view-related* types. :term:`Route predicate` arguments |
|
51 |
narrow the circumstances in which a route will be match a |
|
52 |
request; non-predicate arguments are informational. |
|
53 |
|
|
54 |
Non-Predicate Arguments |
|
55 |
|
|
56 |
name |
|
57 |
|
|
58 |
The name of the route, e.g. ``myroute``. This attribute is |
|
59 |
required. It must be unique among all defined routes in a given |
|
60 |
application. |
|
61 |
|
|
62 |
factory |
|
63 |
|
|
64 |
A Python object (often a function or a class) or a :term:`dotted |
|
65 |
Python name` which refers to the same object that will generate a |
|
66 |
:app:`Pyramid` root resource object when this route matches. For |
|
67 |
example, ``mypackage.resources.MyFactory``. If this argument is |
0507ac
|
68 |
not specified, a default root factory will be used. See |
CM |
69 |
:ref:`the_resource_tree` for more information about root factories. |
5bf23f
|
70 |
|
CM |
71 |
traverse |
|
72 |
|
|
73 |
If you would like to cause the :term:`context` to be |
|
74 |
something other than the :term:`root` object when this route |
|
75 |
matches, you can spell a traversal pattern as the |
|
76 |
``traverse`` argument. This traversal pattern will be used |
|
77 |
as the traversal path: traversal will begin at the root |
|
78 |
object implied by this route (either the global root, or the |
|
79 |
object returned by the ``factory`` associated with this |
|
80 |
route). |
|
81 |
|
|
82 |
The syntax of the ``traverse`` argument is the same as it is |
|
83 |
for ``pattern``. For example, if the ``pattern`` provided to |
|
84 |
``add_route`` is ``articles/{article}/edit``, and the |
|
85 |
``traverse`` argument provided to ``add_route`` is |
|
86 |
``/{article}``, when a request comes in that causes the route |
|
87 |
to match in such a way that the ``article`` match value is |
f1f49b
|
88 |
``'1'`` (when the request URI is ``/articles/1/edit``), the |
5bf23f
|
89 |
traversal path will be generated as ``/1``. This means that |
CM |
90 |
the root object's ``__getitem__`` will be called with the |
f1f49b
|
91 |
name ``'1'`` during the traversal phase. If the ``'1'`` object |
5bf23f
|
92 |
exists, it will become the :term:`context` of the request. |
CM |
93 |
:ref:`traversal_chapter` has more information about |
|
94 |
traversal. |
|
95 |
|
|
96 |
If the traversal path contains segment marker names which |
|
97 |
are not present in the ``pattern`` argument, a runtime error |
|
98 |
will occur. The ``traverse`` pattern should not contain |
|
99 |
segment markers that do not exist in the ``pattern`` |
|
100 |
argument. |
|
101 |
|
|
102 |
A similar combining of routing and traversal is available |
|
103 |
when a route is matched which contains a ``*traverse`` |
|
104 |
remainder marker in its pattern (see |
|
105 |
:ref:`using_traverse_in_a_route_pattern`). The ``traverse`` |
|
106 |
argument to add_route allows you to associate route patterns |
043ccd
|
107 |
with an arbitrary traversal path without using a |
5bf23f
|
108 |
``*traverse`` remainder marker; instead you can use other |
CM |
109 |
match information. |
|
110 |
|
|
111 |
Note that the ``traverse`` argument to ``add_route`` is |
|
112 |
ignored when attached to a route that has a ``*traverse`` |
|
113 |
remainder marker in its pattern. |
|
114 |
|
|
115 |
pregenerator |
|
116 |
|
|
117 |
This option should be a callable object that implements the |
|
118 |
:class:`pyramid.interfaces.IRoutePregenerator` interface. A |
|
119 |
:term:`pregenerator` is a callable called by the |
|
120 |
:meth:`pyramid.request.Request.route_url` function to augment or |
|
121 |
replace the arguments it is passed when generating a URL for the |
|
122 |
route. This is a feature not often used directly by applications, |
|
123 |
it is meant to be hooked by frameworks that use :app:`Pyramid` as |
|
124 |
a base. |
|
125 |
|
|
126 |
use_global_views |
|
127 |
|
|
128 |
When a request matches this route, and view lookup cannot |
|
129 |
find a view which has a ``route_name`` predicate argument |
|
130 |
that matches the route, try to fall back to using a view |
|
131 |
that otherwise matches the context, request, and view name |
|
132 |
(but which does not match the route_name predicate). |
|
133 |
|
|
134 |
static |
|
135 |
|
|
136 |
If ``static`` is ``True``, this route will never match an incoming |
|
137 |
request; it will only be useful for URL generation. By default, |
|
138 |
``static`` is ``False``. See :ref:`static_route_narr`. |
|
139 |
|
0b23b3
|
140 |
.. versionadded:: 1.1 |
5bf23f
|
141 |
|
CM |
142 |
Predicate Arguments |
|
143 |
|
|
144 |
pattern |
|
145 |
|
|
146 |
The pattern of the route e.g. ``ideas/{idea}``. This |
|
147 |
argument is required. See :ref:`route_pattern_syntax` |
|
148 |
for information about the syntax of route patterns. If the |
|
149 |
pattern doesn't match the current URL, route matching |
|
150 |
continues. |
|
151 |
|
012b97
|
152 |
.. note:: |
M |
153 |
|
|
154 |
For backwards compatibility purposes (as of :app:`Pyramid` 1.0), a |
|
155 |
``path`` keyword argument passed to this function will be used to |
|
156 |
represent the pattern value if the ``pattern`` argument is |
a54bc1
|
157 |
``None``. If both ``path`` and ``pattern`` are passed, |
MM |
158 |
``pattern`` wins. |
012b97
|
159 |
|
5bf23f
|
160 |
xhr |
CM |
161 |
|
|
162 |
This value should be either ``True`` or ``False``. If this |
|
163 |
value is specified and is ``True``, the :term:`request` must |
|
164 |
possess an ``HTTP_X_REQUESTED_WITH`` (aka |
|
165 |
``X-Requested-With``) header for this route to match. This |
|
166 |
is useful for detecting AJAX requests issued from jQuery, |
|
167 |
Prototype and other Javascript libraries. If this predicate |
|
168 |
returns ``False``, route matching continues. |
|
169 |
|
|
170 |
request_method |
|
171 |
|
49f082
|
172 |
A string representing an HTTP method name, e.g. ``GET``, ``POST``, |
CM |
173 |
``HEAD``, ``DELETE``, ``PUT`` or a tuple of elements containing |
|
174 |
HTTP method names. If this argument is not specified, this route |
|
175 |
will match if the request has *any* request method. If this |
|
176 |
predicate returns ``False``, route matching continues. |
|
177 |
|
0b23b3
|
178 |
.. versionchanged:: 1.2 |
TL |
179 |
The ability to pass a tuple of items as ``request_method``. |
|
180 |
Previous versions allowed only a string. |
5bf23f
|
181 |
|
CM |
182 |
path_info |
|
183 |
|
|
184 |
This value represents a regular expression pattern that will |
|
185 |
be tested against the ``PATH_INFO`` WSGI environment |
|
186 |
variable. If the regex matches, this predicate will return |
|
187 |
``True``. If this predicate returns ``False``, route |
|
188 |
matching continues. |
|
189 |
|
|
190 |
request_param |
|
191 |
|
939165
|
192 |
This value can be any string or an iterable of strings. A view |
BG |
193 |
declaration with this argument ensures that the associated route will |
|
194 |
only match when the request has a key in the ``request.params`` |
5bf23f
|
195 |
dictionary (an HTTP ``GET`` or ``POST`` variable) that has a |
CM |
196 |
name which matches the supplied value. If the value |
|
197 |
supplied as the argument has a ``=`` sign in it, |
|
198 |
e.g. ``request_param="foo=123"``, then the key |
|
199 |
(``foo``) must both exist in the ``request.params`` dictionary, and |
|
200 |
the value must match the right hand side of the expression (``123``) |
|
201 |
for the route to "match" the current request. If this predicate |
|
202 |
returns ``False``, route matching continues. |
|
203 |
|
|
204 |
header |
|
205 |
|
|
206 |
This argument represents an HTTP header name or a header |
|
207 |
name/value pair. If the argument contains a ``:`` (colon), |
|
208 |
it will be considered a name/value pair |
|
209 |
(e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). If |
|
210 |
the value contains a colon, the value portion should be a |
|
211 |
regular expression. If the value does not contain a colon, |
|
212 |
the entire value will be considered to be the header name |
|
213 |
(e.g. ``If-Modified-Since``). If the value evaluates to a |
|
214 |
header name only without a value, the header specified by |
|
215 |
the name must be present in the request for this predicate |
|
216 |
to be true. If the value evaluates to a header name/value |
|
217 |
pair, the header specified by the name must be present in |
|
218 |
the request *and* the regular expression specified as the |
|
219 |
value must match the header value. Whether or not the value |
|
220 |
represents a header name or a header name/value pair, the |
|
221 |
case of the header name is not significant. If this |
|
222 |
predicate returns ``False``, route matching continues. |
|
223 |
|
121f45
|
224 |
accept |
MM |
225 |
|
30f79d
|
226 |
A :term:`media type` that will be matched against the ``Accept`` |
4cc3a6
|
227 |
HTTP request header. If this value is specified, it may be a |
MM |
228 |
specific media type such as ``text/html``, or a list of the same. |
|
229 |
If the media type is acceptable by the ``Accept`` header of the |
|
230 |
request, or if the ``Accept`` header isn't set at all in the request, |
|
231 |
this predicate will match. If this does not match the ``Accept`` |
|
232 |
header of the request, route matching continues. |
121f45
|
233 |
|
MM |
234 |
If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is |
|
235 |
not taken into consideration when deciding whether or not to select |
|
236 |
the route. |
4a9f4f
|
237 |
|
4cc3a6
|
238 |
Unlike the ``accept`` argument to |
MM |
239 |
:meth:`pyramid.config.Configurator.add_view`, this value is |
|
240 |
strictly a predicate and supports :func:`pyramid.config.not_`. |
|
241 |
|
4a9f4f
|
242 |
.. versionchanged:: 1.10 |
MM |
243 |
|
|
244 |
Specifying a media range is deprecated due to changes in WebOb |
|
245 |
and ambiguities that occur when trying to match ranges against |
|
246 |
ranges in the ``Accept`` header. Support will be removed in |
|
247 |
:app:`Pyramid` 2.0. Use a list of specific media types to match |
|
248 |
more than one type. |
121f45
|
249 |
|
c7337b
|
250 |
effective_principals |
CM |
251 |
|
|
252 |
If specified, this value should be a :term:`principal` identifier or |
|
253 |
a sequence of principal identifiers. If the |
0184b5
|
254 |
:attr:`pyramid.request.Request.effective_principals` property |
CM |
255 |
indicates that every principal named in the argument list is present |
|
256 |
in the current request, this predicate will return True; otherwise it |
|
257 |
will return False. For example: |
c7337b
|
258 |
``effective_principals=pyramid.security.Authenticated`` or |
CM |
259 |
``effective_principals=('fred', 'group:admins')``. |
|
260 |
|
|
261 |
.. versionadded:: 1.4a4 |
|
262 |
|
5bf23f
|
263 |
custom_predicates |
CM |
264 |
|
e96f1b
|
265 |
.. deprecated:: 1.5 |
2033ee
|
266 |
This value should be a sequence of references to custom |
SP |
267 |
predicate callables. Use custom predicates when no set of |
|
268 |
predefined predicates does what you need. Custom predicates |
|
269 |
can be combined with predefined predicates as necessary. |
|
270 |
Each custom predicate callable should accept two arguments: |
|
271 |
``info`` and ``request`` and should return either ``True`` |
|
272 |
or ``False`` after doing arbitrary evaluation of the info |
|
273 |
and/or the request. If all custom and non-custom predicate |
|
274 |
callables return ``True`` the associated route will be |
|
275 |
considered viable for a given request. If any predicate |
|
276 |
callable returns ``False``, route matching continues. Note |
|
277 |
that the value ``info`` passed to a custom route predicate |
|
278 |
is a dictionary containing matching information; see |
|
279 |
:ref:`custom_route_predicates` for more information about |
|
280 |
``info``. |
5bf23f
|
281 |
|
8ec8e2
|
282 |
predicates |
9c8ec5
|
283 |
|
5664c4
|
284 |
Pass a key/value pair here to use a third-party predicate |
CM |
285 |
registered via |
cfd8cc
|
286 |
:meth:`pyramid.config.Configurator.add_route_predicate`. More than |
5664c4
|
287 |
one key/value pair can be used at the same time. See |
95f766
|
288 |
:ref:`view_and_route_predicates` for more information about |
0b23b3
|
289 |
third-party predicates. |
TL |
290 |
|
|
291 |
.. versionadded:: 1.4 |
|
292 |
|
5bf23f
|
293 |
""" |
b01f1d
|
294 |
if custom_predicates: |
CM |
295 |
warnings.warn( |
0c29cf
|
296 |
( |
a54bc1
|
297 |
'The "custom_predicates" argument to ' |
MM |
298 |
'Configurator.add_route is deprecated as of Pyramid 1.5. ' |
|
299 |
'Use "config.add_route_predicate" and use the registered ' |
0c29cf
|
300 |
'route predicate as a predicate argument to add_route ' |
MM |
301 |
'instead. See "Adding A Third Party View, Route, or ' |
|
302 |
'Subscriber Predicate" in the "Hooks" chapter of the ' |
|
303 |
'documentation for more information.' |
|
304 |
), |
c151ad
|
305 |
DeprecationWarning, |
0c29cf
|
306 |
stacklevel=3, |
MM |
307 |
) |
121f45
|
308 |
|
MM |
309 |
if accept is not None: |
c3c83e
|
310 |
if not is_nonstr_iter(accept): |
4a9f4f
|
311 |
if '*' in accept: |
MM |
312 |
warnings.warn( |
0c29cf
|
313 |
( |
a54bc1
|
314 |
'Passing a media range to the "accept" argument ' |
MM |
315 |
'of Configurator.add_route is deprecated as of ' |
|
316 |
'Pyramid 1.10. Use a list of explicit media types.' |
0c29cf
|
317 |
), |
4a9f4f
|
318 |
DeprecationWarning, |
MM |
319 |
stacklevel=3, |
0c29cf
|
320 |
) |
19eef8
|
321 |
# XXX switch this to False when range support is dropped |
MM |
322 |
accept = [normalize_accept_offer(accept, allow_range=True)] |
30f79d
|
323 |
|
4a9f4f
|
324 |
else: |
MM |
325 |
accept = [ |
|
326 |
normalize_accept_offer(accept_option) |
|
327 |
for accept_option in accept |
|
328 |
] |
121f45
|
329 |
|
5bf23f
|
330 |
# these are route predicates; if they do not match, the next route |
CM |
331 |
# in the routelist will be tried |
d8e504
|
332 |
if request_method is not None: |
CM |
333 |
request_method = as_sorted_tuple(request_method) |
|
334 |
|
5bf23f
|
335 |
factory = self.maybe_dotted(factory) |
CM |
336 |
if pattern is None: |
|
337 |
pattern = path |
|
338 |
if pattern is None: |
|
339 |
raise ConfigurationError('"pattern" argument may not be None') |
|
340 |
|
d07d16
|
341 |
# check for an external route; an external route is one which is |
CM |
342 |
# is a full url (e.g. 'http://example.com/{id}') |
84367e
|
343 |
parsed = urlparse.urlparse(pattern) |
582c2e
|
344 |
external_url = pattern |
JA |
345 |
|
84367e
|
346 |
if parsed.hostname: |
MM |
347 |
pattern = parsed.path |
|
348 |
|
|
349 |
original_pregenerator = pregenerator |
0c29cf
|
350 |
|
84367e
|
351 |
def external_url_pregenerator(request, elements, kw): |
d07d16
|
352 |
if '_app_url' in kw: |
CM |
353 |
raise ValueError( |
|
354 |
'You cannot generate a path to an external route ' |
|
355 |
'pattern via request.route_path nor pass an _app_url ' |
|
356 |
'to request.route_url when generating a URL for an ' |
0c29cf
|
357 |
'external route pattern (pattern was "%s") ' |
MM |
358 |
% (pattern,) |
|
359 |
) |
d07d16
|
360 |
if '_scheme' in kw: |
CM |
361 |
scheme = kw['_scheme'] |
|
362 |
elif parsed.scheme: |
|
363 |
scheme = parsed.scheme |
|
364 |
else: |
|
365 |
scheme = request.scheme |
|
366 |
kw['_app_url'] = '{0}://{1}'.format(scheme, parsed.netloc) |
84367e
|
367 |
|
MM |
368 |
if original_pregenerator: |
0c29cf
|
369 |
elements, kw = original_pregenerator(request, elements, kw) |
84367e
|
370 |
return elements, kw |
MM |
371 |
|
|
372 |
pregenerator = external_url_pregenerator |
|
373 |
static = True |
|
374 |
|
|
375 |
elif self.route_prefix: |
5bf23f
|
376 |
pattern = self.route_prefix.rstrip('/') + '/' + pattern.lstrip('/') |
33b638
|
377 |
|
eb2fee
|
378 |
mapper = self.get_routes_mapper() |
5bf23f
|
379 |
|
522405
|
380 |
introspectables = [] |
CM |
381 |
|
0c29cf
|
382 |
intr = self.introspectable( |
MM |
383 |
'routes', name, '%s (pattern: %r)' % (name, pattern), 'route' |
|
384 |
) |
3b5ccb
|
385 |
intr['name'] = name |
CM |
386 |
intr['pattern'] = pattern |
|
387 |
intr['factory'] = factory |
87f8d2
|
388 |
intr['xhr'] = xhr |
d8e504
|
389 |
intr['request_methods'] = request_method |
87f8d2
|
390 |
intr['path_info'] = path_info |
CM |
391 |
intr['request_param'] = request_param |
|
392 |
intr['header'] = header |
|
393 |
intr['accept'] = accept |
|
394 |
intr['traverse'] = traverse |
|
395 |
intr['custom_predicates'] = custom_predicates |
3b5ccb
|
396 |
intr['pregenerator'] = pregenerator |
CM |
397 |
intr['static'] = static |
|
398 |
intr['use_global_views'] = use_global_views |
582c2e
|
399 |
|
JA |
400 |
if static is True: |
|
401 |
intr['external_url'] = external_url |
|
402 |
|
522405
|
403 |
introspectables.append(intr) |
CM |
404 |
|
|
405 |
if factory: |
0c29cf
|
406 |
factory_intr = self.introspectable( |
MM |
407 |
'root factories', |
|
408 |
name, |
|
409 |
self.object_description(factory), |
|
410 |
'root factory', |
|
411 |
) |
522405
|
412 |
factory_intr['factory'] = factory |
CM |
413 |
factory_intr['route_name'] = name |
|
414 |
factory_intr.relate('routes', name) |
|
415 |
introspectables.append(factory_intr) |
3b5ccb
|
416 |
|
de79bc
|
417 |
def register_route_request_iface(): |
0c29cf
|
418 |
request_iface = self.registry.queryUtility( |
MM |
419 |
IRouteRequest, name=name |
|
420 |
) |
b9f2f5
|
421 |
if request_iface is None: |
MM |
422 |
if use_global_views: |
|
423 |
bases = (IRequest,) |
|
424 |
else: |
|
425 |
bases = () |
|
426 |
request_iface = route_request_iface(name, bases) |
|
427 |
self.registry.registerUtility( |
0c29cf
|
428 |
request_iface, IRouteRequest, name=name |
MM |
429 |
) |
b9f2f5
|
430 |
|
de79bc
|
431 |
def register_connect(): |
8ec8e2
|
432 |
pvals = predicates.copy() |
9c8ec5
|
433 |
pvals.update( |
CM |
434 |
dict( |
|
435 |
xhr=xhr, |
|
436 |
request_method=request_method, |
|
437 |
path_info=path_info, |
|
438 |
request_param=request_param, |
|
439 |
header=header, |
|
440 |
accept=accept, |
|
441 |
traverse=traverse, |
|
442 |
custom=predvalseq(custom_predicates), |
|
443 |
) |
0c29cf
|
444 |
) |
9c8ec5
|
445 |
|
405213
|
446 |
predlist = self.get_predlist('route') |
9c8ec5
|
447 |
_, preds, _ = predlist.make(self, **pvals) |
3b5ccb
|
448 |
route = mapper.connect( |
0c29cf
|
449 |
name, |
MM |
450 |
pattern, |
|
451 |
factory, |
|
452 |
predicates=preds, |
|
453 |
pregenerator=pregenerator, |
|
454 |
static=static, |
|
455 |
) |
3b5ccb
|
456 |
intr['object'] = route |
CM |
457 |
return route |
eb2fee
|
458 |
|
de79bc
|
459 |
# We have to connect routes in the order they were provided; |
CM |
460 |
# we can't use a phase to do that, because when the actions are |
|
461 |
# sorted, actions in the same phase lose relative ordering |
19a575
|
462 |
self.action(('route-connect', name), register_connect) |
de79bc
|
463 |
|
CM |
464 |
# But IRouteRequest interfaces must be registered before we begin to |
|
465 |
# process view registrations (in phase 3) |
0c29cf
|
466 |
self.action( |
MM |
467 |
('route', name), |
|
468 |
register_route_request_iface, |
|
469 |
order=PHASE2_CONFIG, |
|
470 |
introspectables=introspectables, |
|
471 |
) |
381de3
|
472 |
|
9c8ec5
|
473 |
@action_method |
0c29cf
|
474 |
def add_route_predicate( |
MM |
475 |
self, name, factory, weighs_more_than=None, weighs_less_than=None |
|
476 |
): |
9c8ec5
|
477 |
""" Adds a route predicate factory. The view predicate can later be |
CM |
478 |
named as a keyword argument to |
|
479 |
:meth:`pyramid.config.Configurator.add_route`. |
|
480 |
|
|
481 |
``name`` should be the name of the predicate. It must be a valid |
|
482 |
Python identifier (it will be used as a keyword argument to |
cfd8cc
|
483 |
``add_route``). |
9c8ec5
|
484 |
|
d71aca
|
485 |
``factory`` should be a :term:`predicate factory` or :term:`dotted |
BJR |
486 |
Python name` which refers to a predicate factory. |
5664c4
|
487 |
|
95f766
|
488 |
See :ref:`view_and_route_predicates` for more information. |
5664c4
|
489 |
|
0b23b3
|
490 |
.. versionadded:: 1.4 |
9c8ec5
|
491 |
""" |
95f766
|
492 |
self._add_predicate( |
CM |
493 |
'route', |
|
494 |
name, |
|
495 |
factory, |
|
496 |
weighs_more_than=weighs_more_than, |
0c29cf
|
497 |
weighs_less_than=weighs_less_than, |
MM |
498 |
) |
9c8ec5
|
499 |
|
CM |
500 |
def add_default_route_predicates(self): |
c7974f
|
501 |
p = pyramid.predicates |
9c8ec5
|
502 |
for (name, factory) in ( |
8ec8e2
|
503 |
('xhr', p.XHRPredicate), |
CM |
504 |
('request_method', p.RequestMethodPredicate), |
|
505 |
('path_info', p.PathInfoPredicate), |
|
506 |
('request_param', p.RequestParamPredicate), |
|
507 |
('header', p.HeaderPredicate), |
|
508 |
('accept', p.AcceptPredicate), |
c7337b
|
509 |
('effective_principals', p.EffectivePrincipalsPredicate), |
8ec8e2
|
510 |
('custom', p.CustomPredicate), |
CM |
511 |
('traverse', p.TraversePredicate), |
0c29cf
|
512 |
): |
9c8ec5
|
513 |
self.add_route_predicate(name, factory) |
503bbb
|
514 |
|
5bf23f
|
515 |
def get_routes_mapper(self): |
CM |
516 |
""" Return the :term:`routes mapper` object associated with |
|
517 |
this configurator's :term:`registry`.""" |
|
518 |
mapper = self.registry.queryUtility(IRoutesMapper) |
|
519 |
if mapper is None: |
|
520 |
mapper = RoutesMapper() |
|
521 |
self.registry.registerUtility(mapper, IRoutesMapper) |
|
522 |
return mapper |
|
523 |
|
efd61e
|
524 |
@contextlib.contextmanager |
HS |
525 |
def route_prefix_context(self, route_prefix): |
|
526 |
""" Return this configurator with the |
|
527 |
:attr:`pyramid.config.Configurator.route_prefix` attribute mutated to |
|
528 |
include the new ``route_prefix``. |
|
529 |
|
|
530 |
When the context exits, the ``route_prefix`` is reset to the original. |
|
531 |
|
66a767
|
532 |
``route_prefix`` is a string suitable to be used as a route prefix, |
MM |
533 |
or ``None``. |
|
534 |
|
efd61e
|
535 |
Example Usage: |
HS |
536 |
|
e14661
|
537 |
.. code-block:: python |
efd61e
|
538 |
|
e14661
|
539 |
config = Configurator() |
MM |
540 |
with config.route_prefix_context('foo'): |
|
541 |
config.add_route('bar', '/bar') |
efd61e
|
542 |
|
f6aee3
|
543 |
.. versionadded:: 1.10 |
efd61e
|
544 |
|
e14661
|
545 |
""" |
efd61e
|
546 |
original_route_prefix = self.route_prefix |
HS |
547 |
|
|
548 |
if route_prefix is None: |
|
549 |
route_prefix = '' |
|
550 |
|
|
551 |
old_route_prefix = self.route_prefix |
|
552 |
if old_route_prefix is None: |
|
553 |
old_route_prefix = '' |
|
554 |
|
|
555 |
route_prefix = '{}/{}'.format( |
0c29cf
|
556 |
old_route_prefix.rstrip('/'), route_prefix.lstrip('/') |
efd61e
|
557 |
) |
HS |
558 |
|
|
559 |
route_prefix = route_prefix.strip('/') |
|
560 |
|
|
561 |
if not route_prefix: |
|
562 |
route_prefix = None |
|
563 |
|
|
564 |
self.begin() |
|
565 |
try: |
|
566 |
self.route_prefix = route_prefix |
|
567 |
yield |
|
568 |
|
|
569 |
finally: |
|
570 |
self.route_prefix = original_route_prefix |
|
571 |
self.end() |