changeset 226:e9dc18a275ff

data: Add ability for `IPaginationSource`s to specify how to get settings. The `IPaginationSource` has a new `getSettingAccessor` method that returns how to access settings values on items in the pagination source. A default accessor is also available, which uses standard attribute lookup. Also clean some stuff in `LazyPageConfigData`.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 04 Feb 2015 23:49:52 -0800
parents a75d024ee839
children d6d0e4976beb
files piecrust/data/base.py piecrust/data/iterators.py piecrust/sources/base.py
diffstat 3 files changed, 44 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/piecrust/data/base.py	Tue Feb 03 21:04:55 2015 -0800
+++ b/piecrust/data/base.py	Wed Feb 04 23:49:52 2015 -0800
@@ -26,6 +26,9 @@
     def getPaginationFilter(self, page):
         raise NotImplementedError()
 
+    def getSetting(self, item, setting_name):
+        raise NotImplementedError()
+
 
 class LazyPageConfigData(object):
     """ An object that represents the configuration header of a page,
@@ -44,16 +47,22 @@
     def page(self):
         return self._page
 
+    def get(self, name):
+        try:
+            return self._getValue(name)
+        except KeyError:
+            return None
+
     def __getattr__(self, name):
         try:
-            return self.getValue(name)
+            return self._getValue(name)
         except KeyError:
             raise AttributeError
 
     def __getitem__(self, name):
-        return self.getValue(name)
+        return self._getValue(name)
 
-    def getValue(self, name):
+    def _getValue(self, name):
         self._load()
 
         if self._loaders:
@@ -76,7 +85,10 @@
 
         return self._values[name]
 
-    def setValue(self, name, value):
+    def _setValue(self, name, value):
+        if self._values is None:
+            raise Exception("Can't call _setValue before this data has been "
+                            "loaded")
         self._values[name] = value
 
     def mapLoader(self, attr_name, loader):
@@ -130,17 +142,17 @@
 
     def _loadCustom(self):
         page_url = self._get_uri()
-        self.setValue('url', page_url)
-        self.setValue('slug', get_slug(self._page.app, page_url))
-        self.setValue(
+        self._setValue('url', page_url)
+        self._setValue('slug', get_slug(self._page.app, page_url))
+        self._setValue(
                 'timestamp',
                 time.mktime(self.page.datetime.timetuple()))
         date_format = self.page.app.config.get('site/date_format')
         if date_format:
-            self.setValue('date', self.page.datetime.strftime(date_format))
+            self._setValue('date', self.page.datetime.strftime(date_format))
 
         assetor = Assetor(self.page, page_url)
-        self.setValue('assets', assetor)
+        self._setValue('assets', assetor)
 
         segment_names = self.page.config.get('segments')
         for name in segment_names:
@@ -174,11 +186,11 @@
 
         for k, v in segs.items():
             self.mapLoader(k, None)
-            self.setValue(k, v)
+            self._setValue(k, v)
 
         if 'content.abstract' in segs:
-            self.setValue('content', segs['content.abstract'])
-            self.setValue('has_more', True)
+            self._setValue('content', segs['content.abstract'])
+            self._setValue('has_more', True)
             if name == 'content':
                 return segs['content.abstract']
 
--- a/piecrust/data/iterators.py	Tue Feb 03 21:04:55 2015 -0800
+++ b/piecrust/data/iterators.py	Wed Feb 04 23:49:52 2015 -0800
@@ -80,16 +80,24 @@
         self.it = it
         self.name = name
         self.reverse = reverse
-        self.value_accessor = value_accessor
+        self.value_accessor = value_accessor or self._default_value_accessor
 
     def __iter__(self):
         return iter(sorted(self.it, key=self._key_getter,
                            reverse=self.reverse))
 
     def _key_getter(self, item):
-        if self.value_accessor:
-            return self.value_accessor(item, self.name)
-        return item.config.get(self.name)
+        key = self.value_accessor(item, self.name)
+        if key is None:
+            return 0
+        return key
+
+    @staticmethod
+    def _default_value_accessor(item, name):
+        try:
+            return getattr(item, name)
+        except AttributeError:
+            return None
 
 
 class PaginationFilterIterator(object):
@@ -125,7 +133,7 @@
         # Apply any filter first, before we start sorting or slicing.
         if pagination_filter is not None:
             self._simpleNonSortedWrap(PaginationFilterIterator,
-                    pagination_filter)
+                                      pagination_filter)
 
         if offset > 0 or limit > 0:
             self.slice(offset, limit)
@@ -207,8 +215,11 @@
         self._ensureUnlocked()
         self._unload()
         if setting_name is not None:
+            accessor = None
+            if not isinstance(self._source, IPaginationSource):
+                accessor = self._source.getSettingAccessor()
             self._pages = SettingSortIterator(self._pages, setting_name,
-                                              reverse)
+                                              reverse, accessor)
         else:
             self._pages = NaturalSortIterator(self._pages, reverse)
         self._has_sorter = True
--- a/piecrust/sources/base.py	Tue Feb 03 21:04:55 2015 -0800
+++ b/piecrust/sources/base.py	Wed Feb 04 23:49:52 2015 -0800
@@ -294,6 +294,9 @@
             return f
         return None
 
+    def getSettingAccessor(self):
+        return lambda i, n: i.config.get(n)
+
 
 class ArraySource(PageSource, SimplePaginationSourceMixin):
     def __init__(self, app, inner_source, name='array', config=None):