comparison piecrust/data/filters.py @ 3:f485ba500df3

Gigantic change to basically make PieCrust 2 vaguely functional. - Serving works, with debug window. - Baking works, multi-threading, with dependency handling. - Various things not implemented yet.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 10 Aug 2014 23:43:16 -0700
parents
children 474c9882decf
comparison
equal deleted inserted replaced
2:40fa08b261b9 3:f485ba500df3
1 import logging
2
3
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(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.iteritems():
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
79
80
81 class IFilterClause(object):
82 def addClause(self, clause):
83 raise NotImplementedError()
84
85 def pageMatches(self, page):
86 raise NotImplementedError()
87
88
89 class NotClause(IFilterClause):
90 def __init__(self):
91 self.child = None
92
93 def addClause(self, clause):
94 if self.child is not None:
95 raise Exception("'NOT' filtering clauses can only have one "
96 "child clause.")
97 self.child = clause
98
99 def pageMatches(self, page):
100 if self.child is None:
101 raise Exception("'NOT' filtering clauses must have one child "
102 "clause.")
103 return not self.child.pageMatches(page)
104
105
106 class BooleanClause(IFilterClause):
107 def __init__(self):
108 self.clauses = []
109
110 def addClause(self, clause):
111 self.clauses.append(clause)
112
113
114 class AndBooleanClause(BooleanClause):
115 def pageMatches(self, page):
116 for c in self.clauses:
117 if not c.pageMatches(page):
118 return False
119 return True
120
121
122 class OrBooleanClause(BooleanClause):
123 def pageMatches(self, page):
124 for c in self.clauses:
125 if c.pageMatches(page):
126 return True
127 return False
128
129
130 class SettingFilterClause(IFilterClause):
131 def __init__(self, name, value, coercer=None):
132 self.name = name
133 self.value = value
134 self.coercer = coercer
135
136 def addClause(self, clause):
137 raise Exception("Setting filter clauses can't have child clauses. "
138 "Use a boolean filter clause instead.")
139
140
141 class HasFilterClause(SettingFilterClause):
142 def pageMatches(self, page):
143 actual_value = page.config.get(self.name)
144 if actual_value is None or not isinstance(actual_value, list):
145 return False
146
147 if self.coercer:
148 actual_value = map(self.coercer, actual_value)
149
150 return self.value in actual_value
151
152
153 class IsFilterClause(SettingFilterClause):
154 def pageMatches(self, page):
155 actual_value = page.config.get(self.name)
156 if self.coercer:
157 actual_value = self.coercer(actual_value)
158 return actual_value == self.value
159