From ac0ecec4c851c7d76418c1520b27619b93a808eb Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 6 Feb 2012 23:04:32 -0600 Subject: Added a test to reproduce #425. --- pyramid/tests/test_config/test_util.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py index ebf308929..43e56af23 100644 --- a/pyramid/tests/test_config/test_util.py +++ b/pyramid/tests/test_config/test_util.py @@ -328,6 +328,16 @@ class Test__make_predicates(unittest.TestCase): hash2, _, __= self._callFUT(request_method='GET') self.assertEqual(hash1, hash2) + def test_match_param_hashable(self): + # https://github.com/Pylons/pyramid/issues/425 + import pyramid.testing + def view(request): pass + config = pyramid.testing.setUp(autocommit=False) + config.add_route('foo', '/foo/{bar}') + config.add_view(view, route_name='foo', match_param='bar=barf') + config.add_view(view, route_name='foo', match_param={'bar': 'baz'}) + config.commit() + class TestActionInfo(unittest.TestCase): def _getTargetClass(self): from pyramid.config.util import ActionInfo -- cgit v1.2.3 From 835d4812d3b5e37c54325b992f66ba45714d56cb Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 6 Feb 2012 23:37:37 -0600 Subject: Modified match_param to accept a tuple. Fixes #425. --- CHANGES.txt | 11 +++++++++++ pyramid/config/util.py | 14 ++++++++------ pyramid/config/views.py | 8 ++++---- pyramid/tests/test_config/test_util.py | 12 ++++++------ 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 7d20796e1..8bfdc6d66 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -10,6 +10,10 @@ Features - Internal: catch unhashable discriminators early (raise an error instead of allowing them to find their way into resolveConflicts). +- The `match_param` view predicate now accepts a string or a tuple. + This replaces the broken behavior of accepting a dict. See + https://github.com/Pylons/pyramid/issues/425 for more information. + Bug Fixes --------- @@ -21,6 +25,13 @@ Bug Fixes - The ``prequest`` script would fail when used against URLs which did not return HTML or text. See https://github.com/Pylons/pyramid/issues/381 +Backwards Incompatibilities +--------------------------- + +- The `match_param` view predicate no longer accepts a dict. This will + have no negative affect because the implementation was broken for + dict-based arguments. + Documentation ------------- diff --git a/pyramid/config/util.py b/pyramid/config/util.py index 6c1bb8368..b39fb8ee0 100644 --- a/pyramid/config/util.py +++ b/pyramid/config/util.py @@ -221,19 +221,21 @@ def make_predicates(xhr=None, request_method=None, path_info=None, h.update(bytes_('request_type:%r' % hash(request_type))) if match_param is not None: - if isinstance(match_param, string_types): - match_param, match_param_val = match_param.split('=', 1) - match_param = {match_param: match_param_val} - text = "match_param %s" % match_param + if not is_nonstr_iter(match_param): + match_param = (match_param,) + match_param = sorted(match_param) + text = "match_param %s" % repr(match_param) + reqs = [p.split('=', 1) for p in match_param] def match_param_predicate(context, request): - for k, v in match_param.items(): + for k, v in reqs: if request.matchdict.get(k) != v: return False return True match_param_predicate.__text__ = text weights.append(1 << 9) predicates.append(match_param_predicate) - h.update(bytes_('match_param:%r' % match_param)) + for p in match_param: + h.update(bytes_('match_param:%r' % p)) if custom: for num, predicate in enumerate(custom): diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 0359c46f7..a87ab54c7 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -843,18 +843,18 @@ class ViewsConfiguratorMixin(object): .. note:: This feature is new as of :app:`Pyramid` 1.2. - This param may be either a single string of the format "key=value" - or a dict of key/value pairs. + This value can be a string of the format "key=value" or a tuple + containing one or more of these strings. A view declaration with this argument ensures that the view will only be called when the :term:`request` has key/value pairs in its :term:`matchdict` that equal those supplied in the predicate. e.g. ``match_param="action=edit" would require the ``action`` - parameter in the :term:`matchdict` match the right hande side of + parameter in the :term:`matchdict` match the right hand side of the expression (``edit``) for the view to "match" the current request. - If the ``match_param`` is a dict, every key/value pair must match + If the ``match_param`` is a tuple, every key/value pair must match for the predicate to pass. containment diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py index 43e56af23..1ad1fb3c1 100644 --- a/pyramid/tests/test_config/test_util.py +++ b/pyramid/tests/test_config/test_util.py @@ -281,7 +281,7 @@ class Test__make_predicates(unittest.TestCase): self.assertEqual(predicates[5].__text__, 'accept = accept') self.assertEqual(predicates[6].__text__, 'containment = containment') self.assertEqual(predicates[7].__text__, 'request_type = request_type') - self.assertEqual(predicates[8].__text__, "match_param {'foo': 'bar'}") + self.assertEqual(predicates[8].__text__, "match_param ['foo=bar']") self.assertEqual(predicates[9].__text__, 'custom predicate') self.assertEqual(predicates[10].__text__, 'classmethod predicate') self.assertEqual(predicates[11].__text__, '') @@ -299,13 +299,13 @@ class Test__make_predicates(unittest.TestCase): self.assertFalse(predicates[0](Dummy(), request)) def test_match_param_from_dict(self): - _, predicates, _ = self._callFUT(match_param={'foo':'bar','baz':'bum'}) + _, predicates, _ = self._callFUT(match_param=('foo=bar','baz=bum')) request = DummyRequest() request.matchdict = {'foo':'bar', 'baz':'bum'} self.assertTrue(predicates[0](Dummy(), request)) def test_match_param_from_dict_fails(self): - _, predicates, _ = self._callFUT(match_param={'foo':'bar','baz':'bum'}) + _, predicates, _ = self._callFUT(match_param=('foo=bar','baz=bum')) request = DummyRequest() request.matchdict = {'foo':'bar', 'baz':'foo'} self.assertFalse(predicates[0](Dummy(), request)) @@ -333,9 +333,9 @@ class Test__make_predicates(unittest.TestCase): import pyramid.testing def view(request): pass config = pyramid.testing.setUp(autocommit=False) - config.add_route('foo', '/foo/{bar}') - config.add_view(view, route_name='foo', match_param='bar=barf') - config.add_view(view, route_name='foo', match_param={'bar': 'baz'}) + config.add_route('foo', '/foo/{a}/{b}') + config.add_view(view, route_name='foo', match_param='a=bar') + config.add_view(view, route_name='foo', match_param=('a=bar', 'b=baz')) config.commit() class TestActionInfo(unittest.TestCase): -- cgit v1.2.3 From 1ceae4adac7c050e955778c71b3680edb9a3cb8c Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 7 Feb 2012 10:06:52 -0600 Subject: bug in url dispatch docs --- docs/narr/urldispatch.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index dfa4e629d..a7bf74786 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -340,7 +340,7 @@ The above pattern will match these URLs, generating the following matchdicts: .. code-block:: text - foo/1/2/ -> {'baz':u'1', 'bar':u'2', 'fizzle':()} + foo/1/2/ -> {'baz':u'1', 'bar':u'2', 'fizzle':u''} foo/abc/def/a/b/c -> {'baz':u'abc', 'bar':u'def', 'fizzle': u'a/b/c'} This occurs because the default regular expression for a marker is ``[^/]+`` -- cgit v1.2.3