diff piecrust/data/paginationdata.py @ 874:f4608e2e80ce

data: Optimize page data creation. `datetime.strftime` was pretty costly so it's no lazily-computed in some places, and replaced with some better alternative elsewhere.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 15 Jun 2017 07:31:50 -0700
parents 08e02c2a2a1a
children d6d35b2efd04
line wrap: on
line diff
--- a/piecrust/data/paginationdata.py	Thu Jun 15 07:30:44 2017 -0700
+++ b/piecrust/data/paginationdata.py	Thu Jun 15 07:31:50 2017 -0700
@@ -11,69 +11,83 @@
         super().__init__(page)
 
     def _load(self):
-        from piecrust.data.assetor import Assetor
         from piecrust.uriutil import split_uri
 
         page = self._page
         dt = page.datetime
+        set_val = self._setValue
+
         page_url = page.getUri()
         _, slug = split_uri(page.app, page_url)
-        self._setValue('url', page_url)
-        self._setValue('slug', slug)
-        self._setValue('timestamp',
-                       time.mktime(page.datetime.timetuple()))
-        self._setValue('datetime', {
+        set_val('url', page_url)
+        set_val('slug', slug)
+        set_val('timestamp', time.mktime(page.datetime.timetuple()))
+        set_val('datetime', {
             'year': dt.year, 'month': dt.month, 'day': dt.day,
             'hour': dt.hour, 'minute': dt.minute, 'second': dt.second})
-        date_format = page.app.config.get('site/date_format')
-        if date_format:
-            self._setValue('date', page.datetime.strftime(date_format))
-        self._setValue('mtime', page.content_mtime)
+        set_val('mtime', page.content_mtime)
 
-        assetor = Assetor(page)
-        self._setValue('assets', assetor)
+        self._mapLoader('date', _load_date)
+        self._mapLoader('assets', _load_assets)
 
         segment_names = page.config.get('segments')
         for name in segment_names:
-            self._mapLoader(name, self._load_rendered_segment)
+            self._mapLoader(name, _load_rendered_segment)
+
+
+def _load_assets(data, name):
+    from piecrust.data.assetor import Assetor
+    return Assetor(data._page)
+
 
-    def _load_rendered_segment(self, data, name):
-        do_render = True
-        stack = self._page.app.env.render_ctx_stack
-        if stack.hasPage(self._page):
-            # This is the pagination data for the page that is currently
-            # being rendered! Inception! But this is possible... so just
-            # prevent infinite recursion.
-            do_render = False
+def _load_date(data, name):
+    page = data._page
+    date_format = page.app.config.get('site/date_format')
+    if date_format:
+        return page.datetime.strftime(date_format)
+    return None
+
 
-        assert self is data
+def _load_rendered_segment(data, name):
+    page = data._page
+
+    do_render = True
+    stack = page.app.env.render_ctx_stack
+    if stack.hasPage(page):
+        # This is the pagination data for the page that is currently
+        # being rendered! Inception! But this is possible... so just
+        # prevent infinite recursion.
+        do_render = False
 
-        if do_render:
-            uri = self._page.getUri()
-            try:
-                from piecrust.rendering import (
-                    RenderingContext, render_page_segments)
-                ctx = RenderingContext(self._page)
-                render_result = render_page_segments(ctx)
-                segs = render_result.segments
-            except Exception as ex:
-                logger.exception(ex)
-                raise Exception(
-                    "Error rendering segments for '%s'" % uri) from ex
-        else:
-            segs = {}
-            for name in self._page.config.get('segments'):
-                segs[name] = "<unavailable: current page>"
+    if do_render:
+        uri = page.getUri()
+        try:
+            from piecrust.rendering import (
+                RenderingContext, render_page_segments)
+            ctx = RenderingContext(page)
+            render_result = render_page_segments(ctx)
+            segs = render_result.segments
+        except Exception as ex:
+            logger.exception(ex)
+            raise Exception(
+                "Error rendering segments for '%s'" % uri) from ex
+    else:
+        segs = {}
+        for name in page.config.get('segments'):
+            segs[name] = "<unavailable: current page>"
 
-        for k, v in segs.items():
-            self._unmapLoader(k)
-            self._setValue(k, v)
+    unmap_loader = data._unmapLoader
+    set_val = data._setValue
+
+    for k, v in segs.items():
+        unmap_loader(k)
+        set_val(k, v)
 
-        if 'content.abstract' in segs:
-            self._setValue('content', segs['content.abstract'])
-            self._setValue('has_more', True)
-            if name == 'content':
-                return segs['content.abstract']
+    if 'content.abstract' in segs:
+        set_val('content', segs['content.abstract'])
+        set_val('has_more', True)
+        if name == 'content':
+            return segs['content.abstract']
 
-        return segs[name]
+    return segs[name]