comparison piecrust/data/filters.py @ 967:afd230972167

data: Improve pagination filters code, add `defined` and `not_empty`.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 08 Oct 2017 09:30:59 -0700
parents 08e02c2a2a1a
children
comparison
equal deleted inserted replaced
966:cc55740860de 967:afd230972167
1 import logging 1 import logging
2 2
3 3
4 logger = logging.getLogger(__name__) 4 logger = logging.getLogger(__name__)
5
6
7 class PaginationFilter(object):
8 def __init__(self):
9 self.root_clause = None
10
11 @property
12 def is_empty(self):
13 return self.root_clause is None
14
15 def addClause(self, clause):
16 self._ensureRootClause()
17 self.root_clause.addClause(clause)
18
19 def addClausesFromConfig(self, config):
20 self._ensureRootClause()
21 self._addClausesFromConfigRecursive(config, self.root_clause)
22
23 def pageMatches(self, page):
24 if self.root_clause is None:
25 return True
26 return self.root_clause.pageMatches(self, page)
27
28 def _ensureRootClause(self):
29 if self.root_clause is None:
30 self.root_clause = AndBooleanClause()
31
32 def _addClausesFromConfigRecursive(self, config, parent_clause):
33 for key, val in config.items():
34 if key == 'and':
35 if not isinstance(val, list) or len(val) == 0:
36 raise Exception("The given boolean 'AND' filter clause "
37 "doesn't have an array of child clauses.")
38 subcl = AndBooleanClause()
39 parent_clause.addClause(subcl)
40 for c in val:
41 self._addClausesFromConfigRecursive(c, subcl)
42
43 elif key == 'or':
44 if not isinstance(val, list) or len(val) == 0:
45 raise Exception("The given boolean 'OR' filter clause "
46 "doesn't have an array of child clauses.")
47 subcl = OrBooleanClause()
48 parent_clause.addClause(subcl)
49 for c in val:
50 self._addClausesFromConfigRecursive(c, subcl)
51
52 elif key == 'not':
53 if isinstance(val, list):
54 if len(val) != 1:
55 raise Exception("'NOT' filter clauses must have "
56 "exactly one child clause.")
57 val = val[0]
58 subcl = NotClause()
59 parent_clause.addClause(subcl)
60 self._addClausesFromConfigRecursive(val, subcl)
61
62 elif key[:4] == 'has_':
63 setting_name = key[4:]
64 if isinstance(val, list):
65 wrappercl = AndBooleanClause()
66 for c in val:
67 wrappercl.addClause(HasFilterClause(setting_name, c))
68 parent_clause.addClause(wrappercl)
69 else:
70 parent_clause.addClause(HasFilterClause(setting_name, val))
71
72 elif key[:3] == 'is_':
73 setting_name = key[3:]
74 parent_clause.addClause(IsFilterClause(setting_name, val))
75
76 else:
77 raise Exception("Unknown filter clause: %s" % key)
78 5
79 6
80 class IFilterClause(object): 7 class IFilterClause(object):
81 def addClause(self, clause): 8 def addClause(self, clause):
82 raise NotImplementedError() 9 raise NotImplementedError()
124 if c.pageMatches(fil, page): 51 if c.pageMatches(fil, page):
125 return True 52 return True
126 return False 53 return False
127 54
128 55
56 class IsDefinedFilterClause(IFilterClause):
57 def __init__(self, name):
58 self.name = name
59
60 def pageMatches(self, fil, page):
61 return self.name in page.config
62
63
64 class IsNotEmptyFilterClause(IFilterClause):
65 def __init__(self, name):
66 self.name = name
67
68 def pageMatches(self, fil, page):
69 return bool(page.config.get(self.name))
70
71
129 class SettingFilterClause(IFilterClause): 72 class SettingFilterClause(IFilterClause):
130 def __init__(self, name, value, coercer=None): 73 def __init__(self, name, value, coercer=None):
131 self.name = name 74 self.name = name
132 self.value = value 75 self.value = value
133 self.coercer = coercer 76 self.coercer = coercer
154 actual_value = page.config.get(self.name) 97 actual_value = page.config.get(self.name)
155 if self.coercer: 98 if self.coercer:
156 actual_value = self.coercer(actual_value) 99 actual_value = self.coercer(actual_value)
157 return actual_value == self.value 100 return actual_value == self.value
158 101
102
103 unary_ops = {'not': NotClause}
104 binary_ops = {
105 'and': AndBooleanClause,
106 'or': OrBooleanClause}
107 misc_ops = {
108 'defined': IsDefinedFilterClause,
109 'not_empty': IsNotEmptyFilterClause}
110
111
112 class PaginationFilter(object):
113 def __init__(self):
114 self.root_clause = None
115
116 @property
117 def is_empty(self):
118 return self.root_clause is None
119
120 def addClause(self, clause):
121 self._ensureRootClause()
122 self.root_clause.addClause(clause)
123
124 def addClausesFromConfig(self, config):
125 self._ensureRootClause()
126 self._addClausesFromConfigRecursive(config, self.root_clause)
127
128 def pageMatches(self, page):
129 if self.root_clause is None:
130 return True
131 return self.root_clause.pageMatches(self, page)
132
133 def _ensureRootClause(self):
134 if self.root_clause is None:
135 self.root_clause = AndBooleanClause()
136
137 def _addClausesFromConfigRecursive(self, config, parent_clause):
138 for key, val in config.items():
139 clause_class = unary_ops.get(key)
140 if clause_class:
141 if isinstance(val, list):
142 if len(val) != 1:
143 raise Exception(
144 "Unary filter '%s' must have exactly one child "
145 "clause." % key)
146 val = val[0]
147 subcl = clause_class()
148 parent_clause.addClause(subcl)
149 self._addClausesFromConfigRecursive(val, subcl)
150 continue
151
152 clause_class = binary_ops.get(key)
153 if clause_class:
154 if not isinstance(val, list) or len(val) == 0:
155 raise Exception(
156 "Binary filter clause '%s' doesn't have an array "
157 "of child clauses." % key)
158 subcl = clause_class()
159 parent_clause.addClause(subcl)
160 for c in val:
161 self._addClausesFromConfigRecursive(c, subcl)
162 continue
163
164 clause_class = misc_ops.get(key)
165 if clause_class:
166 if isinstance(val, list):
167 wrappercl = AndBooleanClause()
168 for c in val:
169 wrappercl.addClause(clause_class(c))
170 parent_clause.addClause(wrappercl)
171 else:
172 parent_clause.addClause(clause_class(val))
173 continue
174
175 if key[:4] == 'has_':
176 setting_name = key[4:]
177 if isinstance(val, list):
178 wrappercl = AndBooleanClause()
179 for c in val:
180 wrappercl.addClause(HasFilterClause(setting_name, c))
181 parent_clause.addClause(wrappercl)
182 else:
183 parent_clause.addClause(HasFilterClause(setting_name, val))
184 continue
185
186 if key[:3] == 'is_':
187 setting_name = key[3:]
188 parent_clause.addClause(IsFilterClause(setting_name, val))
189 continue
190
191 raise Exception("Unknown filter clause: %s" % key)