Hide keyboard shortcuts

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 """ 

2 

3import os 

4 

5from pyramid.interfaces import IResourceURL, IRoutesMapper, IStaticURLInfo 

6 

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 

11 

12from pyramid.traversal import ( 

13 ResourceURL, 

14 quote_path_segment, 

15 PATH_SAFE, 

16 PATH_SEGMENT_SAFE, 

17) 

18 

19QUERY_SAFE = "/?:@!$&'()*+,;=" # RFC 3986 

20ANCHOR_SAFE = QUERY_SAFE 

21 

22 

23def parse_url_overrides(request, kw): 

24 """ 

25 Parse special arguments passed when generating urls. 

26 

27 The supplied dictionary is mutated when we pop arguments. 

28 Returns a 3-tuple of the format: 

29 

30 ``(app_url, qs, anchor)``. 

31 

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', '') 

39 

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 

45 

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) 

52 

53 frag = '' 

54 if anchor: 

55 frag = '#' + url_quote(anchor, ANCHOR_SAFE) 

56 

57 return app_url, qs, frag 

58 

59 

60class URLMethodsMixin(object): 

61 """ Request methods mixin for BaseRequest having to do with URL 

62 generation """ 

63 

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. 

69 

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``. 

74 

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 

108 

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) 

112 

113 def route_url(self, route_name, *elements, **kw): 

114 """Generates a fully qualified URL for a named :app:`Pyramid` 

115 :term:`route configuration`. 

116 

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. 

120 

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). 

125 

126 For example, if you've defined a route named "foobar" with the path 

127 ``{foo}/{bar}/*traverse``:: 

128 

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 

142 

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. 

146 

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. 

154 

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. 

170 

171 .. note:: 

172 

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. 

179 

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``). 

186 

187 .. note:: 

188 

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. 

192 

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``. 

196 

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``. 

203 

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``. 

210 

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). 

221 

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. 

225 

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. 

229 

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. 

233 

234 .. versionchanged:: 1.5 

235 Allow the ``_query`` option to be a string to enable alternative 

236 encodings. 

237 

238 The ``_anchor`` option will be escaped instead of using 

239 its raw string representation. 

240 

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. 

244 

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) 

252 

253 if route is None: 

254 raise KeyError('No such route named %s' % route_name) 

255 

256 if route.pregenerator is not None: 

257 elements, kw = route.pregenerator(self, elements, kw) 

258 

259 app_url, qs, anchor = parse_url_overrides(self, kw) 

260 

261 path = route.generate(kw) # raises KeyError if generate fails 

262 

263 if elements: 

264 suffix = _join_elements(elements) 

265 if not path.endswith('/'): 

266 suffix = '/' + suffix 

267 else: 

268 suffix = '' 

269 

270 return app_url + path + suffix + qs + anchor 

271 

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`. 

276 

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. 

282 

283 For example, if you've defined a route named 'foobar' with the path 

284 ``/{foo}/{bar}``, this call to ``route_path``:: 

285 

286 request.route_path('foobar', foo='1', bar='2') 

287 

288 Will return the string ``/1/2``. 

289 

290 .. note:: 

291 

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. 

298 

299 """ 

300 kw['_app_url'] = self.script_name 

301 return self.route_url(route_name, *elements, **kw) 

302 

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. 

310 

311 Examples:: 

312 

313 request.resource_url(resource) => 

314 

315 http://example.com/ 

316 

317 request.resource_url(resource, 'a.html') => 

318 

319 http://example.com/a.html 

320 

321 request.resource_url(resource, 'a.html', query={'q':'1'}) => 

322 

323 http://example.com/a.html?q=1 

324 

325 request.resource_url(resource, 'a.html', anchor='abc') => 

326 

327 http://example.com/a.html#abc 

328 

329 request.resource_url(resource, app_url='') => 

330 

331 / 

332 

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. 

340 

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. 

345 

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. 

361 

362 .. note:: 

363 

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. 

370 

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``). 

376 

377 .. note:: 

378 

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. 

382 

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``. 

386 

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``. 

393 

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``. 

400 

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``. 

410 

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. 

414 

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. 

418 

419 .. seealso:: 

420 

421 See also :ref:`overriding_resource_url_generation`. 

422 

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:: 

427 

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 ) 

436 

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. 

440 

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``:: 

447 

448 request.resource_url( 

449 resource, 

450 route_name='myroute', 

451 route_remainder_name='subpath' 

452 ) 

453 

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:: 

459 

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 ) 

468 

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. 

475 

476 .. note:: 

477 

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. 

482 

483 .. note:: 

484 

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). 

490 

491 .. note:: 

492 

493 For backwards compatibility purposes, this method is also 

494 aliased as the ``model_url`` method of request. 

495 

496 .. versionchanged:: 1.3 

497 Added the ``app_url`` keyword argument. 

498 

499 .. versionchanged:: 1.5 

500 Allow the ``query`` option to be a string to enable alternative 

501 encodings. 

502 

503 The ``anchor`` option will be escaped instead of using 

504 its raw string representation. 

505 

506 Added the ``route_name``, ``route_kw``, and 

507 ``route_remainder_name`` keyword arguments. 

