From c7974fe0a3363d84afd0db506dbc71b97cb84247 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 5 Dec 2016 22:08:37 -0600 Subject: move predicates into top-level package instead of inside config this better mirrors the view derivers design where the config package uses implementations from the pyramid namespace --- pyramid/config/predicates.py | 303 +-------------- pyramid/config/routes.py | 10 +- pyramid/config/security.py | 2 +- pyramid/config/tweens.py | 2 +- pyramid/config/util.py | 12 - pyramid/config/views.py | 6 +- pyramid/predicates.py | 300 +++++++++++++++ pyramid/tests/test_config/test_predicates.py | 526 --------------------------- pyramid/tests/test_config/test_util.py | 11 +- pyramid/tests/test_predicates.py | 526 +++++++++++++++++++++++++++ pyramid/util.py | 15 +- 11 files changed, 860 insertions(+), 853 deletions(-) create mode 100644 pyramid/predicates.py delete mode 100644 pyramid/tests/test_config/test_predicates.py create mode 100644 pyramid/tests/test_predicates.py diff --git a/pyramid/config/predicates.py b/pyramid/config/predicates.py index 0b76bbd70..5d99d6564 100644 --- a/pyramid/config/predicates.py +++ b/pyramid/config/predicates.py @@ -1,301 +1,2 @@ -import re - -from pyramid.exceptions import ConfigurationError - -from pyramid.compat import is_nonstr_iter - -from pyramid.traversal import ( - find_interface, - traversal_path, - resource_path_tuple - ) - -from pyramid.urldispatch import _compile_route -from pyramid.util import object_description -from pyramid.session import check_csrf_token - -from .util import as_sorted_tuple - -_marker = object() - -class XHRPredicate(object): - def __init__(self, val, config): - self.val = bool(val) - - def text(self): - return 'xhr = %s' % self.val - - phash = text - - def __call__(self, context, request): - return bool(request.is_xhr) is self.val - -class RequestMethodPredicate(object): - def __init__(self, val, config): - request_method = as_sorted_tuple(val) - if 'GET' in request_method and 'HEAD' not in request_method: - # GET implies HEAD too - request_method = as_sorted_tuple(request_method + ('HEAD',)) - self.val = request_method - - def text(self): - return 'request_method = %s' % (','.join(self.val)) - - phash = text - - def __call__(self, context, request): - return request.method in self.val - -class PathInfoPredicate(object): - def __init__(self, val, config): - self.orig = val - try: - val = re.compile(val) - except re.error as why: - raise ConfigurationError(why.args[0]) - self.val = val - - def text(self): - return 'path_info = %s' % (self.orig,) - - phash = text - - def __call__(self, context, request): - return self.val.match(request.upath_info) is not None - -class RequestParamPredicate(object): - def __init__(self, val, config): - val = as_sorted_tuple(val) - reqs = [] - for p in val: - k = p - v = None - if p.startswith('='): - if '=' in p[1:]: - k, v = p[1:].split('=', 1) - k = '=' + k - k, v = k.strip(), v.strip() - elif '=' in p: - k, v = p.split('=', 1) - k, v = k.strip(), v.strip() - reqs.append((k, v)) - self.val = val - self.reqs = reqs - - def text(self): - return 'request_param %s' % ','.join( - ['%s=%s' % (x,y) if y else x for x, y in self.reqs] - ) - - phash = text - - def __call__(self, context, request): - for k, v in self.reqs: - actual = request.params.get(k) - if actual is None: - return False - if v is not None and actual != v: - return False - return True - -class HeaderPredicate(object): - def __init__(self, val, config): - name = val - v = None - if ':' in name: - name, val_str = name.split(':', 1) - try: - v = re.compile(val_str) - except re.error as why: - raise ConfigurationError(why.args[0]) - if v is None: - self._text = 'header %s' % (name,) - else: - self._text = 'header %s=%s' % (name, val_str) - self.name = name - self.val = v - - def text(self): - return self._text - - phash = text - - def __call__(self, context, request): - if self.val is None: - return self.name in request.headers - val = request.headers.get(self.name) - if val is None: - return False - return self.val.match(val) is not None - -class AcceptPredicate(object): - def __init__(self, val, config): - self.val = val - - def text(self): - return 'accept = %s' % (self.val,) - - phash = text - - def __call__(self, context, request): - return self.val in request.accept - -class ContainmentPredicate(object): - def __init__(self, val, config): - self.val = config.maybe_dotted(val) - - def text(self): - return 'containment = %s' % (self.val,) - - phash = text - - def __call__(self, context, request): - ctx = getattr(request, 'context', context) - return find_interface(ctx, self.val) is not None - -class RequestTypePredicate(object): - def __init__(self, val, config): - self.val = val - - def text(self): - return 'request_type = %s' % (self.val,) - - phash = text - - def __call__(self, context, request): - return self.val.providedBy(request) - -class MatchParamPredicate(object): - def __init__(self, val, config): - val = as_sorted_tuple(val) - self.val = val - reqs = [ p.split('=', 1) for p in val ] - self.reqs = [ (x.strip(), y.strip()) for x, y in reqs ] - - def text(self): - return 'match_param %s' % ','.join( - ['%s=%s' % (x,y) for x, y in self.reqs] - ) - - phash = text - - def __call__(self, context, request): - if not request.matchdict: - # might be None - return False - for k, v in self.reqs: - if request.matchdict.get(k) != v: - return False - return True - -class CustomPredicate(object): - def __init__(self, func, config): - self.func = func - - def text(self): - return getattr( - self.func, - '__text__', - 'custom predicate: %s' % object_description(self.func) - ) - - def phash(self): - # using hash() here rather than id() is intentional: we - # want to allow custom predicates that are part of - # frameworks to be able to define custom __hash__ - # functions for custom predicates, so that the hash output - # of predicate instances which are "logically the same" - # may compare equal. - return 'custom:%r' % hash(self.func) - - def __call__(self, context, request): - return self.func(context, request) - - -class TraversePredicate(object): - # Can only be used as a *route* "predicate"; it adds 'traverse' to the - # matchdict if it's specified in the routing args. This causes the - # ResourceTreeTraverser to use the resolved traverse pattern as the - # traversal path. - def __init__(self, val, config): - _, self.tgenerate = _compile_route(val) - self.val = val - - def text(self): - return 'traverse matchdict pseudo-predicate' - - def phash(self): - # This isn't actually a predicate, it's just a infodict modifier that - # injects ``traverse`` into the matchdict. As a result, we don't - # need to update the hash. - return '' - - def __call__(self, context, request): - if 'traverse' in context: - return True - m = context['match'] - tvalue = self.tgenerate(m) # tvalue will be urlquoted string - m['traverse'] = traversal_path(tvalue) - # This isn't actually a predicate, it's just a infodict modifier that - # injects ``traverse`` into the matchdict. As a result, we just - # return True. - return True - -class CheckCSRFTokenPredicate(object): - - check_csrf_token = staticmethod(check_csrf_token) # testing - - def __init__(self, val, config): - self.val = val - - def text(self): - return 'check_csrf = %s' % (self.val,) - - phash = text - - def __call__(self, context, request): - val = self.val - if val: - if val is True: - val = 'csrf_token' - return self.check_csrf_token(request, val, raises=False) - return True - -class PhysicalPathPredicate(object): - def __init__(self, val, config): - if is_nonstr_iter(val): - self.val = tuple(val) - else: - val = tuple(filter(None, val.split('/'))) - self.val = ('',) + val - - def text(self): - return 'physical_path = %s' % (self.val,) - - phash = text - - def __call__(self, context, request): - if getattr(context, '__name__', _marker) is not _marker: - return resource_path_tuple(context) == self.val - return False - -class EffectivePrincipalsPredicate(object): - def __init__(self, val, config): - if is_nonstr_iter(val): - self.val = set(val) - else: - self.val = set((val,)) - - def text(self): - return 'effective_principals = %s' % sorted(list(self.val)) - - phash = text - - def __call__(self, context, request): - req_principals = request.effective_principals - if is_nonstr_iter(req_principals): - rpset = set(req_principals) - if self.val.issubset(rpset): - return True - return False - +import zope.deprecation +zope.deprecation.moved('pyramid.predicates', 'Pyramid 2.0') diff --git a/pyramid/config/routes.py b/pyramid/config/routes.py index 90d4d47d2..203baa128 100644 --- a/pyramid/config/routes.py +++ b/pyramid/config/routes.py @@ -13,12 +13,10 @@ from pyramid.registry import predvalseq from pyramid.request import route_request_iface from pyramid.urldispatch import RoutesMapper -from pyramid.config.util import ( - action_method, - as_sorted_tuple, - ) +from pyramid.config.util import action_method +from pyramid.util import as_sorted_tuple -import pyramid.config.predicates +import pyramid.predicates class RoutesConfiguratorMixin(object): @action_method @@ -446,7 +444,7 @@ class RoutesConfiguratorMixin(object): ) def add_default_route_predicates(self): - p = pyramid.config.predicates + p = pyramid.predicates for (name, factory) in ( ('xhr', p.XHRPredicate), ('request_method', p.RequestMethodPredicate), diff --git a/pyramid/config/security.py b/pyramid/config/security.py index 02732c042..33593376b 100644 --- a/pyramid/config/security.py +++ b/pyramid/config/security.py @@ -9,9 +9,9 @@ from pyramid.interfaces import ( PHASE2_CONFIG, ) -from pyramid.config.util import as_sorted_tuple from pyramid.exceptions import ConfigurationError from pyramid.util import action_method +from pyramid.util import as_sorted_tuple class SecurityConfiguratorMixin(object): @action_method diff --git a/pyramid/config/tweens.py b/pyramid/config/tweens.py index 0aeb01fe3..16712ab16 100644 --- a/pyramid/config/tweens.py +++ b/pyramid/config/tweens.py @@ -17,9 +17,9 @@ from pyramid.tweens import ( from pyramid.config.util import ( action_method, - is_string_or_iterable, TopologicalSorter, ) +from pyramid.util import is_string_or_iterable class TweensConfiguratorMixin(object): def add_tween(self, tween_factory, under=None, over=None): diff --git a/pyramid/config/util.py b/pyramid/config/util.py index 626e8d5fe..b70dae7f3 100644 --- a/pyramid/config/util.py +++ b/pyramid/config/util.py @@ -24,18 +24,6 @@ ActionInfo = ActionInfo # support bw compat imports MAX_ORDER = 1 << 30 DEFAULT_PHASH = md5().hexdigest() -def is_string_or_iterable(v): - if isinstance(v, string_types): - return True - if hasattr(v, '__iter__'): - return True - -def as_sorted_tuple(val): - if not is_nonstr_iter(val): - val = (val,) - val = tuple(sorted(val)) - return val - class not_(object): """ diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 6082d8b48..65c9da585 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -70,10 +70,11 @@ import pyramid.util from pyramid.util import ( viewdefaults, action_method, + as_sorted_tuple, TopologicalSorter, ) -import pyramid.config.predicates +import pyramid.predicates import pyramid.viewderivers from pyramid.viewderivers import ( @@ -89,7 +90,6 @@ from pyramid.viewderivers import ( from pyramid.config.util import ( DEFAULT_PHASH, MAX_ORDER, - as_sorted_tuple, ) urljoin = urlparse.urljoin @@ -1143,7 +1143,7 @@ class ViewsConfiguratorMixin(object): ) def add_default_view_predicates(self): - p = pyramid.config.predicates + p = pyramid.predicates for (name, factory) in ( ('xhr', p.XHRPredicate), ('request_method', p.RequestMethodPredicate), diff --git a/pyramid/predicates.py b/pyramid/predicates.py new file mode 100644 index 000000000..7c3a778ca --- /dev/null +++ b/pyramid/predicates.py @@ -0,0 +1,300 @@ +import re + +from pyramid.exceptions import ConfigurationError + +from pyramid.compat import is_nonstr_iter + +from pyramid.session import check_csrf_token +from pyramid.traversal import ( + find_interface, + traversal_path, + resource_path_tuple + ) + +from pyramid.urldispatch import _compile_route +from pyramid.util import object_description +from pyramid.util import as_sorted_tuple + +_marker = object() + +class XHRPredicate(object): + def __init__(self, val, config): + self.val = bool(val) + + def text(self): + return 'xhr = %s' % self.val + + phash = text + + def __call__(self, context, request): + return bool(request.is_xhr) is self.val + +class RequestMethodPredicate(object): + def __init__(self, val, config): + request_method = as_sorted_tuple(val) + if 'GET' in request_method and 'HEAD' not in request_method: + # GET implies HEAD too + request_method = as_sorted_tuple(request_method + ('HEAD',)) + self.val = request_method + + def text(self): + return 'request_method = %s' % (','.join(self.val)) + + phash = text + + def __call__(self, context, request): + return request.method in self.val + +class PathInfoPredicate(object): + def __init__(self, val, config): + self.orig = val + try: + val = re.compile(val) + except re.error as why: + raise ConfigurationError(why.args[0]) + self.val = val + + def text(self): + return 'path_info = %s' % (self.orig,) + + phash = text + + def __call__(self, context, request): + return self.val.match(request.upath_info) is not None + +class RequestParamPredicate(object): + def __init__(self, val, config): + val = as_sorted_tuple(val) + reqs = [] + for p in val: + k = p + v = None + if p.startswith('='): + if '=' in p[1:]: + k, v = p[1:].split('=', 1) + k = '=' + k + k, v = k.strip(), v.strip() + elif '=' in p: + k, v = p.split('=', 1) + k, v = k.strip(), v.strip() + reqs.append((k, v)) + self.val = val + self.reqs = reqs + + def text(self): + return 'request_param %s' % ','.join( + ['%s=%s' % (x,y) if y else x for x, y in self.reqs] + ) + + phash = text + + def __call__(self, context, request): + for k, v in self.reqs: + actual = request.params.get(k) + if actual is None: + return False + if v is not None and actual != v: + return False + return True + +class HeaderPredicate(object): + def __init__(self, val, config): + name = val + v = None + if ':' in name: + name, val_str = name.split(':', 1) + try: + v = re.compile(val_str) + except re.error as why: + raise ConfigurationError(why.args[0]) + if v is None: + self._text = 'header %s' % (name,) + else: + self._text = 'header %s=%s' % (name, val_str) + self.name = name + self.val = v + + def text(self): + return self._text + + phash = text + + def __call__(self, context, request): + if self.val is None: + return self.name in request.headers + val = request.headers.get(self.name) + if val is None: + return False + return self.val.match(val) is not None + +class AcceptPredicate(object): + def __init__(self, val, config): + self.val = val + + def text(self): + return 'accept = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + return self.val in request.accept + +class ContainmentPredicate(object): + def __init__(self, val, config): + self.val = config.maybe_dotted(val) + + def text(self): + return 'containment = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + ctx = getattr(request, 'context', context) + return find_interface(ctx, self.val) is not None + +class RequestTypePredicate(object): + def __init__(self, val, config): + self.val = val + + def text(self): + return 'request_type = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + return self.val.providedBy(request) + +class MatchParamPredicate(object): + def __init__(self, val, config): + val = as_sorted_tuple(val) + self.val = val + reqs = [ p.split('=', 1) for p in val ] + self.reqs = [ (x.strip(), y.strip()) for x, y in reqs ] + + def text(self): + return 'match_param %s' % ','.join( + ['%s=%s' % (x,y) for x, y in self.reqs] + ) + + phash = text + + def __call__(self, context, request): + if not request.matchdict: + # might be None + return False + for k, v in self.reqs: + if request.matchdict.get(k) != v: + return False + return True + +class CustomPredicate(object): + def __init__(self, func, config): + self.func = func + + def text(self): + return getattr( + self.func, + '__text__', + 'custom predicate: %s' % object_description(self.func) + ) + + def phash(self): + # using hash() here rather than id() is intentional: we + # want to allow custom predicates that are part of + # frameworks to be able to define custom __hash__ + # functions for custom predicates, so that the hash output + # of predicate instances which are "logically the same" + # may compare equal. + return 'custom:%r' % hash(self.func) + + def __call__(self, context, request): + return self.func(context, request) + + +class TraversePredicate(object): + # Can only be used as a *route* "predicate"; it adds 'traverse' to the + # matchdict if it's specified in the routing args. This causes the + # ResourceTreeTraverser to use the resolved traverse pattern as the + # traversal path. + def __init__(self, val, config): + _, self.tgenerate = _compile_route(val) + self.val = val + + def text(self): + return 'traverse matchdict pseudo-predicate' + + def phash(self): + # This isn't actually a predicate, it's just a infodict modifier that + # injects ``traverse`` into the matchdict. As a result, we don't + # need to update the hash. + return '' + + def __call__(self, context, request): + if 'traverse' in context: + return True + m = context['match'] + tvalue = self.tgenerate(m) # tvalue will be urlquoted string + m['traverse'] = traversal_path(tvalue) + # This isn't actually a predicate, it's just a infodict modifier that + # injects ``traverse`` into the matchdict. As a result, we just + # return True. + return True + +class CheckCSRFTokenPredicate(object): + + check_csrf_token = staticmethod(check_csrf_token) # testing + + def __init__(self, val, config): + self.val = val + + def text(self): + return 'check_csrf = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + val = self.val + if val: + if val is True: + val = 'csrf_token' + return self.check_csrf_token(request, val, raises=False) + return True + +class PhysicalPathPredicate(object): + def __init__(self, val, config): + if is_nonstr_iter(val): + self.val = tuple(val) + else: + val = tuple(filter(None, val.split('/'))) + self.val = ('',) + val + + def text(self): + return 'physical_path = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + if getattr(context, '__name__', _marker) is not _marker: + return resource_path_tuple(context) == self.val + return False + +class EffectivePrincipalsPredicate(object): + def __init__(self, val, config): + if is_nonstr_iter(val): + self.val = set(val) + else: + self.val = set((val,)) + + def text(self): + return 'effective_principals = %s' % sorted(list(self.val)) + + phash = text + + def __call__(self, context, request): + req_principals = request.effective_principals + if is_nonstr_iter(req_principals): + rpset = set(req_principals) + if self.val.issubset(rpset): + return True + return False + diff --git a/pyramid/tests/test_config/test_predicates.py b/pyramid/tests/test_config/test_predicates.py deleted file mode 100644 index 9cd8f2734..000000000 --- a/pyramid/tests/test_config/test_predicates.py +++ /dev/null @@ -1,526 +0,0 @@ -import unittest - -from pyramid import testing - -from pyramid.compat import text_ - -class TestXHRPredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import XHRPredicate - return XHRPredicate(val, None) - - def test___call___true(self): - inst = self._makeOne(True) - request = Dummy() - request.is_xhr = True - result = inst(None, request) - self.assertTrue(result) - - def test___call___false(self): - inst = self._makeOne(True) - request = Dummy() - request.is_xhr = False - result = inst(None, request) - self.assertFalse(result) - - def test_text(self): - inst = self._makeOne(True) - self.assertEqual(inst.text(), 'xhr = True') - - def test_phash(self): - inst = self._makeOne(True) - self.assertEqual(inst.phash(), 'xhr = True') - -class TestRequestMethodPredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import RequestMethodPredicate - return RequestMethodPredicate(val, None) - - def test_ctor_get_but_no_head(self): - inst = self._makeOne('GET') - self.assertEqual(inst.val, ('GET', 'HEAD')) - - def test___call___true_single(self): - inst = self._makeOne('GET') - request = Dummy() - request.method = 'GET' - result = inst(None, request) - self.assertTrue(result) - - def test___call___true_multi(self): - inst = self._makeOne(('GET','HEAD')) - request = Dummy() - request.method = 'GET' - result = inst(None, request) - self.assertTrue(result) - - def test___call___false(self): - inst = self._makeOne(('GET','HEAD')) - request = Dummy() - request.method = 'POST' - result = inst(None, request) - self.assertFalse(result) - - def test_text(self): - inst = self._makeOne(('HEAD','GET')) - self.assertEqual(inst.text(), 'request_method = GET,HEAD') - - def test_phash(self): - inst = self._makeOne(('HEAD','GET')) - self.assertEqual(inst.phash(), 'request_method = GET,HEAD') - -class TestPathInfoPredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import PathInfoPredicate - return PathInfoPredicate(val, None) - - def test_ctor_compilefail(self): - from pyramid.exceptions import ConfigurationError - self.assertRaises(ConfigurationError, self._makeOne, '\\') - - def test___call___true(self): - inst = self._makeOne(r'/\d{2}') - request = Dummy() - request.upath_info = text_('/12') - result = inst(None, request) - self.assertTrue(result) - - def test___call___false(self): - inst = self._makeOne(r'/\d{2}') - request = Dummy() - request.upath_info = text_('/n12') - result = inst(None, request) - self.assertFalse(result) - - def test_text(self): - inst = self._makeOne('/') - self.assertEqual(inst.text(), 'path_info = /') - - def test_phash(self): - inst = self._makeOne('/') - self.assertEqual(inst.phash(), 'path_info = /') - -class TestRequestParamPredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import RequestParamPredicate - return RequestParamPredicate(val, None) - - def test___call___true_exists(self): - inst = self._makeOne('abc') - request = Dummy() - request.params = {'abc':1} - result = inst(None, request) - self.assertTrue(result) - - def test___call___true_withval(self): - inst = self._makeOne('abc=1') - request = Dummy() - request.params = {'abc':'1'} - result = inst(None, request) - self.assertTrue(result) - - def test___call___true_multi(self): - inst = self._makeOne(('abc', '=def =2= ')) - request = Dummy() - request.params = {'abc':'1', '=def': '2='} - result = inst(None, request) - self.assertTrue(result) - - def test___call___false_multi(self): - inst = self._makeOne(('abc=3', 'def =2 ')) - request = Dummy() - request.params = {'abc':'3', 'def': '1'} - result = inst(None, request) - self.assertFalse(result) - - def test___call___false(self): - inst = self._makeOne('abc') - request = Dummy() - request.params = {} - result = inst(None, request) - self.assertFalse(result) - - def test_text_exists(self): - inst = self._makeOne('abc') - self.assertEqual(inst.text(), 'request_param abc') - - def test_text_exists_equal_sign(self): - inst = self._makeOne('=abc') - self.assertEqual(inst.text(), 'request_param =abc') - - def test_text_withval(self): - inst = self._makeOne('abc= 1') - self.assertEqual(inst.text(), 'request_param abc=1') - - def test_text_multi(self): - inst = self._makeOne(('abc= 1', 'def')) - self.assertEqual(inst.text(), 'request_param abc=1,def') - - def test_text_multi_equal_sign(self): - inst = self._makeOne(('abc= 1', '=def= 2')) - self.assertEqual(inst.text(), 'request_param =def=2,abc=1') - - def test_phash_exists(self): - inst = self._makeOne('abc') - self.assertEqual(inst.phash(), 'request_param abc') - - def test_phash_exists_equal_sign(self): - inst = self._makeOne('=abc') - self.assertEqual(inst.phash(), 'request_param =abc') - - def test_phash_withval(self): - inst = self._makeOne('abc= 1') - self.assertEqual(inst.phash(), "request_param abc=1") - -class TestMatchParamPredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import MatchParamPredicate - return MatchParamPredicate(val, None) - - def test___call___true_single(self): - inst = self._makeOne('abc=1') - request = Dummy() - request.matchdict = {'abc':'1'} - result = inst(None, request) - self.assertTrue(result) - - - def test___call___true_multi(self): - inst = self._makeOne(('abc=1', 'def=2')) - request = Dummy() - request.matchdict = {'abc':'1', 'def':'2'} - result = inst(None, request) - self.assertTrue(result) - - def test___call___false(self): - inst = self._makeOne('abc=1') - request = Dummy() - request.matchdict = {} - result = inst(None, request) - self.assertFalse(result) - - def test___call___matchdict_is_None(self): - inst = self._makeOne('abc=1') - request = Dummy() - request.matchdict = None - result = inst(None, request) - self.assertFalse(result) - - def test_text(self): - inst = self._makeOne(('def= 1', 'abc =2')) - self.assertEqual(inst.text(), 'match_param abc=2,def=1') - - def test_phash(self): - inst = self._makeOne(('def= 1', 'abc =2')) - self.assertEqual(inst.phash(), 'match_param abc=2,def=1') - -class TestCustomPredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import CustomPredicate - return CustomPredicate(val, None) - - def test___call___true(self): - def func(context, request): - self.assertEqual(context, None) - self.assertEqual(request, None) - return True - inst = self._makeOne(func) - result = inst(None, None) - self.assertTrue(result) - - def test___call___false(self): - def func(context, request): - self.assertEqual(context, None) - self.assertEqual(request, None) - return False - inst = self._makeOne(func) - result = inst(None, None) - self.assertFalse(result) - - def test_text_func_has___text__(self): - pred = predicate() - pred.__text__ = 'text' - inst = self._makeOne(pred) - self.assertEqual(inst.text(), 'text') - - def test_text_func_repr(self): - pred = predicate() - inst = self._makeOne(pred) - self.assertEqual(inst.text(), 'custom predicate: object predicate') - - def test_phash(self): - pred = predicate() - inst = self._makeOne(pred) - self.assertEqual(inst.phash(), 'custom:1') - -class TestTraversePredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import TraversePredicate - return TraversePredicate(val, None) - - def test___call__traverse_has_remainder_already(self): - inst = self._makeOne('/1/:a/:b') - info = {'traverse':'abc'} - request = Dummy() - result = inst(info, request) - self.assertEqual(result, True) - self.assertEqual(info, {'traverse':'abc'}) - - def test___call__traverse_matches(self): - inst = self._makeOne('/1/:a/:b') - info = {'match':{'a':'a', 'b':'b'}} - request = Dummy() - result = inst(info, request) - self.assertEqual(result, True) - self.assertEqual(info, {'match': - {'a':'a', 'b':'b', 'traverse':('1', 'a', 'b')}}) - - def test___call__traverse_matches_with_highorder_chars(self): - inst = self._makeOne(text_(b'/La Pe\xc3\xb1a/{x}', 'utf-8')) - info = {'match':{'x':text_(b'Qu\xc3\xa9bec', 'utf-8')}} - request = Dummy() - result = inst(info, request) - self.assertEqual(result, True) - self.assertEqual( - info['match']['traverse'], - (text_(b'La Pe\xc3\xb1a', 'utf-8'), - text_(b'Qu\xc3\xa9bec', 'utf-8')) - ) - - def test_text(self): - inst = self._makeOne('/abc') - self.assertEqual(inst.text(), 'traverse matchdict pseudo-predicate') - - def test_phash(self): - inst = self._makeOne('/abc') - self.assertEqual(inst.phash(), '') - -class Test_CheckCSRFTokenPredicate(unittest.TestCase): - def _makeOne(self, val, config): - from pyramid.config.predicates import CheckCSRFTokenPredicate - return CheckCSRFTokenPredicate(val, config) - - def test_text(self): - inst = self._makeOne(True, None) - self.assertEqual(inst.text(), 'check_csrf = True') - - def test_phash(self): - inst = self._makeOne(True, None) - self.assertEqual(inst.phash(), 'check_csrf = True') - - def test_it_call_val_True(self): - inst = self._makeOne(True, None) - request = Dummy() - def check_csrf_token(req, val, raises=True): - self.assertEqual(req, request) - self.assertEqual(val, 'csrf_token') - self.assertEqual(raises, False) - return True - inst.check_csrf_token = check_csrf_token - result = inst(None, request) - self.assertEqual(result, True) - - def test_it_call_val_str(self): - inst = self._makeOne('abc', None) - request = Dummy() - def check_csrf_token(req, val, raises=True): - self.assertEqual(req, request) - self.assertEqual(val, 'abc') - self.assertEqual(raises, False) - return True - inst.check_csrf_token = check_csrf_token - result = inst(None, request) - self.assertEqual(result, True) - - def test_it_call_val_False(self): - inst = self._makeOne(False, None) - request = Dummy() - result = inst(None, request) - self.assertEqual(result, True) - -class TestHeaderPredicate(unittest.TestCase): - def _makeOne(self, val): - from pyramid.config.predicates import HeaderPredicate - return HeaderPredicate(val, None) - - def test___call___true_exists(self): - inst = self._makeOne('abc') - request = Dummy() - request.headers = {'abc':1} - result = inst(None, request) - self.assertTrue(result) - - def test___call___true_withval(self): - inst = self._makeOne('abc:1') - request = Dummy() - request.headers = {'abc':'1'} - result = inst(None, request) - self.assertTrue(result) - - def test___call___true_withregex(self): - inst = self._makeOne(r'abc:\d+') - request = Dummy() - request.headers = {'abc':'1'} - result = inst(None, request) - self.assertTrue(result) - - def test___call___false_withregex(self): - inst = self._makeOne(r'abc:\d+') - request = Dummy() - request.headers = {'abc':'a'} - result = inst(None, request) - self.assertFalse(result) - - def test___call___false(self): - inst = self._makeOne('abc') - request = Dummy() - request.headers = {} - result = inst(None, request) - self.assertFalse(result) - - def test_text_exists(self): - inst = self._makeOne('abc') - self.assertEqual(inst.text(), 'header abc') - - def test_text_withval(self): - inst = self._makeOne('abc:1') - self.assertEqual(inst.text(), 'header abc=1') - - def test_text_withregex(self): - inst = self._makeOne(r'abc:\d+') - self.assertEqual(inst.text(), r'header abc=\d+') - - def test_phash_exists(self): - inst = self._makeOne('abc') - self.assertEqual(inst.phash(), 'header abc') - - def test_phash_withval(self): - inst = self._makeOne('abc:1') - self.assertEqual(inst.phash(), "header abc=1") - - def test_phash_withregex(self): - inst = self._makeOne(r'abc:\d+') - self.assertEqual(inst.phash(), r'header abc=\d+') - -class Test_PhysicalPathPredicate(unittest.TestCase): - def _makeOne(self, val, config): - from pyramid.config.predicates import PhysicalPathPredicate - return PhysicalPathPredicate(val, config) - - def test_text(self): - inst = self._makeOne('/', None) - self.assertEqual(inst.text(), "physical_path = ('',)") - - def test_phash(self): - inst = self._makeOne('/', None) - self.assertEqual(inst.phash(), "physical_path = ('',)") - - def test_it_call_val_tuple_True(self): - inst = self._makeOne(('', 'abc'), None) - root = Dummy() - root.__name__ = '' - root.__parent__ = None - context = Dummy() - context.__name__ = 'abc' - context.__parent__ = root - self.assertTrue(inst(context, None)) - - def test_it_call_val_list_True(self): - inst = self._makeOne(['', 'abc'], None) - root = Dummy() - root.__name__ = '' - root.__parent__ = None - context = Dummy() - context.__name__ = 'abc' - context.__parent__ = root - self.assertTrue(inst(context, None)) - - def test_it_call_val_str_True(self): - inst = self._makeOne('/abc', None) - root = Dummy() - root.__name__ = '' - root.__parent__ = None - context = Dummy() - context.__name__ = 'abc' - context.__parent__ = root - self.assertTrue(inst(context, None)) - - def test_it_call_False(self): - inst = self._makeOne('/', None) - root = Dummy() - root.__name__ = '' - root.__parent__ = None - context = Dummy() - context.__name__ = 'abc' - context.__parent__ = root - self.assertFalse(inst(context, None)) - - def test_it_call_context_has_no_name(self): - inst = self._makeOne('/', None) - context = Dummy() - self.assertFalse(inst(context, None)) - -class Test_EffectivePrincipalsPredicate(unittest.TestCase): - def setUp(self): - self.config = testing.setUp() - - def tearDown(self): - testing.tearDown() - - def _makeOne(self, val, config): - from pyramid.config.predicates import EffectivePrincipalsPredicate - return EffectivePrincipalsPredicate(val, config) - - def test_text(self): - inst = self._makeOne(('verna', 'fred'), None) - self.assertEqual(inst.text(), - "effective_principals = ['fred', 'verna']") - - def test_text_noniter(self): - inst = self._makeOne('verna', None) - self.assertEqual(inst.text(), - "effective_principals = ['verna']") - - def test_phash(self): - inst = self._makeOne(('verna', 'fred'), None) - self.assertEqual(inst.phash(), - "effective_principals = ['fred', 'verna']") - - def test_it_call_no_authentication_policy(self): - request = testing.DummyRequest() - inst = self._makeOne(('verna', 'fred'), None) - context = Dummy() - self.assertFalse(inst(context, request)) - - def test_it_call_authentication_policy_provides_superset(self): - request = testing.DummyRequest() - self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi')) - inst = self._makeOne(('verna', 'fred'), None) - context = Dummy() - self.assertTrue(inst(context, request)) - - def test_it_call_authentication_policy_provides_superset_implicit(self): - from pyramid.security import Authenticated - request = testing.DummyRequest() - self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi')) - inst = self._makeOne(Authenticated, None) - context = Dummy() - self.assertTrue(inst(context, request)) - - def test_it_call_authentication_policy_doesnt_provide_superset(self): - request = testing.DummyRequest() - self.config.testing_securitypolicy('fred') - inst = self._makeOne(('verna', 'fred'), None) - context = Dummy() - self.assertFalse(inst(context, request)) - -class predicate(object): - def __repr__(self): - return 'predicate' - def __hash__(self): - return 1 - -class Dummy(object): - def __init__(self, **kw): - self.__dict__.update(**kw) - diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py index ccf7fa260..398b6fba8 100644 --- a/pyramid/tests/test_config/test_util.py +++ b/pyramid/tests/test_config/test_util.py @@ -5,7 +5,7 @@ class TestPredicateList(unittest.TestCase): def _makeOne(self): from pyramid.config.util import PredicateList - from pyramid.config import predicates + from pyramid import predicates inst = PredicateList() for name, factory in ( ('xhr', predicates.XHRPredicate), @@ -594,6 +594,15 @@ class TestNotted(unittest.TestCase): self.assertEqual(inst.phash(), '') self.assertEqual(inst(None, None), True) + +class TestDeprecatedPredicates(unittest.TestCase): + def test_it(self): + import warnings + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always') + from pyramid.config.predicates import XHRPredicate + self.assertEqual(len(w), 1) + class DummyPredicate(object): def __init__(self, result): self.result = result diff --git a/pyramid/tests/test_predicates.py b/pyramid/tests/test_predicates.py new file mode 100644 index 000000000..8a002c24e --- /dev/null +++ b/pyramid/tests/test_predicates.py @@ -0,0 +1,526 @@ +import unittest + +from pyramid import testing + +from pyramid.compat import text_ + +class TestXHRPredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import XHRPredicate + return XHRPredicate(val, None) + + def test___call___true(self): + inst = self._makeOne(True) + request = Dummy() + request.is_xhr = True + result = inst(None, request) + self.assertTrue(result) + + def test___call___false(self): + inst = self._makeOne(True) + request = Dummy() + request.is_xhr = False + result = inst(None, request) + self.assertFalse(result) + + def test_text(self): + inst = self._makeOne(True) + self.assertEqual(inst.text(), 'xhr = True') + + def test_phash(self): + inst = self._makeOne(True) + self.assertEqual(inst.phash(), 'xhr = True') + +class TestRequestMethodPredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import RequestMethodPredicate + return RequestMethodPredicate(val, None) + + def test_ctor_get_but_no_head(self): + inst = self._makeOne('GET') + self.assertEqual(inst.val, ('GET', 'HEAD')) + + def test___call___true_single(self): + inst = self._makeOne('GET') + request = Dummy() + request.method = 'GET' + result = inst(None, request) + self.assertTrue(result) + + def test___call___true_multi(self): + inst = self._makeOne(('GET','HEAD')) + request = Dummy() + request.method = 'GET' + result = inst(None, request) + self.assertTrue(result) + + def test___call___false(self): + inst = self._makeOne(('GET','HEAD')) + request = Dummy() + request.method = 'POST' + result = inst(None, request) + self.assertFalse(result) + + def test_text(self): + inst = self._makeOne(('HEAD','GET')) + self.assertEqual(inst.text(), 'request_method = GET,HEAD') + + def test_phash(self): + inst = self._makeOne(('HEAD','GET')) + self.assertEqual(inst.phash(), 'request_method = GET,HEAD') + +class TestPathInfoPredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import PathInfoPredicate + return PathInfoPredicate(val, None) + + def test_ctor_compilefail(self): + from pyramid.exceptions import ConfigurationError + self.assertRaises(ConfigurationError, self._makeOne, '\\') + + def test___call___true(self): + inst = self._makeOne(r'/\d{2}') + request = Dummy() + request.upath_info = text_('/12') + result = inst(None, request) + self.assertTrue(result) + + def test___call___false(self): + inst = self._makeOne(r'/\d{2}') + request = Dummy() + request.upath_info = text_('/n12') + result = inst(None, request) + self.assertFalse(result) + + def test_text(self): + inst = self._makeOne('/') + self.assertEqual(inst.text(), 'path_info = /') + + def test_phash(self): + inst = self._makeOne('/') + self.assertEqual(inst.phash(), 'path_info = /') + +class TestRequestParamPredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import RequestParamPredicate + return RequestParamPredicate(val, None) + + def test___call___true_exists(self): + inst = self._makeOne('abc') + request = Dummy() + request.params = {'abc':1} + result = inst(None, request) + self.assertTrue(result) + + def test___call___true_withval(self): + inst = self._makeOne('abc=1') + request = Dummy() + request.params = {'abc':'1'} + result = inst(None, request) + self.assertTrue(result) + + def test___call___true_multi(self): + inst = self._makeOne(('abc', '=def =2= ')) + request = Dummy() + request.params = {'abc':'1', '=def': '2='} + result = inst(None, request) + self.assertTrue(result) + + def test___call___false_multi(self): + inst = self._makeOne(('abc=3', 'def =2 ')) + request = Dummy() + request.params = {'abc':'3', 'def': '1'} + result = inst(None, request) + self.assertFalse(result) + + def test___call___false(self): + inst = self._makeOne('abc') + request = Dummy() + request.params = {} + result = inst(None, request) + self.assertFalse(result) + + def test_text_exists(self): + inst = self._makeOne('abc') + self.assertEqual(inst.text(), 'request_param abc') + + def test_text_exists_equal_sign(self): + inst = self._makeOne('=abc') + self.assertEqual(inst.text(), 'request_param =abc') + + def test_text_withval(self): + inst = self._makeOne('abc= 1') + self.assertEqual(inst.text(), 'request_param abc=1') + + def test_text_multi(self): + inst = self._makeOne(('abc= 1', 'def')) + self.assertEqual(inst.text(), 'request_param abc=1,def') + + def test_text_multi_equal_sign(self): + inst = self._makeOne(('abc= 1', '=def= 2')) + self.assertEqual(inst.text(), 'request_param =def=2,abc=1') + + def test_phash_exists(self): + inst = self._makeOne('abc') + self.assertEqual(inst.phash(), 'request_param abc') + + def test_phash_exists_equal_sign(self): + inst = self._makeOne('=abc') + self.assertEqual(inst.phash(), 'request_param =abc') + + def test_phash_withval(self): + inst = self._makeOne('abc= 1') + self.assertEqual(inst.phash(), "request_param abc=1") + +class TestMatchParamPredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import MatchParamPredicate + return MatchParamPredicate(val, None) + + def test___call___true_single(self): + inst = self._makeOne('abc=1') + request = Dummy() + request.matchdict = {'abc':'1'} + result = inst(None, request) + self.assertTrue(result) + + + def test___call___true_multi(self): + inst = self._makeOne(('abc=1', 'def=2')) + request = Dummy() + request.matchdict = {'abc':'1', 'def':'2'} + result = inst(None, request) + self.assertTrue(result) + + def test___call___false(self): + inst = self._makeOne('abc=1') + request = Dummy() + request.matchdict = {} + result = inst(None, request) + self.assertFalse(result) + + def test___call___matchdict_is_None(self): + inst = self._makeOne('abc=1') + request = Dummy() + request.matchdict = None + result = inst(None, request) + self.assertFalse(result) + + def test_text(self): + inst = self._makeOne(('def= 1', 'abc =2')) + self.assertEqual(inst.text(), 'match_param abc=2,def=1') + + def test_phash(self): + inst = self._makeOne(('def= 1', 'abc =2')) + self.assertEqual(inst.phash(), 'match_param abc=2,def=1') + +class TestCustomPredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import CustomPredicate + return CustomPredicate(val, None) + + def test___call___true(self): + def func(context, request): + self.assertEqual(context, None) + self.assertEqual(request, None) + return True + inst = self._makeOne(func) + result = inst(None, None) + self.assertTrue(result) + + def test___call___false(self): + def func(context, request): + self.assertEqual(context, None) + self.assertEqual(request, None) + return False + inst = self._makeOne(func) + result = inst(None, None) + self.assertFalse(result) + + def test_text_func_has___text__(self): + pred = predicate() + pred.__text__ = 'text' + inst = self._makeOne(pred) + self.assertEqual(inst.text(), 'text') + + def test_text_func_repr(self): + pred = predicate() + inst = self._makeOne(pred) + self.assertEqual(inst.text(), 'custom predicate: object predicate') + + def test_phash(self): + pred = predicate() + inst = self._makeOne(pred) + self.assertEqual(inst.phash(), 'custom:1') + +class TestTraversePredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import TraversePredicate + return TraversePredicate(val, None) + + def test___call__traverse_has_remainder_already(self): + inst = self._makeOne('/1/:a/:b') + info = {'traverse':'abc'} + request = Dummy() + result = inst(info, request) + self.assertEqual(result, True) + self.assertEqual(info, {'traverse':'abc'}) + + def test___call__traverse_matches(self): + inst = self._makeOne('/1/:a/:b') + info = {'match':{'a':'a', 'b':'b'}} + request = Dummy() + result = inst(info, request) + self.assertEqual(result, True) + self.assertEqual(info, {'match': + {'a':'a', 'b':'b', 'traverse':('1', 'a', 'b')}}) + + def test___call__traverse_matches_with_highorder_chars(self): + inst = self._makeOne(text_(b'/La Pe\xc3\xb1a/{x}', 'utf-8')) + info = {'match':{'x':text_(b'Qu\xc3\xa9bec', 'utf-8')}} + request = Dummy() + result = inst(info, request) + self.assertEqual(result, True) + self.assertEqual( + info['match']['traverse'], + (text_(b'La Pe\xc3\xb1a', 'utf-8'), + text_(b'Qu\xc3\xa9bec', 'utf-8')) + ) + + def test_text(self): + inst = self._makeOne('/abc') + self.assertEqual(inst.text(), 'traverse matchdict pseudo-predicate') + + def test_phash(self): + inst = self._makeOne('/abc') + self.assertEqual(inst.phash(), '') + +class Test_CheckCSRFTokenPredicate(unittest.TestCase): + def _makeOne(self, val, config): + from pyramid.predicates import CheckCSRFTokenPredicate + return CheckCSRFTokenPredicate(val, config) + + def test_text(self): + inst = self._makeOne(True, None) + self.assertEqual(inst.text(), 'check_csrf = True') + + def test_phash(self): + inst = self._makeOne(True, None) + self.assertEqual(inst.phash(), 'check_csrf = True') + + def test_it_call_val_True(self): + inst = self._makeOne(True, None) + request = Dummy() + def check_csrf_token(req, val, raises=True): + self.assertEqual(req, request) + self.assertEqual(val, 'csrf_token') + self.assertEqual(raises, False) + return True + inst.check_csrf_token = check_csrf_token + result = inst(None, request) + self.assertEqual(result, True) + + def test_it_call_val_str(self): + inst = self._makeOne('abc', None) + request = Dummy() + def check_csrf_token(req, val, raises=True): + self.assertEqual(req, request) + self.assertEqual(val, 'abc') + self.assertEqual(raises, False) + return True + inst.check_csrf_token = check_csrf_token + result = inst(None, request) + self.assertEqual(result, True) + + def test_it_call_val_False(self): + inst = self._makeOne(False, None) + request = Dummy() + result = inst(None, request) + self.assertEqual(result, True) + +class TestHeaderPredicate(unittest.TestCase): + def _makeOne(self, val): + from pyramid.predicates import HeaderPredicate + return HeaderPredicate(val, None) + + def test___call___true_exists(self): + inst = self._makeOne('abc') + request = Dummy() + request.headers = {'abc':1} + result = inst(None, request) + self.assertTrue(result) + + def test___call___true_withval(self): + inst = self._makeOne('abc:1') + request = Dummy() + request.headers = {'abc':'1'} + result = inst(None, request) + self.assertTrue(result) + + def test___call___true_withregex(self): + inst = self._makeOne(r'abc:\d+') + request = Dummy() + request.headers = {'abc':'1'} + result = inst(None, request) + self.assertTrue(result) + + def test___call___false_withregex(self): + inst = self._makeOne(r'abc:\d+') + request = Dummy() + request.headers = {'abc':'a'} + result = inst(None, request) + self.assertFalse(result) + + def test___call___false(self): + inst = self._makeOne('abc') + request = Dummy() + request.headers = {} + result = inst(None, request) + self.assertFalse(result) + + def test_text_exists(self): + inst = self._makeOne('abc') + self.assertEqual(inst.text(), 'header abc') + + def test_text_withval(self): + inst = self._makeOne('abc:1') + self.assertEqual(inst.text(), 'header abc=1') + + def test_text_withregex(self): + inst = self._makeOne(r'abc:\d+') + self.assertEqual(inst.text(), r'header abc=\d+') + + def test_phash_exists(self): + inst = self._makeOne('abc') + self.assertEqual(inst.phash(), 'header abc') + + def test_phash_withval(self): + inst = self._makeOne('abc:1') + self.assertEqual(inst.phash(), "header abc=1") + + def test_phash_withregex(self): + inst = self._makeOne(r'abc:\d+') + self.assertEqual(inst.phash(), r'header abc=\d+') + +class Test_PhysicalPathPredicate(unittest.TestCase): + def _makeOne(self, val, config): + from pyramid.predicates import PhysicalPathPredicate + return PhysicalPathPredicate(val, config) + + def test_text(self): + inst = self._makeOne('/', None) + self.assertEqual(inst.text(), "physical_path = ('',)") + + def test_phash(self): + inst = self._makeOne('/', None) + self.assertEqual(inst.phash(), "physical_path = ('',)") + + def test_it_call_val_tuple_True(self): + inst = self._makeOne(('', 'abc'), None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertTrue(inst(context, None)) + + def test_it_call_val_list_True(self): + inst = self._makeOne(['', 'abc'], None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertTrue(inst(context, None)) + + def test_it_call_val_str_True(self): + inst = self._makeOne('/abc', None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertTrue(inst(context, None)) + + def test_it_call_False(self): + inst = self._makeOne('/', None) + root = Dummy() + root.__name__ = '' + root.__parent__ = None + context = Dummy() + context.__name__ = 'abc' + context.__parent__ = root + self.assertFalse(inst(context, None)) + + def test_it_call_context_has_no_name(self): + inst = self._makeOne('/', None) + context = Dummy() + self.assertFalse(inst(context, None)) + +class Test_EffectivePrincipalsPredicate(unittest.TestCase): + def setUp(self): + self.config = testing.setUp() + + def tearDown(self): + testing.tearDown() + + def _makeOne(self, val, config): + from pyramid.predicates import EffectivePrincipalsPredicate + return EffectivePrincipalsPredicate(val, config) + + def test_text(self): + inst = self._makeOne(('verna', 'fred'), None) + self.assertEqual(inst.text(), + "effective_principals = ['fred', 'verna']") + + def test_text_noniter(self): + inst = self._makeOne('verna', None) + self.assertEqual(inst.text(), + "effective_principals = ['verna']") + + def test_phash(self): + inst = self._makeOne(('verna', 'fred'), None) + self.assertEqual(inst.phash(), + "effective_principals = ['fred', 'verna']") + + def test_it_call_no_authentication_policy(self): + request = testing.DummyRequest() + inst = self._makeOne(('verna', 'fred'), None) + context = Dummy() + self.assertFalse(inst(context, request)) + + def test_it_call_authentication_policy_provides_superset(self): + request = testing.DummyRequest() + self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi')) + inst = self._makeOne(('verna', 'fred'), None) + context = Dummy() + self.assertTrue(inst(context, request)) + + def test_it_call_authentication_policy_provides_superset_implicit(self): + from pyramid.security import Authenticated + request = testing.DummyRequest() + self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi')) + inst = self._makeOne(Authenticated, None) + context = Dummy() + self.assertTrue(inst(context, request)) + + def test_it_call_authentication_policy_doesnt_provide_superset(self): + request = testing.DummyRequest() + self.config.testing_securitypolicy('fred') + inst = self._makeOne(('verna', 'fred'), None) + context = Dummy() + self.assertFalse(inst(context, request)) + +class predicate(object): + def __repr__(self): + return 'predicate' + def __hash__(self): + return 1 + +class Dummy(object): + def __init__(self, **kw): + self.__dict__.update(**kw) + diff --git a/pyramid/util.py b/pyramid/util.py index d5b3c6d72..3337d410d 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -28,13 +28,24 @@ from pyramid.compat import ( from pyramid.interfaces import IActionInfo from pyramid.path import DottedNameResolver as _DottedNameResolver +_marker = object() + class DottedNameResolver(_DottedNameResolver): def __init__(self, package=None): # default to package = None for bw compat _DottedNameResolver.__init__(self, package) -_marker = object() - +def is_string_or_iterable(v): + if isinstance(v, string_types): + return True + if hasattr(v, '__iter__'): + return True + +def as_sorted_tuple(val): + if not is_nonstr_iter(val): + val = (val,) + val = tuple(sorted(val)) + return val class InstancePropertyHelper(object): """A helper object for assigning properties and descriptors to instances. -- cgit v1.2.3 From 7363ebfe8f0e9b65e493780628a7e558dbb74741 Mon Sep 17 00:00:00 2001 From: Mikko Ohtamaa Date: Tue, 6 Dec 2016 11:25:07 +0100 Subject: Fix docs for Sphinx 1.5 --- CONTRIBUTORS.txt | 2 ++ docs/conf.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 98e243c1f..b4e30e085 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -286,3 +286,5 @@ Contributors - Keith Yang, 2016/07/22 - Moriyoshi Koizumi, 2016/11/20 + +- Mikko Ohtamaa, 2016/12/6 diff --git a/docs/conf.py b/docs/conf.py index c3a7170fc..f35f7b34f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -191,7 +191,7 @@ latex_documents = [ # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -latex_use_parts = True +latex_toplevel_sectioning = "section" # If false, no module index is generated. latex_use_modindex = False -- cgit v1.2.3 From 9d1d5776c76d63af6241a995ff648059f12d15ea Mon Sep 17 00:00:00 2001 From: Mikko Ohtamaa Date: Tue, 6 Dec 2016 11:32:23 +0100 Subject: Another Sphinx 1.5 configuraition file change. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index f35f7b34f..84fd5cf1b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -194,7 +194,7 @@ latex_documents = [ latex_toplevel_sectioning = "section" # If false, no module index is generated. -latex_use_modindex = False +latex_domain_indices = False ## Say, for a moment that you have a twoside document that needs a 3cm ## inner margin to allow for binding and at least two centimetres the -- cgit v1.2.3 From 9c120b5e9983c89bd9824269801b4d463d5c892a Mon Sep 17 00:00:00 2001 From: Mikko Ohtamaa Date: Tue, 6 Dec 2016 11:35:58 +0100 Subject: Fix pep8 error on config/util.py --- pyramid/config/util.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyramid/config/util.py b/pyramid/config/util.py index b70dae7f3..67bba9593 100644 --- a/pyramid/config/util.py +++ b/pyramid/config/util.py @@ -4,8 +4,7 @@ import inspect from pyramid.compat import ( bytes_, getargspec, - is_nonstr_iter, - string_types, + is_nonstr_iter ) from pyramid.compat import im_func -- cgit v1.2.3