diff piecrust/data/base.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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/piecrust/data/base.py	Sun Aug 10 23:43:16 2014 -0700
@@ -0,0 +1,132 @@
+import time
+import logging
+from piecrust.data.assetor import Assetor
+
+
+logger = logging.getLogger(__name__)
+
+
+class LazyPageConfigData(object):
+    """ An object that represents the configuration header of a page,
+        but also allows for additional data. It's meant to be exposed
+        to the templating system.
+    """
+    def __init__(self, page):
+        self._page = page
+        self._values = None
+        self._loaders = None
+
+    @property
+    def page(self):
+        return self._page
+
+    def __getitem__(self, name):
+        self._load()
+
+        if self._loaders:
+            loader = self._loaders.get(name)
+            if loader is not None:
+                try:
+                    self._values[name] = loader(self, name)
+                except Exception as ex:
+                    logger.error("Error while loading attribute '%s' for: %s"
+                            % (name, self._page.path))
+                    logger.exception(ex)
+                    raise Exception("Internal Error: %s" % ex)
+
+                # We need to double-check `_loaders` here because
+                # the loader could have removed all loaders, which
+                # would set this back to `None`.
+                if self._loaders is not None:
+                    del self._loaders[name]
+                    if len(self._loaders) == 0:
+                        self._loaders = None
+
+        return self._values[name]
+
+    def setValue(self, name, value):
+        self._values[name] = value
+
+    def mapLoader(self, attr_name, loader):
+        if loader is None:
+            if self._loaders is None or attr_name not in self._loaders:
+                return
+            del self._loaders[attr_name]
+            if len(self._loaders) == 0:
+                self._loaders = None
+            return
+
+        if self._loaders is None:
+            self._loaders = {}
+        if attr_name in self._loaders:
+            raise Exception("A loader has already been mapped for: %s" %
+                    attr_name)
+        self._loaders[attr_name] = loader
+
+    def _load(self):
+        if self._values is not None:
+            return
+        self._values = dict(self._page.config.get())
+        try:
+            self._loadCustom()
+        except Exception as ex:
+            logger.error("Error while loading data for: %s" % self._page.path)
+            logger.exception(ex)
+            raise Exception("Internal Error: %s" % ex)
+
+    def _loadCustom(self):
+        pass
+
+
+def build_uri(page):
+    route = page.app.getRoute(page.source.name, page.source_metadata)
+    if route is None:
+        raise Exception("Can't get route for page: %s" % page.path)
+    return route.getUri(page.source_metadata)
+
+
+def load_rendered_segment(data, name):
+    from piecrust.rendering import PageRenderingContext, render_page_segments
+
+    uri = build_uri(data.page)
+    try:
+        ctx = PageRenderingContext(data.page, uri)
+        segs = render_page_segments(ctx)
+    except Exception as e:
+        logger.exception("Error rendering segments for '%s': %s" % (uri, e))
+        raise
+
+    for k, v in segs.iteritems():
+        data.mapLoader(k, None)
+        data.setValue(k, v)
+
+    if 'content.abstract' in segs:
+        data.setValue('content', segs['content.abstract'])
+        data.setValue('has_more', True)
+        if name == 'content':
+            return segs['content.abstract']
+
+    return segs[name]
+
+
+class PaginationData(LazyPageConfigData):
+    def __init__(self, page):
+        super(PaginationData, self).__init__(page)
+
+    def _loadCustom(self):
+        page_url = build_uri(self.page)
+        self.setValue('url', page_url)
+        self.setValue('slug', 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))
+
+        assetor = Assetor(self.page, page_url)
+        self.setValue('assets', assetor)
+
+        segment_names = self.page.config.get('segments')
+        for name in segment_names:
+            self.mapLoader(name, load_rendered_segment)
+