diff piecrust/rendering.py @ 338:938be93215cb

bake: Improve render context and bake record, fix incremental bake bugs. * Used sources and taxonomies are now stored on a per-render-pass basis. This fixes bugs where sources/taxonomies were used for one pass, but that pass is skipped on a later bake because its result is cached. * Bake records are now created for all pages even when they're not baked. Record collapsing is gone except for taxonomy index pages. * Bake records now also have sub-entries in order to store information about each sub-page, since some sub-pages could use sources/taxonomies differently than others, or be missing from the output. This lets PieCrust handle clean/dirty states on a sub-page level.
author Ludovic Chabant <ludovic@chabant.com>
date Mon, 06 Apr 2015 19:59:54 -0700
parents b034f6f15e22
children 4b1019bb2533
line wrap: on
line diff
--- a/piecrust/rendering.py	Sat Apr 04 07:55:49 2015 -0700
+++ b/piecrust/rendering.py	Mon Apr 06 19:59:54 2015 -0700
@@ -32,7 +32,6 @@
         self.num = num
         self.data = None
         self.content = None
-        self.execution_info = None
 
     @property
     def app(self):
@@ -44,6 +43,15 @@
 PASS_RENDERING = 2
 
 
+RENDER_PASSES = [PASS_FORMATTING, PASS_RENDERING]
+
+
+class RenderPassInfo(object):
+    def __init__(self):
+        self.used_source_names = set()
+        self.used_taxonomy_terms = set()
+
+
 class PageRenderingContext(object):
     def __init__(self, page, uri, page_num=1, force_render=False):
         self.page = page
@@ -53,12 +61,11 @@
         self.pagination_source = None
         self.pagination_filter = None
         self.custom_data = None
-        self.use_cache = False
-        self.used_assets = None
+        self._current_pass = PASS_NONE
+
+        self.render_passes = {}
         self.used_pagination = None
-        self.used_source_names = set()
-        self.used_taxonomy_terms = set()
-        self.current_pass = PASS_NONE
+        self.used_assets = None
 
     @property
     def app(self):
@@ -68,15 +75,27 @@
     def source_metadata(self):
         return self.page.source_metadata
 
+    @property
+    def current_pass_info(self):
+        return self.render_passes.get(self._current_pass)
+
+    def setCurrentPass(self, rdr_pass):
+        if rdr_pass != PASS_NONE:
+            self.render_passes.setdefault(rdr_pass, RenderPassInfo())
+        self._current_pass = rdr_pass
+
     def setPagination(self, paginator):
+        self._raiseIfNoCurrentPass()
         if self.used_pagination is not None:
             raise Exception("Pagination has already been used.")
         self.used_pagination = paginator
         self.addUsedSource(paginator._source)
 
     def addUsedSource(self, source):
+        self._raiseIfNoCurrentPass()
         if isinstance(source, PageSource):
-            self.used_source_names.add((source.name, self.current_pass))
+            pass_info = self.render_passes[self._current_pass]
+            pass_info.used_source_names.add(source.name)
 
     def setTaxonomyFilter(self, taxonomy, term_value):
         is_combination = isinstance(term_value, tuple)
@@ -98,6 +117,10 @@
                 taxonomy.term_name: term_value,
                 'is_multiple_%s' % taxonomy.term_name: is_combination}
 
+    def _raiseIfNoCurrentPass(self):
+        if self._current_pass == PASS_NONE:
+            raise Exception("No rendering pass is currently active.")
+
 
 def render_page(ctx):
     eis = ctx.app.env.exec_info_stack
@@ -114,7 +137,7 @@
             page_data.update(ctx.custom_data)
 
         # Render content segments.
-        ctx.current_pass = PASS_FORMATTING
+        ctx.setCurrentPass(PASS_FORMATTING)
         repo = ctx.app.env.rendered_segments_repository
         if repo and not ctx.force_render:
             cache_key = ctx.uri
@@ -127,7 +150,7 @@
             contents = _do_render_page_segments(page, page_data)
 
         # Render layout.
-        ctx.current_pass = PASS_RENDERING
+        ctx.setCurrentPass(PASS_RENDERING)
         layout_name = page.config.get('layout')
         if layout_name is None:
             layout_name = page.source.config.get('default_layout', 'default')
@@ -141,10 +164,9 @@
         rp = RenderedPage(page, ctx.uri, ctx.page_num)
         rp.data = page_data
         rp.content = output
-        rp.execution_info = eis.current_page_info
         return rp
     finally:
-        ctx.current_pass = PASS_NONE
+        ctx.setCurrentPass(PASS_NONE)
         eis.popPage()
 
 
@@ -162,13 +184,13 @@
 def _do_render_page_segments_from_ctx(ctx):
     eis = ctx.app.env.exec_info_stack
     eis.pushPage(ctx.page, ctx)
-    ctx.current_pass = PASS_FORMATTING
+    ctx.setCurrentPass(PASS_FORMATTING)
     try:
         data_ctx = DataBuildingContext(ctx.page, ctx.uri, ctx.page_num)
         page_data = build_page_data(data_ctx)
         return _do_render_page_segments(ctx.page, page_data)
     finally:
-        ctx.current_pass = PASS_NONE
+        ctx.setCurrentPass(PASS_NONE)
         eis.popPage()