Mercurial > piecrust2
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 |
