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

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
1""" Utility functions for dealing with URLs in pyramid """
3import os
5from pyramid.interfaces import IResourceURL, IRoutesMapper, IStaticURLInfo
7from pyramid.compat import bytes_, lru_cache, string_types
8from pyramid.encode import url_quote, urlencode
9from pyramid.path import caller_package
10from pyramid.threadlocal import get_current_registry
12from pyramid.traversal import (
13 ResourceURL,
14 quote_path_segment,
15 PATH_SAFE,
16 PATH_SEGMENT_SAFE,
17)
19QUERY_SAFE = "/?:@!$&'()*+,;=" # RFC 3986
20ANCHOR_SAFE = QUERY_SAFE
23def parse_url_overrides(request, kw):
24 """
25 Parse special arguments passed when generating urls.
27 The supplied dictionary is mutated when we pop arguments.
28 Returns a 3-tuple of the format:
30 ``(app_url, qs, anchor)``.
32 """
33 app_url = kw.pop('_app_url', None)
34 scheme = kw.pop('_scheme', None)
35 host = kw.pop('_host', None)
36 port = kw.pop('_port', None)
37 query = kw.pop('_query', '')
38 anchor = kw.pop('_anchor', '')
40 if app_url is None:
41 if scheme is not None or host is not None or port is not None:
42 app_url = request._partial_application_url(scheme, host, port)
43 else:
44 app_url = request.application_url
46 qs = ''
47 if query:
48 if isinstance(query, string_types):
49 qs = '?' + url_quote(query, QUERY_SAFE)
50 else:
51 qs = '?' + urlencode(query, doseq=True)
53 frag = ''
54 if anchor:
55 frag = '#' + url_quote(anchor, ANCHOR_SAFE)
57 return app_url, qs, frag
60class URLMethodsMixin(object):
61 """ Request methods mixin for BaseRequest having to do with URL
62 generation """
64 def _partial_application_url(self, scheme=None, host=None, port=None):
65 """
66 Construct the URL defined by request.application_url, replacing any
67 of the default scheme, host, or port portions with user-supplied
68 variants.
70 If ``scheme`` is passed as ``https``, and the ``port`` is *not*
71 passed, the ``port`` value is assumed to ``443``. Likewise, if
72 ``scheme`` is passed as ``http`` and ``port`` is not passed, the
73 ``port`` value is assumed to be ``80``.
75 """
76 e = self.environ
77 if scheme is None:
78 scheme = e['wsgi.url_scheme']
79 else:
80 if scheme == 'https':
81 if port is None:
82 port = '443'
83 if scheme == 'http':
84 if port is None:
85 port = '80'
86 if host is None:
87 host = e.get('HTTP_HOST')
88 if host is None:
89 host = e['SERVER_NAME']
90 if port is None:
91 if ':' in host:
92 host, port = host.split(':', 1)
93 else:
94 port = e['SERVER_PORT']
95 else:
96 port = str(port)
97 if ':' in host:
98 host, _ = host.split(':', 1)
99 if scheme == 'https':
100 if port == '443':
101 port = None
102 elif scheme == 'http':
103 if port == '80':
104 port = None
105 url = scheme + '://' + host
106 if port:
107 url += ':%s' % port
109 url_encoding = getattr(self, 'url_encoding', 'utf-8') # webob 1.2b3+
110 bscript_name = bytes_(self.script_name, url_encoding)
111 return url + url_quote(bscript_name, PATH_SAFE)
113 def route_url(self, route_name, *elements, **kw):
114 """Generates a fully qualified URL for a named :app:`Pyramid`
115 :term:`route configuration`.
117 Use the route's ``name`` as the first positional argument.
118 Additional positional arguments (``*elements``) are appended to the
119 URL as path segments after it is generated.
121 Use keyword arguments to supply values which match any dynamic
122 path elements in the route definition. Raises a :exc:`KeyError`
123 exception if the URL cannot be generated for any reason (not
124 enough arguments, for example).
126 For example, if you've defined a route named "foobar" with the path
127 ``{foo}/{bar}/*traverse``::
129 request.route_url('foobar',
130 foo='1') => <KeyError exception>
131 request.route_url('foobar',
132 foo='1',
133 bar='2') => <KeyError exception>
134 request.route_url('foobar',
135 foo='1',
136 bar='2',
137 traverse=('a','b')) => http://e.com/1/2/a/b
138 request.route_url('foobar',
139 foo='1',
140 bar='2',
141 traverse='/a/b') => http://e.com/1/2/a/b
143 Values replacing ``:segment`` arguments can be passed as strings
144 or Unicode objects. They will be encoded to UTF-8 and URL-quoted
145 before being placed into the generated URL.
147 Values replacing ``*remainder`` arguments can be passed as strings
148 *or* tuples of Unicode/string values. If a tuple is passed as a
149 ``*remainder`` replacement value, its values are URL-quoted and
150 encoded to UTF-8. The resulting strings are joined with slashes
151 and rendered into the URL. If a string is passed as a
152 ``*remainder`` replacement value, it is tacked on to the URL
153 after being URL-quoted-except-for-embedded-slashes.
155 If ``_query`` is provided, it will be used to compose a query string
156 that will be tacked on to the end of the URL. The value of ``_query``
157 may be a sequence of two-tuples *or* a data structure with an
158 ``.items()`` method that returns a sequence of two-tuples
159 (presumably a dictionary). This data structure will be turned into
160 a query string per the documentation of the
161 :func:`pyramid.url.urlencode` function. This will produce a query
162 string in the ``x-www-form-urlencoded`` format. A
163 non-``x-www-form-urlencoded`` query string may be used by passing a
164 *string* value as ``_query`` in which case it will be URL-quoted
165 (e.g. query="foo bar" will become "foo%20bar"). However, the result
166 will not need to be in ``k=v`` form as required by
167 ``x-www-form-urlencoded``. After the query data is turned into a query
168 string, a leading ``?`` is prepended, and the resulting string is
169 appended to the generated URL.
171 .. note::
173 Python data structures that are passed as ``_query`` which are
174 sequences or dictionaries are turned into a string under the same
175 rules as when run through :func:`urllib.urlencode` with the
176 ``doseq`` argument equal to ``True``. This means that sequences can
177 be passed as values, and a k=v pair will be placed into the query
178 string for each value.
180 If a keyword argument ``_anchor`` is present, its string
181 representation will be quoted per :rfc:`3986#section-3.5` and used as
182 a named anchor in the generated URL
183 (e.g. if ``_anchor`` is passed as ``foo`` and the route URL is
184 ``http://example.com/route/url``, the resulting generated URL will
185 be ``http://example.com/route/url#foo``).
187 .. note::
189 If ``_anchor`` is passed as a string, it should be UTF-8 encoded. If
190 ``_anchor`` is passed as a Unicode object, it will be converted to
191 UTF-8 before being appended to the URL.
193 If both ``_anchor`` and ``_query`` are specified, the anchor
194 element will always follow the query element,
195 e.g. ``http://example.com?foo=1#bar``.
197 If any of the keyword arguments ``_scheme``, ``_host``, or ``_port``
198 is passed and is non-``None``, the provided value will replace the
199 named portion in the generated URL. For example, if you pass
200 ``_host='foo.com'``, and the URL that would have been generated
201 without the host replacement is ``http://example.com/a``, the result
202 will be ``http://foo.com/a``.
204 Note that if ``_scheme`` is passed as ``https``, and ``_port`` is not
205 passed, the ``_port`` value is assumed to have been passed as
206 ``443``. Likewise, if ``_scheme`` is passed as ``http`` and
207 ``_port`` is not passed, the ``_port`` value is assumed to have been
208 passed as ``80``. To avoid this behavior, always explicitly pass
209 ``_port`` whenever you pass ``_scheme``.
211 If a keyword ``_app_url`` is present, it will be used as the
212 protocol/hostname/port/leading path prefix of the generated URL.
213 For example, using an ``_app_url`` of
214 ``http://example.com:8080/foo`` would cause the URL
215 ``http://example.com:8080/foo/fleeb/flub`` to be returned from
216 this function if the expansion of the route pattern associated
217 with the ``route_name`` expanded to ``/fleeb/flub``. If
218 ``_app_url`` is not specified, the result of
219 ``request.application_url`` will be used as the prefix (the
220 default).
222 If both ``_app_url`` and any of ``_scheme``, ``_host``, or ``_port``
223 are passed, ``_app_url`` takes precedence and any values passed for
224 ``_scheme``, ``_host``, and ``_port`` will be ignored.
226 This function raises a :exc:`KeyError` if the URL cannot be
227 generated due to missing replacement names. Extra replacement
228 names are ignored.
230 If the route object which matches the ``route_name`` argument has
231 a :term:`pregenerator`, the ``*elements`` and ``**kw``
232 arguments passed to this function might be augmented or changed.
234 .. versionchanged:: 1.5
235 Allow the ``_query`` option to be a string to enable alternative
236 encodings.
238 The ``_anchor`` option will be escaped instead of using
239 its raw string representation.
241 .. versionchanged:: 1.9
242 If ``_query`` or ``_anchor`` are falsey (such as ``None`` or an
243 empty string) they will not be included in the generated url.
245 """
246 try:
247 reg = self.registry
248 except AttributeError:
249 reg = get_current_registry() # b/c
250 mapper = reg.getUtility(IRoutesMapper)
251 route = mapper.get_route(route_name)
253 if route is None:
254 raise KeyError('No such route named %s' % route_name)
256 if route.pregenerator is not None:
257 elements, kw = route.pregenerator(self, elements, kw)
259 app_url, qs, anchor = parse_url_overrides(self, kw)
261 path = route.generate(kw) # raises KeyError if generate fails
263 if elements:
264 suffix = _join_elements(elements)
265 if not path.endswith('/'):
266 suffix = '/' + suffix
267 else:
268 suffix = ''
270 return app_url + path + suffix + qs + anchor
272 def route_path(self, route_name, *elements, **kw):
273 """
274 Generates a path (aka a 'relative URL', a URL minus the host, scheme,
275 and port) for a named :app:`Pyramid` :term:`route configuration`.
277 This function accepts the same argument as
278 :meth:`pyramid.request.Request.route_url` and performs the same duty.
279 It just omits the host, port, and scheme information in the return
280 value; only the script_name, path, query parameters, and anchor data
281 are present in the returned string.
283 For example, if you've defined a route named 'foobar' with the path
284 ``/{foo}/{bar}``, this call to ``route_path``::
286 request.route_path('foobar', foo='1', bar='2')
288 Will return the string ``/1/2``.
290 .. note::
292 Calling ``request.route_path('route')`` is the same as calling
293 ``request.route_url('route', _app_url=request.script_name)``.
294 :meth:`pyramid.request.Request.route_path` is, in fact,
295 implemented in terms of :meth:`pyramid.request.Request.route_url`
296 in just this way. As a result, any ``_app_url`` passed within the
297 ``**kw`` values to ``route_path`` will be ignored.
299 """
300 kw['_app_url'] = self.script_name
301 return self.route_url(route_name, *elements, **kw)
303 def resource_url(self, resource, *elements, **kw):
304 """
305 Generate a string representing the absolute URL of the
306 :term:`resource` object based on the ``wsgi.url_scheme``,
307 ``HTTP_HOST`` or ``SERVER_NAME`` in the request, plus any
308 ``SCRIPT_NAME``. The overall result of this method is always a
309 UTF-8 encoded string.
311 Examples::
313 request.resource_url(resource) =>
315 http://example.com/
317 request.resource_url(resource, 'a.html') =>
319 http://example.com/a.html
321 request.resource_url(resource, 'a.html', query={'q':'1'}) =>
323 http://example.com/a.html?q=1
325 request.resource_url(resource, 'a.html', anchor='abc') =>
327 http://example.com/a.html#abc
329 request.resource_url(resource, app_url='') =>
331 /
333 Any positional arguments passed in as ``elements`` must be strings
334 Unicode objects, or integer objects. These will be joined by slashes
335 and appended to the generated resource URL. Each of the elements
336 passed in is URL-quoted before being appended; if any element is
337 Unicode, it will converted to a UTF-8 bytestring before being
338 URL-quoted. If any element is an integer, it will be converted to its
339 string representation before being URL-quoted.
341 .. warning:: if no ``elements`` arguments are specified, the resource
342 URL will end with a trailing slash. If any
343 ``elements`` are used, the generated URL will *not*
344 end in a trailing slash.
346 If ``query`` is provided, it will be used to compose a query string
347 that will be tacked on to the end of the URL. The value of ``query``
348 may be a sequence of two-tuples *or* a data structure with an
349 ``.items()`` method that returns a sequence of two-tuples
350 (presumably a dictionary). This data structure will be turned into
351 a query string per the documentation of the
352 :func:`pyramid.url.urlencode` function. This will produce a query
353 string in the ``x-www-form-urlencoded`` format. A
354 non-``x-www-form-urlencoded`` query string may be used by passing a
355 *string* value as ``query`` in which case it will be URL-quoted
356 (e.g. query="foo bar" will become "foo%20bar"). However, the result
357 will not need to be in ``k=v`` form as required by
358 ``x-www-form-urlencoded``. After the query data is turned into a query
359 string, a leading ``?`` is prepended, and the resulting string is
360 appended to the generated URL.
362 .. note::
364 Python data structures that are passed as ``query`` which are
365 sequences or dictionaries are turned into a string under the same
366 rules as when run through :func:`urllib.urlencode` with the
367 ``doseq`` argument equal to ``True``. This means that sequences can
368 be passed as values, and a k=v pair will be placed into the query
369 string for each value.
371 If a keyword argument ``anchor`` is present, its string
372 representation will be used as a named anchor in the generated URL
373 (e.g. if ``anchor`` is passed as ``foo`` and the resource URL is
374 ``http://example.com/resource/url``, the resulting generated URL will
375 be ``http://example.com/resource/url#foo``).
377 .. note::
379 If ``anchor`` is passed as a string, it should be UTF-8 encoded. If
380 ``anchor`` is passed as a Unicode object, it will be converted to
381 UTF-8 before being appended to the URL.
383 If both ``anchor`` and ``query`` are specified, the anchor element
384 will always follow the query element,
385 e.g. ``http://example.com?foo=1#bar``.
387 If any of the keyword arguments ``scheme``, ``host``, or ``port`` is
388 passed and is non-``None``, the provided value will replace the named
389 portion in the generated URL. For example, if you pass
390 ``host='foo.com'``, and the URL that would have been generated
391 without the host replacement is ``http://example.com/a``, the result
392 will be ``http://foo.com/a``.
394 If ``scheme`` is passed as ``https``, and an explicit ``port`` is not
395 passed, the ``port`` value is assumed to have been passed as ``443``.
396 Likewise, if ``scheme`` is passed as ``http`` and ``port`` is not
397 passed, the ``port`` value is assumed to have been passed as
398 ``80``. To avoid this behavior, always explicitly pass ``port``
399 whenever you pass ``scheme``.
401 If a keyword argument ``app_url`` is passed and is not ``None``, it
402 should be a string that will be used as the port/hostname/initial
403 path portion of the generated URL instead of the default request
404 application URL. For example, if ``app_url='http://foo'``, then the
405 resulting url of a resource that has a path of ``/baz/bar`` will be
406 ``http://foo/baz/bar``. If you want to generate completely relative
407 URLs with no leading scheme, host, port, or initial path, you can
408 pass ``app_url=''``. Passing ``app_url=''`` when the resource path is
409 ``/baz/bar`` will return ``/baz/bar``.
411 If ``app_url`` is passed and any of ``scheme``, ``port``, or ``host``
412 are also passed, ``app_url`` will take precedence and the values
413 passed for ``scheme``, ``host``, and/or ``port`` will be ignored.
415 If the ``resource`` passed in has a ``__resource_url__`` method, it
416 will be used to generate the URL (scheme, host, port, path) for the
417 base resource which is operated upon by this function.
419 .. seealso::
421 See also :ref:`overriding_resource_url_generation`.
423 If ``route_name`` is passed, this function will delegate its URL
424 production to the ``route_url`` function. Calling
425 ``resource_url(someresource, 'element1', 'element2', query={'a':1},
426 route_name='blogentry')`` is roughly equivalent to doing::
428 traversal_path = request.resource_path(someobject)
429 url = request.route_url(
430 'blogentry',
431 'element1',
432 'element2',
433 _query={'a':'1'},
434 traverse=traversal_path,
435 )
437 It is only sensible to pass ``route_name`` if the route being named has
438 a ``*remainder`` stararg value such as ``*traverse``. The remainder
439 value will be ignored in the output otherwise.
441 By default, the resource path value will be passed as the name
442 ``traverse`` when ``route_url`` is called. You can influence this by
443 passing a different ``route_remainder_name`` value if the route has a
444 different ``*stararg`` value at its end. For example if the route
445 pattern you want to replace has a ``*subpath`` stararg ala
446 ``/foo*subpath``::
448 request.resource_url(
449 resource,
450 route_name='myroute',
451 route_remainder_name='subpath'
452 )
454 If ``route_name`` is passed, it is also permissible to pass
455 ``route_kw``, which will passed as additional keyword arguments to
456 ``route_url``. Saying ``resource_url(someresource, 'element1',
457 'element2', route_name='blogentry', route_kw={'id':'4'},
458 _query={'a':'1'})`` is roughly equivalent to::
460 traversal_path = request.resource_path_tuple(someobject)
461 kw = {'id':'4', '_query':{'a':'1'}, 'traverse':traversal_path}
462 url = request.route_url(
463 'blogentry',
464 'element1',
465 'element2',
466 **kw,
467 )
469 If ``route_kw`` or ``route_remainder_name`` is passed, but
470 ``route_name`` is not passed, both ``route_kw`` and
471 ``route_remainder_name`` will be ignored. If ``route_name``
472 is passed, the ``__resource_url__`` method of the resource passed is
473 ignored unconditionally. This feature is incompatible with
474 resources which generate their own URLs.
476 .. note::
478 If the :term:`resource` used is the result of a :term:`traversal`,
479 it must be :term:`location`-aware. The resource can also be the
480 context of a :term:`URL dispatch`; contexts found this way do not
481 need to be location-aware.
483 .. note::
485 If a 'virtual root path' is present in the request environment (the
486 value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the resource
487 was obtained via :term:`traversal`, the URL path will not include
488 the virtual root prefix (it will be stripped off the left hand side
489 of the generated URL).
491 .. note::
493 For backwards compatibility purposes, this method is also
494 aliased as the ``model_url`` method of request.
496 .. versionchanged:: 1.3
497 Added the ``app_url`` keyword argument.
499 .. versionchanged:: 1.5
500 Allow the ``query`` option to be a string to enable alternative
501 encodings.
503 The ``anchor`` option will be escaped instead of using
504 its raw string representation.
506 Added the ``route_name``, ``route_kw``, and
507 ``route_remainder_name`` keyword arguments.
509 .. versionchanged:: 1.9
510 If ``query`` or ``anchor`` are falsey (such as ``None`` or an
511 empty string) they will not be included in the generated url.
512 """
513 try:
514 reg = self.registry
515 except AttributeError:
516 reg = get_current_registry() # b/c
518 url_adapter = reg.queryMultiAdapter((resource, self), IResourceURL)
519 if url_adapter is None:
520 url_adapter = ResourceURL(resource, self)
522 virtual_path = getattr(url_adapter, 'virtual_path', None)
524 urlkw = {}
525 for name in ('app_url', 'scheme', 'host', 'port', 'query', 'anchor'):
526 val = kw.get(name, None)
527 if val is not None:
528 urlkw['_' + name] = val
530 if 'route_name' in kw:
531 route_name = kw['route_name']
532 remainder = getattr(url_adapter, 'virtual_path_tuple', None)
533 if remainder is None:
534 # older user-supplied IResourceURL adapter without 1.5
535 # virtual_path_tuple
536 remainder = tuple(url_adapter.virtual_path.split('/'))
537 remainder_name = kw.get('route_remainder_name', 'traverse')
538 urlkw[remainder_name] = remainder
540 if 'route_kw' in kw:
541 route_kw = kw.get('route_kw')
542 if route_kw is not None:
543 urlkw.update(route_kw)
545 return self.route_url(route_name, *elements, **urlkw)
547 app_url, qs, anchor = parse_url_overrides(self, urlkw)
549 resource_url = None
550 local_url = getattr(resource, '__resource_url__', None)
552 if local_url is not None:
553 # the resource handles its own url generation
554 d = dict(
555 virtual_path=virtual_path,
556 physical_path=url_adapter.physical_path,
557 app_url=app_url,
558 )
560 # allow __resource_url__ to punt by returning None
561 resource_url = local_url(self, d)
563 if resource_url is None:
564 # the resource did not handle its own url generation or the
565 # __resource_url__ function returned None
566 resource_url = app_url + virtual_path
568 if elements:
569 suffix = _join_elements(elements)
570 else:
571 suffix = ''
573 return resource_url + suffix + qs + anchor
575 model_url = resource_url # b/w compat forever
577 def resource_path(self, resource, *elements, **kw):
578 """
579 Generates a path (aka a 'relative URL', a URL minus the host, scheme,
580 and port) for a :term:`resource`.
582 This function accepts the same argument as
583 :meth:`pyramid.request.Request.resource_url` and performs the same
584 duty. It just omits the host, port, and scheme information in the
585 return value; only the script_name, path, query parameters, and
586 anchor data are present in the returned string.
588 .. note::
590 Calling ``request.resource_path(resource)`` is the same as calling
591 ``request.resource_path(resource, app_url=request.script_name)``.
592 :meth:`pyramid.request.Request.resource_path` is, in fact,
593 implemented in terms of
594 :meth:`pyramid.request.Request.resource_url` in just this way. As
595 a result, any ``app_url`` passed within the ``**kw`` values to
596 ``route_path`` will be ignored. ``scheme``, ``host``, and
597 ``port`` are also ignored.
598 """
599 kw['app_url'] = self.script_name
600 return self.resource_url(resource, *elements, **kw)
602 def static_url(self, path, **kw):
603 """
604 Generates a fully qualified URL for a static :term:`asset`.
605 The asset must live within a location defined via the
606 :meth:`pyramid.config.Configurator.add_static_view`
607 :term:`configuration declaration` (see :ref:`static_assets_section`).
609 Example::
611 request.static_url('mypackage:static/foo.css') =>
613 http://example.com/static/foo.css
616 The ``path`` argument points at a file or directory on disk which
617 a URL should be generated for. The ``path`` may be either a
618 relative path (e.g. ``static/foo.css``) or an absolute path (e.g.
619 ``/abspath/to/static/foo.css``) or a :term:`asset specification`
620 (e.g. ``mypackage:static/foo.css``).
622 The purpose of the ``**kw`` argument is the same as the purpose of
623 the :meth:`pyramid.request.Request.route_url` ``**kw`` argument. See
624 the documentation for that function to understand the arguments which
625 you can provide to it. However, typically, you don't need to pass
626 anything as ``*kw`` when generating a static asset URL.
628 This function raises a :exc:`ValueError` if a static view
629 definition cannot be found which matches the path specification.
631 """
632 if not os.path.isabs(path):
633 if ':' not in path:
634 # if it's not a package:relative/name and it's not an
635 # /absolute/path it's a relative/path; this means its relative
636 # to the package in which the caller's module is defined.
637 package = caller_package()
638 path = '%s:%s' % (package.__name__, path)
640 try:
641 reg = self.registry
642 except AttributeError:
643 reg = get_current_registry() # b/c
645 info = reg.queryUtility(IStaticURLInfo)
646 if info is None:
647 raise ValueError('No static URL definition matching %s' % path)
649 return info.generate(path, self, **kw)
651 def static_path(self, path, **kw):
652 """
653 Generates a path (aka a 'relative URL', a URL minus the host, scheme,
654 and port) for a static resource.
656 This function accepts the same argument as
657 :meth:`pyramid.request.Request.static_url` and performs the
658 same duty. It just omits the host, port, and scheme information in
659 the return value; only the script_name, path, query parameters, and
660 anchor data are present in the returned string.
662 Example::
664 request.static_path('mypackage:static/foo.css') =>
666 /static/foo.css
668 .. note::
670 Calling ``request.static_path(apath)`` is the same as calling
671 ``request.static_url(apath, _app_url=request.script_name)``.
672 :meth:`pyramid.request.Request.static_path` is, in fact, implemented
673 in terms of :meth:`pyramid.request.Request.static_url` in just this
674 way. As a result, any ``_app_url`` passed within the ``**kw`` values
675 to ``static_path`` will be ignored.
676 """
677 if not os.path.isabs(path):
678 if ':' not in path:
679 # if it's not a package:relative/name and it's not an
680 # /absolute/path it's a relative/path; this means its relative
681 # to the package in which the caller's module is defined.
682 package = caller_package()
683 path = '%s:%s' % (package.__name__, path)
685 kw['_app_url'] = self.script_name
686 return self.static_url(path, **kw)
688 def current_route_url(self, *elements, **kw):
689 """
690 Generates a fully qualified URL for a named :app:`Pyramid`
691 :term:`route configuration` based on the 'current route'.
693 This function supplements
694 :meth:`pyramid.request.Request.route_url`. It presents an easy way to
695 generate a URL for the 'current route' (defined as the route which
696 matched when the request was generated).
698 The arguments to this method have the same meaning as those with the
699 same names passed to :meth:`pyramid.request.Request.route_url`. It
700 also understands an extra argument which ``route_url`` does not named
701 ``_route_name``.
703 The route name used to generate a URL is taken from either the
704 ``_route_name`` keyword argument or the name of the route which is
705 currently associated with the request if ``_route_name`` was not
706 passed. Keys and values from the current request :term:`matchdict`
707 are combined with the ``kw`` arguments to form a set of defaults
708 named ``newkw``. Then ``request.route_url(route_name, *elements,
709 **newkw)`` is called, returning a URL.
711 Examples follow.
713 If the 'current route' has the route pattern ``/foo/{page}`` and the
714 current url path is ``/foo/1`` , the matchdict will be
715 ``{'page':'1'}``. The result of ``request.current_route_url()`` in
716 this situation will be ``/foo/1``.
718 If the 'current route' has the route pattern ``/foo/{page}`` and the
719 current url path is ``/foo/1``, the matchdict will be
720 ``{'page':'1'}``. The result of
721 ``request.current_route_url(page='2')`` in this situation will be
722 ``/foo/2``.
724 Usage of the ``_route_name`` keyword argument: if our routing table
725 defines routes ``/foo/{action}`` named 'foo' and
726 ``/foo/{action}/{page}`` named ``fooaction``, and the current url
727 pattern is ``/foo/view`` (which has matched the ``/foo/{action}``
728 route), we may want to use the matchdict args to generate a URL to
729 the ``fooaction`` route. In this scenario,
730 ``request.current_route_url(_route_name='fooaction', page='5')``
731 Will return string like: ``/foo/view/5``.
733 """
734 if '_route_name' in kw:
735 route_name = kw.pop('_route_name')
736 else:
737 route = getattr(self, 'matched_route', None)
738 route_name = getattr(route, 'name', None)
739 if route_name is None:
740 raise ValueError('Current request matches no route')
742 if '_query' not in kw:
743 kw['_query'] = self.GET
745 newkw = {}
746 newkw.update(self.matchdict)
747 newkw.update(kw)
748 return self.route_url(route_name, *elements, **newkw)
750 def current_route_path(self, *elements, **kw):
751 """
752 Generates a path (aka a 'relative URL', a URL minus the host, scheme,
753 and port) for the :app:`Pyramid` :term:`route configuration` matched
754 by the current request.
756 This function accepts the same argument as
757 :meth:`pyramid.request.Request.current_route_url` and performs the
758 same duty. It just omits the host, port, and scheme information in
759 the return value; only the script_name, path, query parameters, and
760 anchor data are present in the returned string.
762 For example, if the route matched by the current request has the
763 pattern ``/{foo}/{bar}``, this call to ``current_route_path``::
765 request.current_route_path(foo='1', bar='2')
767 Will return the string ``/1/2``.
769 .. note::
771 Calling ``request.current_route_path('route')`` is the same
772 as calling ``request.current_route_url('route',
773 _app_url=request.script_name)``.
774 :meth:`pyramid.request.Request.current_route_path` is, in fact,
775 implemented in terms of
776 :meth:`pyramid.request.Request.current_route_url` in just this
777 way. As a result, any ``_app_url`` passed within the ``**kw``
778 values to ``current_route_path`` will be ignored.
779 """
780 kw['_app_url'] = self.script_name
781 return self.current_route_url(*elements, **kw)
784def route_url(route_name, request, *elements, **kw):
785 """
786 This is a backwards compatibility function. Its result is the same as
787 calling::
789 request.route_url(route_name, *elements, **kw)
791 See :meth:`pyramid.request.Request.route_url` for more information.
792 """
793 return request.route_url(route_name, *elements, **kw)
796def route_path(route_name, request, *elements, **kw):
797 """
798 This is a backwards compatibility function. Its result is the same as
799 calling::
801 request.route_path(route_name, *elements, **kw)
803 See :meth:`pyramid.request.Request.route_path` for more information.
804 """
805 return request.route_path(route_name, *elements, **kw)
808def resource_url(resource, request, *elements, **kw):
809 """
810 This is a backwards compatibility function. Its result is the same as
811 calling::
813 request.resource_url(resource, *elements, **kw)
815 See :meth:`pyramid.request.Request.resource_url` for more information.
816 """
817 return request.resource_url(resource, *elements, **kw)
820model_url = resource_url # b/w compat (forever)
823def static_url(path, request, **kw):
824 """
825 This is a backwards compatibility function. Its result is the same as
826 calling::
828 request.static_url(path, **kw)
830 See :meth:`pyramid.request.Request.static_url` for more information.
831 """
832 if not os.path.isabs(path):
833 if ':' not in path:
834 # if it's not a package:relative/name and it's not an
835 # /absolute/path it's a relative/path; this means its relative
836 # to the package in which the caller's module is defined.
837 package = caller_package()
838 path = '%s:%s' % (package.__name__, path)
839 return request.static_url(path, **kw)
842def static_path(path, request, **kw):
843 """
844 This is a backwards compatibility function. Its result is the same as
845 calling::
847 request.static_path(path, **kw)
849 See :meth:`pyramid.request.Request.static_path` for more information.
850 """
851 if not os.path.isabs(path):
852 if ':' not in path:
853 # if it's not a package:relative/name and it's not an
854 # /absolute/path it's a relative/path; this means its relative
855 # to the package in which the caller's module is defined.
856 package = caller_package()
857 path = '%s:%s' % (package.__name__, path)
858 return request.static_path(path, **kw)
861def current_route_url(request, *elements, **kw):
862 """
863 This is a backwards compatibility function. Its result is the same as
864 calling::
866 request.current_route_url(*elements, **kw)
868 See :meth:`pyramid.request.Request.current_route_url` for more
869 information.
870 """
871 return request.current_route_url(*elements, **kw)
874def current_route_path(request, *elements, **kw):
875 """
876 This is a backwards compatibility function. Its result is the same as
877 calling::
879 request.current_route_path(*elements, **kw)
881 See :meth:`pyramid.request.Request.current_route_path` for more
882 information.
883 """
884 return request.current_route_path(*elements, **kw)
887@lru_cache(1000)
888def _join_elements(elements):
889 return '/'.join(
890 [quote_path_segment(s, safe=PATH_SEGMENT_SAFE) for s in elements]
891 )