CHANGES.txt | ●●●●● patch | view | raw | blame | history | |
docs/narr/urldispatch.rst | ●●●●● patch | view | raw | blame | history | |
pyramid/config/routes.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_url.py | ●●●●● patch | view | raw | blame | history |
CHANGES.txt
@@ -142,6 +142,10 @@ - The ``alchemy`` scaffold tests now provide better coverage. See https://github.com/Pylons/pyramid/pull/1029 - The ``pyramid.config.Configurator.add_route`` method now supports being called with an external URL as pattern. See https://github.com/Pylons/pyramid/issues/611 for more information. Bug Fixes --------- docs/narr/urldispatch.rst
@@ -105,6 +105,7 @@ .. _route_pattern_syntax: Route Pattern Syntax ~~~~~~~~~~~~~~~~~~~~ @@ -126,6 +127,10 @@ .. code-block:: text /{foo}/bar/baz If a pattern is a valid URL it won't be ever matched against an incoming request. Instead it can be useful for generating external URLs. See :ref:`External routes <external_route_narr>` for details. A pattern segment (an individual item between ``/`` characters in the pattern) may either be a literal string (e.g. ``foo``) *or* it may be a @@ -754,9 +759,43 @@ exception to this rule is use of the ``pregenerator`` argument, which is not ignored when ``static`` is ``True``. :ref:`External routes <external_route_narr>` are implicitly static. .. versionadded:: 1.1 the ``static`` argument to :meth:`~pyramid.config.Configurator.add_route` .. _external_route_narr: External Routes --------------- .. versionadded:: 1.5 Route patterns that are valid URLs, are treated as external routes. Like :ref:`static routes <static_route_narr>` they are useful for URL generation purposes only and are never considered for matching at request time. .. code-block:: python :linenos: >>> config = Configurator() >>> config.add_route('youtube', 'https://youtube.com/watch/{video_id}') ... >>> request.route_url('youtube', video_id='oHg5SJYRHA0') >>> "https://youtube.com/watch/oHg5SJYRHA0" All pattern replacements and calls to :meth:`pyramid.request.Request.route_url` will work as expected. Note that :meth:`pyramid.request.Request.route_path` will also just return the external URLs path part. .. note:: The external URL feature is implemented with a :term:`pregenerator` so you cannot use both with the same route. .. index:: single: redirecting to slash-appended routes pyramid/config/routes.py
@@ -1,4 +1,5 @@ import warnings from urlparse import urlparse from pyramid.interfaces import ( IRequest, @@ -387,6 +388,25 @@ if self.route_prefix: pattern = self.route_prefix.rstrip('/') + '/' + pattern.lstrip('/') if pregenerator is None: parsed = urlparse(pattern) if parsed.hostname: pattern = parsed.path def external_url_pregenerator(request, elements, kw): if not '_app_url' in kw: if '_scheme' in kw and parsed.scheme != kw['_scheme']: scheme = kw['_scheme'] elif parsed.scheme: scheme = parsed.scheme else: scheme = request.scheme kw['_app_url'] = '{0}://{1}'.format( scheme, parsed.netloc) return elements, kw pregenerator = external_url_pregenerator mapper = self.get_routes_mapper() introspectables = [] pyramid/tests/test_url.py
@@ -1027,6 +1027,57 @@ self.assertEqual(request.elements, ('abc',)) self.assertEqual(request.kw, {'_anchor':'abc'}) class Test_external_static_url_integration(unittest.TestCase): def setUp(self): self.config = testing.setUp() def tearDown(self): testing.tearDown() def _makeRequest(self): from pyramid.request import Request return Request.blank('/') def test_generate_external_url(self): self.config.add_route('acme', 'https://acme.org/path/{foo}') request = self._makeRequest() request.registry = self.config.registry self.assertEqual(request.route_url('acme', foo='bar'), 'https://acme.org/path/bar') def test_generate_external_url_without_scheme(self): self.config.add_route('acme', '//acme.org/path/{foo}') request = self._makeRequest() request.registry = self.config.registry self.assertEqual(request.route_url('acme', foo='bar'), 'http://acme.org/path/bar') def test_generate_external_url_with_explicit_scheme(self): self.config.add_route('acme', '//acme.org/path/{foo}') request = self._makeRequest() request.registry = self.config.registry self.assertEqual(request.route_url('acme', foo='bar', _scheme='https'), 'https://acme.org/path/bar') def test_generate_external_url_with_explicit_app_url(self): self.config.add_route('acme', 'http://acme.org/path/{foo}') request = self._makeRequest() request.registry = self.config.registry self.assertEqual(request.route_url('acme', foo='bar', _app_url='http://fakeme.com'), 'http://fakeme.com/path/bar') def test_generate_external_url_route_path(self): self.config.add_route('acme', 'https://acme.org/path/{foo}') request = self._makeRequest() request.registry = self.config.registry self.assertEqual(request.route_path('acme', foo='bar'), '/path/bar') class DummyContext(object): def __init__(self, next=None): self.next = next