Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/pyramid/predicates.py : 40%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import re
3from pyramid.exceptions import ConfigurationError
5from pyramid.compat import is_nonstr_iter
7from pyramid.csrf import check_csrf_token
8from pyramid.traversal import (
9 find_interface,
10 traversal_path,
11 resource_path_tuple,
12)
14from pyramid.urldispatch import _compile_route
15from pyramid.util import as_sorted_tuple, object_description
17_marker = object()
20class XHRPredicate(object):
21 def __init__(self, val, config):
22 self.val = bool(val)
24 def text(self):
25 return 'xhr = %s' % self.val
27 phash = text
29 def __call__(self, context, request):
30 return bool(request.is_xhr) is self.val
33class RequestMethodPredicate(object):
34 def __init__(self, val, config):
35 request_method = as_sorted_tuple(val)
36 if 'GET' in request_method and 'HEAD' not in request_method:
37 # GET implies HEAD too
38 request_method = as_sorted_tuple(request_method + ('HEAD',))
39 self.val = request_method
41 def text(self):
42 return 'request_method = %s' % (','.join(self.val))
44 phash = text
46 def __call__(self, context, request):
47 return request.method in self.val
50class PathInfoPredicate(object):
51 def __init__(self, val, config):
52 self.orig = val
53 try:
54 val = re.compile(val)
55 except re.error as why:
56 raise ConfigurationError(why.args[0])
57 self.val = val
59 def text(self):
60 return 'path_info = %s' % (self.orig,)
62 phash = text
64 def __call__(self, context, request):
65 return self.val.match(request.upath_info) is not None
68class RequestParamPredicate(object):
69 def __init__(self, val, config):
70 val = as_sorted_tuple(val)
71 reqs = []
72 for p in val:
73 k = p
74 v = None
75 if p.startswith('='):
76 if '=' in p[1:]:
77 k, v = p[1:].split('=', 1)
78 k = '=' + k
79 k, v = k.strip(), v.strip()
80 elif '=' in p:
81 k, v = p.split('=', 1)
82 k, v = k.strip(), v.strip()
83 reqs.append((k, v))
84 self.val = val
85 self.reqs = reqs
87 def text(self):
88 return 'request_param %s' % ','.join(
89 ['%s=%s' % (x, y) if y else x for x, y in self.reqs]
90 )
92 phash = text
94 def __call__(self, context, request):
95 for k, v in self.reqs:
96 actual = request.params.get(k)
97 if actual is None:
98 return False
99 if v is not None and actual != v:
100 return False
101 return True
104class HeaderPredicate(object):
105 def __init__(self, val, config):
106 name = val
107 v = None
108 if ':' in name:
109 name, val_str = name.split(':', 1)
110 try:
111 v = re.compile(val_str)
112 except re.error as why:
113 raise ConfigurationError(why.args[0])
114 if v is None:
115 self._text = 'header %s' % (name,)
116 else:
117 self._text = 'header %s=%s' % (name, val_str)
118 self.name = name
119 self.val = v
121 def text(self):
122 return self._text
124 phash = text
126 def __call__(self, context, request):
127 if self.val is None:
128 return self.name in request.headers
129 val = request.headers.get(self.name)
130 if val is None:
131 return False
132 return self.val.match(val) is not None
135class AcceptPredicate(object):
136 _is_using_deprecated_ranges = False
138 def __init__(self, values, config):
139 if not is_nonstr_iter(values):
140 values = (values,)
141 # deprecated media ranges were only supported in versions of the
142 # predicate that didn't support lists, so check it here
143 if len(values) == 1 and '*' in values[0]:
144 self._is_using_deprecated_ranges = True
145 self.values = values
147 def text(self):
148 return 'accept = %s' % (', '.join(self.values),)
150 phash = text
152 def __call__(self, context, request):
153 if self._is_using_deprecated_ranges:
154 return self.values[0] in request.accept
155 return bool(request.accept.acceptable_offers(self.values))
158class ContainmentPredicate(object):
159 def __init__(self, val, config):
160 self.val = config.maybe_dotted(val)
162 def text(self):
163 return 'containment = %s' % (self.val,)
165 phash = text
167 def __call__(self, context, request):
168 ctx = getattr(request, 'context', context)
169 return find_interface(ctx, self.val) is not None
172class RequestTypePredicate(object):
173 def __init__(self, val, config):
174 self.val = val
176 def text(self):
177 return 'request_type = %s' % (self.val,)
179 phash = text
181 def __call__(self, context, request):
182 return self.val.providedBy(request)
185class MatchParamPredicate(object):
186 def __init__(self, val, config):
187 val = as_sorted_tuple(val)
188 self.val = val
189 reqs = [p.split('=', 1) for p in val]
190 self.reqs = [(x.strip(), y.strip()) for x, y in reqs]
192 def text(self):
193 return 'match_param %s' % ','.join(
194 ['%s=%s' % (x, y) for x, y in self.reqs]
195 )
197 phash = text
199 def __call__(self, context, request):
200 if not request.matchdict:
201 # might be None
202 return False
203 for k, v in self.reqs:
204 if request.matchdict.get(k) != v:
205 return False
206 return True
209class CustomPredicate(object):
210 def __init__(self, func, config):
211 self.func = func
213 def text(self):
214 return getattr(
215 self.func,
216 '__text__',
217 'custom predicate: %s' % object_description(self.func),
218 )
220 def phash(self):
221 # using hash() here rather than id() is intentional: we
222 # want to allow custom predicates that are part of
223 # frameworks to be able to define custom __hash__
224 # functions for custom predicates, so that the hash output
225 # of predicate instances which are "logically the same"
226 # may compare equal.
227 return 'custom:%r' % hash(self.func)
229 def __call__(self, context, request):
230 return self.func(context, request)
233class TraversePredicate(object):
234 # Can only be used as a *route* "predicate"; it adds 'traverse' to the
235 # matchdict if it's specified in the routing args. This causes the
236 # ResourceTreeTraverser to use the resolved traverse pattern as the
237 # traversal path.
238 def __init__(self, val, config):
239 _, self.tgenerate = _compile_route(val)
240 self.val = val
242 def text(self):
243 return 'traverse matchdict pseudo-predicate'
245 def phash(self):
246 # This isn't actually a predicate, it's just a infodict modifier that
247 # injects ``traverse`` into the matchdict. As a result, we don't
248 # need to update the hash.
249 return ''
251 def __call__(self, context, request):
252 if 'traverse' in context:
253 return True
254 m = context['match']
255 tvalue = self.tgenerate(m) # tvalue will be urlquoted string
256 m['traverse'] = traversal_path(tvalue)
257 # This isn't actually a predicate, it's just a infodict modifier that
258 # injects ``traverse`` into the matchdict. As a result, we just
259 # return True.
260 return True
263class CheckCSRFTokenPredicate(object):
265 check_csrf_token = staticmethod(check_csrf_token) # testing
267 def __init__(self, val, config):
268 self.val = val
270 def text(self):
271 return 'check_csrf = %s' % (self.val,)
273 phash = text
275 def __call__(self, context, request):
276 val = self.val
277 if val:
278 if val is True:
279 val = 'csrf_token'
280 return self.check_csrf_token(request, val, raises=False)
281 return True
284class PhysicalPathPredicate(object):
285 def __init__(self, val, config):
286 if is_nonstr_iter(val):
287 self.val = tuple(val)
288 else:
289 val = tuple(filter(None, val.split('/')))
290 self.val = ('',) + val
292 def text(self):
293 return 'physical_path = %s' % (self.val,)
295 phash = text
297 def __call__(self, context, request):
298 if getattr(context, '__name__', _marker) is not _marker:
299 return resource_path_tuple(context) == self.val
300 return False
303class EffectivePrincipalsPredicate(object):
304 def __init__(self, val, config):
305 if is_nonstr_iter(val):
306 self.val = set(val)
307 else:
308 self.val = set((val,))
310 def text(self):
311 return 'effective_principals = %s' % sorted(list(self.val))
313 phash = text
315 def __call__(self, context, request):
316 req_principals = request.effective_principals
317 if is_nonstr_iter(req_principals):
318 rpset = set(req_principals)
319 if self.val.issubset(rpset):
320 return True
321 return False
324class Notted(object):
325 def __init__(self, predicate):
326 self.predicate = predicate
328 def _notted_text(self, val):
329 # if the underlying predicate doesnt return a value, it's not really
330 # a predicate, it's just something pretending to be a predicate,
331 # so dont update the hash
332 if val:
333 val = '!' + val
334 return val
336 def text(self):
337 return self._notted_text(self.predicate.text())
339 def phash(self):
340 return self._notted_text(self.predicate.phash())
342 def __call__(self, context, request):
343 result = self.predicate(context, request)
344 phash = self.phash()
345 if phash:
346 result = not result
347 return result