summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Merickel <michael@merickel.org>2011-08-23 02:21:40 -0500
committerMichael Merickel <michael@merickel.org>2011-08-23 02:21:40 -0500
commit718a440916739fd433c8edda3e93a672b42aa371 (patch)
tree5285d5792d75574bbe7437f04d62672135cb831a
parent0025e98c245a170d319510b0ba02a1b745d7adc8 (diff)
downloadpyramid-718a440916739fd433c8edda3e93a672b42aa371.tar.gz
pyramid-718a440916739fd433c8edda3e93a672b42aa371.tar.bz2
pyramid-718a440916739fd433c8edda3e93a672b42aa371.zip
Added support for a ``match_param`` view predicate.
-rw-r--r--pyramid/config/util.py19
-rw-r--r--pyramid/config/views.py26
-rw-r--r--pyramid/tests/test_config/test_util.py55
3 files changed, 90 insertions, 10 deletions
diff --git a/pyramid/config/util.py b/pyramid/config/util.py
index e6be528bf..c631da44c 100644
--- a/pyramid/config/util.py
+++ b/pyramid/config/util.py
@@ -35,8 +35,8 @@ def action_method(wrapped):
return wrapper
def make_predicates(xhr=None, request_method=None, path_info=None,
- request_param=None, header=None, accept=None,
- containment=None, request_type=None,
+ request_param=None, match_param=None, header=None,
+ accept=None, containment=None, request_type=None,
traverse=None, custom=()):
# PREDICATES
@@ -184,6 +184,21 @@ def make_predicates(xhr=None, request_method=None, path_info=None,
predicates.append(request_type_predicate)
h.update('request_type:%r' % hash(request_type))
+ if match_param is not None:
+ if isinstance(match_param, basestring):
+ match_param, match_param_val = match_param.split('=', 1)
+ match_param = {match_param: match_param_val}
+ text = "match_param %s" % match_param
+ def match_param_predicate(context, request):
+ for k, v in match_param.iteritems():
+ 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('match_param:%r' % match_param)
+
if traverse is not None:
# ``traverse`` can only be used as a *route* "predicate"; it
# adds 'traverse' to the matchdict if it's specified in the
diff --git a/pyramid/config/views.py b/pyramid/config/views.py
index 2d39524ac..8c7106736 100644
--- a/pyramid/config/views.py
+++ b/pyramid/config/views.py
@@ -531,7 +531,8 @@ class ViewsConfiguratorMixin(object):
request_param=None, containment=None, attr=None,
renderer=None, wrapper=None, xhr=False, accept=None,
header=None, path_info=None, custom_predicates=(),
- context=None, decorator=None, mapper=None, http_cache=None):
+ context=None, decorator=None, mapper=None, http_cache=None,
+ match_param=None):
""" Add a :term:`view configuration` to the current
configuration state. Arguments to ``add_view`` are broken
down below into *predicate* arguments and *non-predicate*
@@ -775,6 +776,23 @@ class ViewsConfiguratorMixin(object):
the value must match the right hand side of the expression
(``123``) for the view to "match" the current request.
+ match_param
+
+ .. 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.
+
+ A view declaration with this argument ensures that the view will
+ only be called when the :term:`request` has key/value pairs in
+ the ``matchdict`` that equal those supplied in the predicate.
+ e.g. ``match_param="action=edit" would require the ``action``
+ parameter in the ``matchdict`` match the right hande 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
+ for the predicate to pass.
+
containment
This value should be a Python class or :term:`interface` (or a
@@ -832,7 +850,6 @@ class ViewsConfiguratorMixin(object):
variable. If the regex matches, this predicate will be
``True``.
-
custom_predicates
This value should be a sequence of references to custom
@@ -885,6 +902,7 @@ class ViewsConfiguratorMixin(object):
containment=containment, attr=attr,
renderer=renderer, wrapper=wrapper, xhr=xhr, accept=accept,
header=header, path_info=path_info,
+ match_param=match_param,
custom_predicates=custom_predicates, context=context,
mapper = mapper, http_cache = http_cache,
)
@@ -896,7 +914,7 @@ class ViewsConfiguratorMixin(object):
request_method=request_method, path_info=path_info,
request_param=request_param, header=header, accept=accept,
containment=containment, request_type=request_type,
- custom=custom_predicates)
+ match_param=match_param, custom=custom_predicates)
if context is None:
context = for_
@@ -1040,7 +1058,7 @@ class ViewsConfiguratorMixin(object):
discriminator = [
'view', context, name, request_type, IView, containment,
- request_param, request_method, route_name, attr,
+ request_param, request_method, match_param, route_name, attr,
xhr, accept, header, path_info]
discriminator.extend(sorted(custom_predicates))
discriminator = tuple(discriminator)
diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py
index 1e43fc6f1..a7119eced 100644
--- a/pyramid/tests/test_config/test_util.py
+++ b/pyramid/tests/test_config/test_util.py
@@ -16,6 +16,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
path_info='path_info',
request_param='param',
+ match_param='foo=bar',
header='header',
accept='accept',
containment='containment',
@@ -27,6 +28,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
path_info='path_info',
request_param='param',
+ match_param='foo=bar',
header='header',
accept='accept',
containment='containment',
@@ -38,6 +40,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
path_info='path_info',
request_param='param',
+ match_param='foo=bar',
header='header',
accept='accept',
containment='containment',
@@ -48,6 +51,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
path_info='path_info',
request_param='param',
+ match_param='foo=bar',
header='header',
accept='accept',
containment='containment',
@@ -57,6 +61,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
path_info='path_info',
request_param='param',
+ match_param='foo=bar',
header='header',
accept='accept',
)
@@ -65,6 +70,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
path_info='path_info',
request_param='param',
+ match_param='foo=bar',
header='header',
)
order7, _, _ = self._callFUT(
@@ -72,20 +78,27 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
path_info='path_info',
request_param='param',
+ match_param='foo=bar',
)
order8, _, _ = self._callFUT(
xhr='xhr',
request_method='request_method',
path_info='path_info',
+ request_param='param',
)
order9, _, _ = self._callFUT(
xhr='xhr',
request_method='request_method',
+ path_info='path_info',
)
order10, _, _ = self._callFUT(
xhr='xhr',
+ request_method='request_method',
)
order11, _, _ = self._callFUT(
+ xhr='xhr',
+ )
+ order12, _, _ = self._callFUT(
)
self.assertEqual(order1, order2)
self.assertTrue(order3 > order2)
@@ -97,6 +110,7 @@ class Test__make_predicates(unittest.TestCase):
self.assertTrue(order9 > order8)
self.assertTrue(order10 > order9)
self.assertTrue(order11 > order10)
+ self.assertTrue(order12 > order10)
def test_ordering_importance_of_predicates(self):
order1, _, _ = self._callFUT(
@@ -124,6 +138,9 @@ class Test__make_predicates(unittest.TestCase):
request_type='request_type',
)
order9, _, _ = self._callFUT(
+ match_param='foo=bar',
+ )
+ order10, _, _ = self._callFUT(
custom=(DummyCustomPredicate(),),
)
self.assertTrue(order1 > order2)
@@ -134,6 +151,7 @@ class Test__make_predicates(unittest.TestCase):
self.assertTrue(order6 > order7)
self.assertTrue(order7 > order8)
self.assertTrue(order8 > order9)
+ self.assertTrue(order9 > order10)
def test_ordering_importance_and_number(self):
order1, _, _ = self._callFUT(
@@ -221,7 +239,8 @@ class Test__make_predicates(unittest.TestCase):
request_type='request_type',
custom=(DummyCustomPredicate(),
DummyCustomPredicate.classmethod_predicate,
- DummyCustomPredicate.classmethod_predicate_no_text))
+ DummyCustomPredicate.classmethod_predicate_no_text),
+ match_param='foo=bar')
self.assertEqual(predicates[0].__text__, 'xhr = True')
self.assertEqual(predicates[1].__text__,
'request method = request_method')
@@ -231,9 +250,34 @@ 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__, 'custom predicate')
- self.assertEqual(predicates[9].__text__, 'classmethod predicate')
- self.assertEqual(predicates[10].__text__, '<unknown custom predicate>')
+ 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__, '<unknown custom predicate>')
+
+ def test_match_param_from_string(self):
+ _, predicates, _ = self._callFUT(match_param='foo=bar')
+ request = DummyRequest()
+ request.matchdict = {'foo':'bar', 'baz':'bum'}
+ self.assertTrue(predicates[0](Dummy(), request))
+
+ def test_match_param_from_string_fails(self):
+ _, predicates, _ = self._callFUT(match_param='foo=bar')
+ request = DummyRequest()
+ request.matchdict = {'foo':'bum', 'baz':'bum'}
+ self.assertFalse(predicates[0](Dummy(), request))
+
+ def test_match_param_from_dict(self):
+ _, 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'})
+ request = DummyRequest()
+ request.matchdict = {'foo':'bar', 'baz':'foo'}
+ self.assertFalse(predicates[0](Dummy(), request))
class DummyCustomPredicate(object):
def __init__(self):
@@ -246,6 +290,9 @@ class DummyCustomPredicate(object):
@classmethod
def classmethod_predicate_no_text(*args): pass # pragma: no cover
+class Dummy:
+ pass
+
class DummyRequest:
subpath = ()
matchdict = None