Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/webob/etag.py : 50%

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
1"""
2Does parsing of ETag-related headers: If-None-Matches, If-Matches
4Also If-Range parsing
5"""
7from webob.datetime_utils import (
8 parse_date,
9 serialize_date,
10 )
11from webob.descriptors import _rx_etag
12from webob.util import header_docstring
14__all__ = ['AnyETag', 'NoETag', 'ETagMatcher', 'IfRange', 'etag_property']
17def etag_property(key, default, rfc_section, strong=True):
18 doc = header_docstring(key, rfc_section)
19 doc += " Converts it as a Etag."
21 def fget(req):
22 value = req.environ.get(key)
23 if not value:
24 return default
25 else:
26 return ETagMatcher.parse(value, strong=strong)
28 def fset(req, val):
29 if val is None:
30 req.environ[key] = None
31 else:
32 req.environ[key] = str(val)
34 def fdel(req):
35 del req.environ[key]
37 return property(fget, fset, fdel, doc=doc)
40class _AnyETag(object):
41 """
42 Represents an ETag of *, or a missing ETag when matching is 'safe'
43 """
45 def __repr__(self):
46 return '<ETag *>'
48 def __nonzero__(self):
49 return False
51 __bool__ = __nonzero__ # python 3
53 def __contains__(self, other):
54 return True
56 def __str__(self):
57 return '*'
60AnyETag = _AnyETag()
63class _NoETag(object):
64 """
65 Represents a missing ETag when matching is unsafe
66 """
68 def __repr__(self):
69 return '<No ETag>'
71 def __nonzero__(self):
72 return False
74 __bool__ = __nonzero__ # python 3
76 def __contains__(self, other):
77 return False
79 def __str__(self):
80 return ''
83NoETag = _NoETag()
86# TODO: convert into a simple tuple
88class ETagMatcher(object):
89 def __init__(self, etags):
90 self.etags = etags
92 def __contains__(self, other):
93 return other in self.etags
95 def __repr__(self):
96 return '<ETag %s>' % (' or '.join(self.etags))
98 @classmethod
99 def parse(cls, value, strong=True):
100 """
101 Parse this from a header value
102 """
103 if value == '*':
104 return AnyETag
105 if not value:
106 return cls([])
107 matches = _rx_etag.findall(value)
108 if not matches:
109 return cls([value])
110 elif strong:
111 return cls([t for w, t in matches if not w])
112 else:
113 return cls([t for w, t in matches])
115 def __str__(self):
116 return ', '.join(map('"%s"'.__mod__, self.etags))
119class IfRange(object):
120 def __init__(self, etag):
121 self.etag = etag
123 @classmethod
124 def parse(cls, value):
125 """
126 Parse this from a header value.
127 """
128 if not value:
129 return cls(AnyETag)
130 elif value.endswith(' GMT'):
131 # Must be a date
132 return IfRangeDate(parse_date(value))
133 else:
134 return cls(ETagMatcher.parse(value))
136 def __contains__(self, resp):
137 """
138 Return True if the If-Range header matches the given etag or last_modified
139 """
140 return resp.etag_strong in self.etag
142 def __nonzero__(self):
143 return bool(self.etag)
145 def __repr__(self):
146 return '%s(%r)' % (
147 self.__class__.__name__,
148 self.etag
149 )
151 def __str__(self):
152 return str(self.etag) if self.etag else ''
154 __bool__ = __nonzero__ # python 3
157class IfRangeDate(object):
158 def __init__(self, date):
159 self.date = date
161 def __contains__(self, resp):
162 last_modified = resp.last_modified
163 return last_modified and (last_modified <= self.date)
165 def __repr__(self):
166 return '%s(%r)' % (
167 self.__class__.__name__,
168 self.date
169 )
171 def __str__(self):
172 return serialize_date(self.date)