From e725cf6f3290a5fa974230d6c5c82eed3358bcf2 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 13 May 2011 03:51:49 -0400 Subject: - The ``add_route`` method of the Configurator now accepts a ``static`` argument. If this argument is ``True``, the added route will never be considered for matching when a request is handled. Instead, it will only be useful for URL generation via ``route_url`` and ``route_path``. See the section entitled "Static Routes" in the URL Dispatch narrative chapter for more information. --- CHANGES.txt | 10 ++++++++++ TODO.txt | 6 ++---- docs/narr/urldispatch.rst | 29 +++++++++++++++++++++++++++++ pyramid/config.py | 11 ++++++++++- pyramid/interfaces.py | 3 ++- pyramid/tests/test_config.py | 8 ++++++++ pyramid/tests/test_urldispatch.py | 23 +++++++++++++++++++++++ pyramid/urldispatch.py | 8 +++++--- 8 files changed, 89 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 0182bdce0..adf926ea2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -32,6 +32,9 @@ Documentation - Added documentation for a "multidict" (e.g. the API of ``request.POST``) as interface API documentation. +- Added a section to the "URL Dispatch" narrative chapter regarding the new + "static" route feature. + Features -------- @@ -85,6 +88,13 @@ Features section entitled "Displaying Matching Views for a Given URL" in the "View Configuration" chapter of the narrative documentation for more information. +- The ``add_route`` method of the Configurator now accepts a ``static`` + argument. If this argument is ``True``, the added route will never be + considered for matching when a request is handled. Instead, it will only + be useful for URL generation via ``route_url`` and ``route_path``. See the + section entitled "Static Routes" in the URL Dispatch narrative chapter for + more information. + Bug Fixes --------- diff --git a/TODO.txt b/TODO.txt index 1429bd80c..b6fda3fbf 100644 --- a/TODO.txt +++ b/TODO.txt @@ -10,14 +10,10 @@ Should-Have - Fix misleading conflict error reports for static views ala http://cluebin.appspot.com/pasted/7242843 -- Nicer Mako exceptions in WebError. - - Consider adding a default exception view for HTTPException and attendant ``redirect`` and ``abort`` functions ala Pylons (promised Mike I'd enable this in 1.1). -- Static (URL-generation only) routes. - - Add narrative docs for wsgiapp and wsgiapp2. - Fix message catalog extraction / compilation documentation. Chameleon 2 @@ -28,6 +24,8 @@ Should-Have Nice-to-Have ------------ +- Nicer Mako exceptions in WebError. + - Response.RequestClass should probably be pyramid.request.Request but this may imply actually subclassing webob.Response diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index a180003d0..5df1eb3af 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -831,6 +831,35 @@ least if the current protocol and hostname implied ``http://example.com``). See the :func:`~pyramid.url.route_url` API documentation for more information. +.. index:: + single: static routes + +.. _static_route_narr: + +Static Routes +------------- + +Routes may be added with a ``static`` keyword argument. For example: + +.. code-block:: python + :linenos: + + config = Configurator() + config.add_route('page', '/page/{action}', static=True) + +Routes added with a ``True`` ``static`` keyword argument will never be +considered for matching at request time. Static routes are useful for URL +generation purposes only. As a result, it is usually nonsensical to provide +other non-``name`` and non-``pattern`` arguments to +:meth:`~pyramid.config.Configurator.add_route` when ``static`` is passed as +``True``, as none of the other arguments will ever be employed. A single +exception to this rule is use of the ``pregenerator`` argument, which is not +ignored when ``static`` is ``True``. + +.. note:: the ``static`` argument to + :meth:`~pyramid.config.Configurator.add_route` is new as of :app:`Pyramid` + 1.1. + .. index:: single: redirecting to slash-appended routes diff --git a/pyramid/config.py b/pyramid/config.py index 9286136cf..4e06a9b2e 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -1453,6 +1453,7 @@ class Configurator(object): use_global_views=False, path=None, pregenerator=None, + static=False, ): """ Add a :term:`route configuration` to the current configuration state, as well as possibly a :term:`view @@ -1542,6 +1543,14 @@ class Configurator(object): that otherwise matches the context, request, and view name (but which does not match the route_name predicate). + static + + If ``static`` is ``True``, this route will never match an incoming + request; it will only be useful for URL generation. By default, + ``static`` is ``False``. See :ref:`static_route_narr`. + + .. note:: New in :app:`Pyramid` 1.1. + Predicate Arguments pattern @@ -1798,7 +1807,7 @@ class Configurator(object): self.action(discriminator, None) return mapper.connect(name, pattern, factory, predicates=predicates, - pregenerator=pregenerator) + pregenerator=pregenerator, static=static) def get_routes_mapper(self): """ Return the :term:`routes mapper` object associated with diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 617133052..07812e0cd 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -429,7 +429,8 @@ class IRoute(Interface): class IRoutesMapper(Interface): """ Interface representing a Routes ``Mapper`` object """ def get_routes(): - """ Return a sequence of Route objects registered in the mapper.""" + """ Return a sequence of Route objects registered in the mapper. + Static routes will not be returned in this sequence.""" def has_routes(): """ Returns ``True`` if any route has been registered. """ diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index 9f7873ab5..97a93616d 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -1898,6 +1898,14 @@ class ConfiguratorTests(unittest.TestCase): route = config.add_route('name', 'path', factory=factory) self.assertEqual(route.factory, factory) + def test_add_route_with_static(self): + config = self._makeOne(autocommit=True) + route = config.add_route('name', 'path/{foo}', static=True) + self.assertEqual(route.name, 'name') + mapper = config.get_routes_mapper() + self.assertEqual(len(mapper.get_routes()), 0) + self.assertEqual(mapper.generate('name', {"foo":"a"}), '/path/a') + def test_add_route_with_factory_dottedname(self): config = self._makeOne(autocommit=True) route = config.add_route( diff --git a/pyramid/tests/test_urldispatch.py b/pyramid/tests/test_urldispatch.py index 6e1474b1d..7df237aeb 100644 --- a/pyramid/tests/test_urldispatch.py +++ b/pyramid/tests/test_urldispatch.py @@ -90,6 +90,29 @@ class RoutesMapperTests(unittest.TestCase): self.assertEqual(mapper.routelist[0].pattern, 'archives/:action/:article2') + def test_connect_static(self): + mapper = self._makeOne() + mapper.connect('foo', 'archives/:action/:article', static=True) + self.assertEqual(len(mapper.routelist), 0) + self.assertEqual(len(mapper.routes), 1) + self.assertEqual(mapper.routes['foo'].pattern, + 'archives/:action/:article') + + def test_connect_static_overridden(self): + mapper = self._makeOne() + mapper.connect('foo', 'archives/:action/:article', static=True) + self.assertEqual(len(mapper.routelist), 0) + self.assertEqual(len(mapper.routes), 1) + self.assertEqual(mapper.routes['foo'].pattern, + 'archives/:action/:article') + mapper.connect('foo', 'archives/:action/:article2') + self.assertEqual(len(mapper.routelist), 1) + self.assertEqual(len(mapper.routes), 1) + self.assertEqual(mapper.routes['foo'].pattern, + 'archives/:action/:article2') + self.assertEqual(mapper.routelist[0].pattern, + 'archives/:action/:article2') + def test___call__route_matches(self): mapper = self._makeOne() mapper.connect('foo', 'archives/:action/:article') diff --git a/pyramid/urldispatch.py b/pyramid/urldispatch.py index 989cc62b9..43bc7e50f 100644 --- a/pyramid/urldispatch.py +++ b/pyramid/urldispatch.py @@ -42,12 +42,14 @@ class RoutesMapper(object): return self.routes.get(name) def connect(self, name, pattern, factory=None, predicates=(), - pregenerator=None): + pregenerator=None, static=False): if name in self.routes: oldroute = self.routes[name] - self.routelist.remove(oldroute) + if oldroute in self.routelist: + self.routelist.remove(oldroute) route = Route(name, pattern, factory, predicates, pregenerator) - self.routelist.append(route) + if not static: + self.routelist.append(route) self.routes[name] = route return route -- cgit v1.2.3