first cut at indicating that only some predicates are negatable
| | |
| | | Inverting Predicate Values |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | You can invert the meaning of any predicate value by wrapping it in a call to |
| | | :class:`pyramid.config.not_`. |
| | | You can invert the meaning of a supported predicate value by wrapping it in a |
| | | call to :class:`pyramid.config.not_`. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | config.add_view( |
| | | 'mypackage.views.my_view', |
| | | route_name='ok', |
| | | request_method=not_('POST') |
| | | header=not_('X-Foo') |
| | | ) |
| | | |
| | | The above example will ensure that the view is called if the request method |
| | | is *not* ``POST``, at least if no other view is more specific. |
| | | does not have the ``X-Foo`` header, at least if no other view is more specific. |
| | | |
| | | A predicate must be *negatable* to use ``not_`` against its value. The current |
| | | set of built-in negatable predicates are: ``path_info``, ``request_param``, |
| | | ``header``, ``containment``, ``request_type``, ``match_param``, |
| | | ``physical_path``, and ``effective_principals``. If you try to use ``not_`` |
| | | against a non-negatable predicate, an error will be raised at startup time. |
| | | |
| | | You can make sure a custom view predicate added via |
| | | :meth:`pyramid.config.Configurator.add_view_predicate` is negatable by adding a |
| | | ``negatable`` attribute to it that is True. |
| | | |
| | | This technique of wrapping a predicate value in ``not_`` can be used anywhere |
| | | predicate values are accepted: |
| | |
| | | # and "i" exist for sorting purposes after conflict resolution. |
| | | ainfo = (order, i, action) |
| | | |
| | | discriminator = undefer(action['discriminator']) |
| | | try: |
| | | discriminator = undefer(action['discriminator']) |
| | | except: |
| | | t, v, tb = sys.exc_info() |
| | | try: |
| | | reraise(ConfigurationExecutionError, |
| | | ConfigurationExecutionError(t, v, action['info']), |
| | | tb) |
| | | finally: |
| | | del t, v, tb |
| | | |
| | | action['discriminator'] = discriminator |
| | | |
| | | if discriminator is None: |
| | |
| | | return request.method in self.val |
| | | |
| | | class PathInfoPredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | self.orig = val |
| | | try: |
| | |
| | | return self.val.match(request.upath_info) is not None |
| | | |
| | | class RequestParamPredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | val = as_sorted_tuple(val) |
| | | reqs = [] |
| | |
| | | return True |
| | | |
| | | class HeaderPredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | name = val |
| | | v = None |
| | |
| | | return self.val in request.accept |
| | | |
| | | class ContainmentPredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | self.val = config.maybe_dotted(val) |
| | | |
| | |
| | | return find_interface(ctx, self.val) is not None |
| | | |
| | | class RequestTypePredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | self.val = val |
| | | |
| | |
| | | return self.val.providedBy(request) |
| | | |
| | | class MatchParamPredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | val = as_sorted_tuple(val) |
| | | self.val = val |
| | |
| | | return True |
| | | |
| | | class PhysicalPathPredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | if is_nonstr_iter(val): |
| | | self.val = tuple(val) |
| | |
| | | return False |
| | | |
| | | class EffectivePrincipalsPredicate(object): |
| | | negatable = True |
| | | def __init__(self, val, config): |
| | | if is_nonstr_iter(val): |
| | | self.val = set(val) |
| | |
| | | notted = True |
| | | pred = predicate_factory(realval, config) |
| | | if notted: |
| | | pred = Notted(pred) |
| | | if getattr(pred, 'negatable', False): |
| | | pred = Notted(pred) |
| | | else: |
| | | raise ConfigurationError( |
| | | '%s is not a negatable predicate' % (pred.text(),), |
| | | ) |
| | | |
| | | hashes = pred.phash() |
| | | if not is_nonstr_iter(hashes): |
| | | hashes = [hashes] |
| | |
| | | from pyramid.exceptions import ConfigurationError |
| | | self.assertRaises(ConfigurationError, self._callFUT, unknown=1) |
| | | |
| | | def test_notted(self): |
| | | def test_notted_configerror(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.config import not_ |
| | | from pyramid.testing import DummyRequest |
| | | request = DummyRequest() |
| | | _, predicates, _ = self._callFUT( |
| | | self.assertRaises(ConfigurationError, self._callFUT, |
| | | xhr='xhr', |
| | | request_method=not_('POST'), |
| | | header=not_('header'), |
| | | ) |
| | | |
| | | def test_notted_ok(self): |
| | | from pyramid.config import not_ |
| | | _, predicates, _ = self._callFUT( |
| | | xhr='xhr', |
| | | path_info=not_('/path_info'), |
| | | header=not_('header'), |
| | | ) |
| | | from pyramid.testing import DummyRequest |
| | | request = DummyRequest() |
| | | request.upath_info = request.path_info |
| | | request.is_xhr = False |
| | | self.assertEqual(predicates[0].text(), 'xhr = True') |
| | | self.assertEqual(predicates[1].text(), |
| | | "!request_method = POST") |
| | | self.assertEqual(predicates[2].text(), '!header header') |
| | | self.assertEqual(predicates[1].text(), '!path_info = /path_info') |
| | | self.assertEqual(predicates[2].text(), |
| | | "!header header") |
| | | self.assertEqual(predicates[0](None, request), False) |
| | | self.assertEqual(predicates[1](None, request), True) |
| | | self.assertEqual(predicates[2](None, request), True) |
| | | |