diff options
| author | Chris McDonough <chrism@plope.com> | 2011-01-03 03:10:34 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-01-03 03:10:34 -0500 |
| commit | c089d1538884704b55b1b8ffb5aad7c51ba2d3cb (patch) | |
| tree | 4729e7ff7778d05c5d4f73818343b7bd70fb8b09 | |
| parent | 070a798934bd39223fad37471e8e2168d78909a2 (diff) | |
| parent | 5653d13e554433adf34fd81b2c6593a54e7c4ea1 (diff) | |
| download | pyramid-c089d1538884704b55b1b8ffb5aad7c51ba2d3cb.tar.gz pyramid-c089d1538884704b55b1b8ffb5aad7c51ba2d3cb.tar.bz2 pyramid-c089d1538884704b55b1b8ffb5aad7c51ba2d3cb.zip | |
Merge branch 'ergo-master'
| -rw-r--r-- | CHANGES.txt | 3 | ||||
| -rw-r--r-- | CONTRIBUTORS.txt | 2 | ||||
| -rw-r--r-- | TODO.txt | 2 | ||||
| -rw-r--r-- | docs/api/url.rst | 2 | ||||
| -rw-r--r-- | docs/glossary.rst | 5 | ||||
| -rw-r--r-- | pyramid/tests/test_config.py | 9 | ||||
| -rw-r--r-- | pyramid/tests/test_url.py | 42 | ||||
| -rw-r--r-- | pyramid/url.py | 54 |
8 files changed, 111 insertions, 8 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 8d0e50722..520a73847 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -15,6 +15,9 @@ Bug Fixes Features -------- +- Add a new API ``pyramid.url.current_route_url``, which computes a URL based + on the "current" route (if any) and its matchdict values. + - ``config.add_view`` now accepts a ``decorator`` keyword argument, a callable which will decorate the view callable before it is added to the registry. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 7b0364b6d..ec9042f08 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -120,3 +120,5 @@ Contributors - Rob Miller, 2010/12/28 - Marius Gedminas, 2010/12/31 + +- Marcin Lulek, 2011/01/02
\ No newline at end of file @@ -34,8 +34,6 @@ Must-Have (before 1.0) Should-Have ----------- -- ``current_route_url`` function. https://gist.github.com/762842 - - Convert paster template and tutorial HTML templates to use ``request.static_url('{{package}}:static/foo.css')`` rather than ``${request.application_url}/static/foo.css``. diff --git a/docs/api/url.rst b/docs/api/url.rst index 1aa3082b7..01be76283 100644 --- a/docs/api/url.rst +++ b/docs/api/url.rst @@ -9,6 +9,8 @@ .. autofunction:: route_url + .. autofunction:: current_route_url + .. autofunction:: route_path .. autofunction:: static_url diff --git a/docs/glossary.rst b/docs/glossary.rst index ce2d77d8d..890f7e837 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -857,3 +857,8 @@ Glossary view argument and return value mapping. This is a plug point for extension builders, not normally used by "civilians". + matchdict + The dictionary attached to the :term:`request` object as + ``request.matchdict`` when a :term:`URL dispatch` route has been matched. + Its keys are names as identified within the route pattern; its values are + the values matched by each pattern name. diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index 1632a4e5c..70e4df07e 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -3798,8 +3798,7 @@ class TestViewDeriver(unittest.TestCase): def wrapped(context, request): return 'OK' return wrapped - def view(context, request): - return 'NOTOK' + def view(context, request): return 'NOTOK' deriver = self._makeOne(view_mapper=mapper) result = deriver(view) self.failIf(result is view) @@ -3813,8 +3812,7 @@ class TestViewDeriver(unittest.TestCase): return 'OK' return superinner return inner - def view(context, request): - return 'NOTOK' + def view(context, request): return 'NOTOK' view.__view_mapper__ = mapper deriver = self._makeOne() result = deriver(view) @@ -3830,8 +3828,7 @@ class TestViewDeriver(unittest.TestCase): return superinner return inner self.config.set_view_mapper(mapper) - def view(context, request): - return 'NOTOK' + def view(context, request): return 'NOTOK' deriver = self._makeOne() result = deriver(view) self.failIf(result is view) diff --git a/pyramid/tests/test_url.py b/pyramid/tests/test_url.py index f11d36aca..a40727e9b 100644 --- a/pyramid/tests/test_url.py +++ b/pyramid/tests/test_url.py @@ -209,6 +209,47 @@ class TestRouteUrl(unittest.TestCase): self.assertEqual(result, 'http://example2.com/1/2/3/a') self.assertEqual(route.kw, {}) # shouldnt have anchor/query +class TestCurrentRouteUrl(unittest.TestCase): + def setUp(self): + cleanUp() + + def tearDown(self): + cleanUp() + + def _callFUT(self, *arg, **kw): + from pyramid.url import current_route_url + return current_route_url(*arg, **kw) + + def test_current_request_has_no_route(self): + request = _makeRequest() + self.assertRaises(ValueError, self._callFUT, request) + + def test_with_elements_query_and_anchor(self): + from pyramid.interfaces import IRoutesMapper + request = _makeRequest() + route = DummyRoute('/1/2/3') + mapper = DummyRoutesMapper(route=route) + request.matched_route = route + request.matchdict = {} + request.registry.registerUtility(mapper, IRoutesMapper) + result = self._callFUT(request, 'extra1', 'extra2', _query={'a':1}, + _anchor=u"foo") + self.assertEqual(result, + 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo') + + def test_with__route_name(self): + from pyramid.interfaces import IRoutesMapper + request = _makeRequest() + route = DummyRoute('/1/2/3') + mapper = DummyRoutesMapper(route=route) + request.matched_route = route + request.matchdict = {} + request.registry.registerUtility(mapper, IRoutesMapper) + result = self._callFUT(request, 'extra1', 'extra2', _query={'a':1}, + _anchor=u"foo", _route_name='bar') + self.assertEqual(result, + 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo') + class TestRoutePath(unittest.TestCase): def setUp(self): cleanUp() @@ -302,6 +343,7 @@ class DummyRoutesMapper: class DummyRoute: pregenerator = None + name = 'route' def __init__(self, result='/1/2/3'): self.result = result diff --git a/pyramid/url.py b/pyramid/url.py index c11e39143..3126ad26c 100644 --- a/pyramid/url.py +++ b/pyramid/url.py @@ -366,6 +366,60 @@ def static_url(path, request, **kw): return info.generate(path, request, **kw) +def current_route_url(request, *elements, **kw): + """Generates a fully qualified URL for a named :app:`Pyramid` + :term:`route configuration` based on the 'current route'. + + This function supplements :func:`pyramid.url.route_url`. It presents an + easy way to generate a URL for the 'current route' (defined as the route + which matched when the request was generated). + + The arguments to this function have the same meaning as those with the + same names passed to :func:`pyramid.url.route_url`. It also understands + an extra argument which ``route_url`` does not named ``_route_name``. + + The route name used to generate a URL is taken from either the + ``_route_name`` keyword argument or the name of the route which is + currently associated with the request if ``_route_name`` was not passed. + Keys and values from the current request :term:`matchdict` are combined + with the ``kw`` arguments to form a set of defaults named ``newkw``. + Then ``route_url(route_name, request, *elements, **newkw)`` is called, + returning a URL. + + Examples follow. + + If the 'current route' has the route pattern ``/foo/{page}`` and the + current url path is ``/foo/1`` , the matchdict will be ``{'page':'1'}``. + The result of ``current_route_url(request)`` in this situation will be + ``/foo/1``. + + If the 'current route' has the route pattern ``/foo/{page}`` and the + current current url path is ``/foo/1``, the matchdict will be + ``{'page':'1'}``. The result of ``current_route_url(request, page='2')`` + in this situation will be ``/foo/2``. + + Usage of the ``_route_name`` keyword argument: if our routing table + defines routes ``/foo/{action}`` named 'foo' and ``/foo/{action}/{page}`` + named ``fooaction``, and the current url pattern is ``/foo/view`` (which + has matched the ``/foo/{action}`` route), we may want to use the + matchdict args to generate a URL to the ``fooaction`` route. In this + scenario, ``current_url(request, _route_name='fooaction', page='5')`` + Will return string like: ``/foo/view/5``. + """ + + if '_route_name' in kw: + route_name = kw.pop('_route_name') + else: + route = getattr(request, 'matched_route', None) + route_name = getattr(route, 'name', None) + if route_name is None: + raise ValueError('Current request matches no route') + + newkw = {} + newkw.update(request.matchdict) + newkw.update(kw) + return route_url(route_name, request, *elements, **newkw) + @lru_cache(1000) def _join_elements(elements): return '/'.join([quote_path_segment(s) for s in elements]) |