508 

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 

517 

518 url_adapter = reg.queryMultiAdapter((resource, self), IResourceURL) 

519 if url_adapter is None: 

520 url_adapter = ResourceURL(resource, self) 

521 

522 virtual_path = getattr(url_adapter, 'virtual_path', None) 

523 

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 

529 

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 

539 

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) 

544 

545 return self.route_url(route_name, *elements, **urlkw) 

546 

547 app_url, qs, anchor = parse_url_overrides(self, urlkw) 

548 

549 resource_url = None 

550 local_url = getattr(resource, '__resource_url__', None) 

551 

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 ) 

559 

560 # allow __resource_url__ to punt by returning None 

561 resource_url = local_url(self, d) 

562 

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 

567 

568 if elements: 

569 suffix = _join_elements(elements) 

570 else: 

571 suffix = '' 

572 

573 return resource_url + suffix + qs + anchor 

574 

575 model_url = resource_url # b/w compat forever 

576 

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`. 

581 

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. 

587 

588 .. note:: 

589 

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) 

601 

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`). 

608 

609 Example:: 

610 

611 request.static_url('mypackage:static/foo.css') => 

612 

613 http://example.com/static/foo.css 

614 

615 

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``). 

621 

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. 

627 

628 This function raises a :exc:`ValueError` if a static view 

629 definition cannot be found which matches the path specification. 

630 

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) 

639 

640 try: 

641 reg = self.registry 

642 except AttributeError: 

643 reg = get_current_registry() # b/c 

644 

645 info = reg.queryUtility(IStaticURLInfo) 

646 if info is None: 

647 raise ValueError('No static URL definition matching %s' % path) 

648 

649 return info.generate(path, self, **kw) 

650 

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. 

655 

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. 

661 

662 Example:: 

663 

664 request.static_path('mypackage:static/foo.css') => 

665 

666 /static/foo.css 

667 

668 .. note:: 

669 

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) 

684 

685 kw['_app_url'] = self.script_name 

686 return self.static_url(path, **kw) 

687 

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'. 

692 

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). 

697 

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``. 

702 

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. 

710 

711 Examples follow. 

712 

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``. 

717 

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``. 

723 

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``. 

732 

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') 

741 

742 if '_query' not in kw: 

743 kw['_query'] = self.GET 

744 

745 newkw = {} 

746 newkw.update(self.matchdict) 

747 newkw.update(kw) 

748 return self.route_url(route_name, *elements, **newkw) 

749 

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. 

755 

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. 

761 

762 For example, if the route matched by the current request has the 

763 pattern ``/{foo}/{bar}``, this call to ``current_route_path``:: 

764 

765 request.current_route_path(foo='1', bar='2') 

766 

767 Will return the string ``/1/2``. 

768 

769 .. note:: 

770 

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) 

782 

783 

784def route_url(route_name, request, *elements, **kw): 

785 """ 

786 This is a backwards compatibility function. Its result is the same as 

787 calling:: 

788 

789 request.route_url(route_name, *elements, **kw) 

790 

791 See :meth:`pyramid.request.Request.route_url` for more information. 

792 """ 

793 return request.route_url(route_name, *elements, **kw) 

794 

795 

796def route_path(route_name, request, *elements, **kw): 

797 """ 

798 This is a backwards compatibility function. Its result is the same as 

799 calling:: 

800 

801 request.route_path(route_name, *elements, **kw) 

802 

803 See :meth:`pyramid.request.Request.route_path` for more information. 

804 """ 

805 return request.route_path(route_name, *elements, **kw) 

806 

807 

808def resource_url(resource, request, *elements, **kw): 

809 """ 

810 This is a backwards compatibility function. Its result is the same as 

811 calling:: 

812 

813 request.resource_url(resource, *elements, **kw) 

814 

815 See :meth:`pyramid.request.Request.resource_url` for more information. 

816 """ 

817 return request.resource_url(resource, *elements, **kw) 

818 

819 

820model_url = resource_url # b/w compat (forever) 

821 

822 

823def static_url(path, request, **kw): 

824 """ 

825 This is a backwards compatibility function. Its result is the same as 

826 calling:: 

827 

828 request.static_url(path, **kw) 

829 

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) 

840 

841 

842def static_path(path, request, **kw): 

843 """ 

844 This is a backwards compatibility function. Its result is the same as 

845 calling:: 

846 

847 request.static_path(path, **kw) 

848 

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) 

859 

860 

861def current_route_url(request, *elements, **kw): 

862 """ 

863 This is a backwards compatibility function. Its result is the same as 

864 calling:: 

865 

866 request.current_route_url(*elements, **kw) 

867 

868 See :meth:`pyramid.request.Request.current_route_url` for more 

869 information. 

870 """ 

871 return request.current_route_url(*elements, **kw) 

872 

873 

874def current_route_path(request, *elements, **kw): 

875 """ 

876 This is a backwards compatibility function. Its result is the same as 

877 calling:: 

878 

879 request.current_route_path(*elements, **kw) 

880 

881 See :meth:`pyramid.request.Request.current_route_path` for more 

882 information. 

883 """ 

884 return request.current_route_path(*elements, **kw) 

885 

886 

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 )