comparison piecrust/data/iterators.py @ 6:f5ca5c5bed85

More Python 3 fixes, modularization, and new unit tests.
author Ludovic Chabant <ludovic@chabant.com>
date Sat, 16 Aug 2014 08:15:30 -0700
parents f485ba500df3
children cd35d356ccce
comparison
equal deleted inserted replaced
5:474c9882decf 6:f5ca5c5bed85
1 import logging 1 import logging
2 from piecrust.data.base import PaginationData 2 from piecrust.data.base import IPaginationSource
3 from piecrust.data.filters import PaginationFilter 3 from piecrust.data.filters import PaginationFilter
4 from piecrust.events import Event 4 from piecrust.events import Event
5 5
6 6
7 logger = logging.getLogger(__name__) 7 logger = logging.getLogger(__name__)
87 return -1 if v1 < v2 else 1 87 return -1 if v1 < v2 else 1
88 88
89 return sorted(self.it, cmp=self._comparer, reverse=self.reverse) 89 return sorted(self.it, cmp=self._comparer, reverse=self.reverse)
90 90
91 91
92 class DateSortIterator(object):
93 def __init__(self, it, reverse=True):
94 self.it = it
95 self.reverse = reverse
96
97 def __iter__(self):
98 return iter(sorted(self.it,
99 key=lambda x: x.datetime, reverse=self.reverse))
100
101
102 class PaginationFilterIterator(object): 92 class PaginationFilterIterator(object):
103 def __init__(self, it, fil): 93 def __init__(self, it, fil):
104 self.it = it 94 self.it = it
105 self._fil = fil 95 self._fil = fil
106 96
107 def __iter__(self): 97 def __iter__(self):
108 for page in self.it: 98 for page in self.it:
109 if self._fil.pageMatches(page): 99 if self._fil.pageMatches(page):
110 yield page 100 yield page
111
112
113 class SourceFactoryIterator(object):
114 def __init__(self, source):
115 self.source = source
116 self.it = None # This is to permit recursive traversal of the
117 # iterator chain. It acts as the end.
118
119 def __iter__(self):
120 for factory in self.source.getPageFactories():
121 yield factory.buildPage()
122
123
124 class PaginationDataBuilderIterator(object):
125 def __init__(self, it):
126 self.it = it
127
128 def __iter__(self):
129 for page in self.it:
130 yield PaginationData(page)
131 101
132 102
133 class PageIterator(object): 103 class PageIterator(object):
134 def __init__(self, source, current_page=None, pagination_filter=None, 104 def __init__(self, source, current_page=None, pagination_filter=None,
135 offset=0, limit=-1, locked=False): 105 offset=0, limit=-1, locked=False):
136 self._source = source 106 self._source = source
137 self._current_page = current_page 107 self._current_page = current_page
138 self._locked = False 108 self._locked = False
139 self._pages = SourceFactoryIterator(source) 109 self._pages = source
140 self._pagesData = None 110 self._pagesData = None
141 self._pagination_slicer = None 111 self._pagination_slicer = None
142 self._has_sorter = False 112 self._has_sorter = False
143 self._next_page = None 113 self._next_page = None
144 self._prev_page = None 114 self._prev_page = None
145 self._iter_event = Event() 115 self._iter_event = Event()
146 116
117 if isinstance(source, IPaginationSource):
118 src_it = source.getSourceIterator()
119 if src_it is not None:
120 self._pages = src_it
121
147 # Apply any filter first, before we start sorting or slicing. 122 # Apply any filter first, before we start sorting or slicing.
148 if pagination_filter is not None: 123 if pagination_filter is not None:
149 self._simpleNonSortedWrap(PaginationFilterIterator, 124 self._simpleNonSortedWrap(PaginationFilterIterator,
150 pagination_filter) 125 pagination_filter)
151 126
201 def has_filter(value): 176 def has_filter(value):
202 conf = {'has_%s' % name[5:]: value} 177 conf = {'has_%s' % name[5:]: value}
203 return self._simpleNonSortedWrap(SettingFilterIterator, conf) 178 return self._simpleNonSortedWrap(SettingFilterIterator, conf)
204 return has_filter 179 return has_filter
205 180
206 raise AttributeError() 181 return self.__getattribute__(name)
207 182
208 def skip(self, count): 183 def skip(self, count):
209 return self._simpleWrap(SliceIterator, count) 184 return self._simpleWrap(SliceIterator, count)
210 185
211 def limit(self, count): 186 def limit(self, count):
266 "you're trying to tamper with pagination data.") 241 "you're trying to tamper with pagination data.")
267 242
268 def _ensureSorter(self): 243 def _ensureSorter(self):
269 if self._has_sorter: 244 if self._has_sorter:
270 return 245 return
271 self._pages = DateSortIterator(self._pages) 246 if isinstance(self._source, IPaginationSource):
247 sort_it = self._source.getSorterIterator(self._pages)
248 if sort_it is not None:
249 self._pages = sort_it
272 self._has_sorter = True 250 self._has_sorter = True
273 251
274 def _unload(self): 252 def _unload(self):
275 self._pagesData = None 253 self._pagesData = None
276 self._next_page = None 254 self._next_page = None
280 if self._pagesData is not None: 258 if self._pagesData is not None:
281 return 259 return
282 260
283 self._ensureSorter() 261 self._ensureSorter()
284 262
285 it_chain = PaginationDataBuilderIterator(self._pages) 263 it_chain = self._pages
264 is_pgn_source = False
265 if isinstance(self._source, IPaginationSource):
266 is_pgn_source = True
267 tail_it = self._source.getTailIterator(self._pages)
268 if tail_it is not None:
269 it_chain = tail_it
270
286 self._pagesData = list(it_chain) 271 self._pagesData = list(it_chain)
287 272
288 if self._current_page and self._pagination_slicer: 273 if is_pgn_source and self._current_page and self._pagination_slicer:
289 self._prev_page = PaginationData(self._pagination_slicer.prev_page) 274 pn = [self._pagination_slicer.prev_page,
290 self._next_page = PaginationData(self._pagination_slicer.next_page) 275 self._pagination_slicer.next_page]
291 276 pn_it = self._source.getTailIterator(iter(pn))
277 self._prev_page, self._next_page = (list(pn_it))
278