Mercurial > piecrust2
diff piecrust/rendering.py @ 989:8adc27285d93
bake: Big pass on bake performance.
- Reduce the amount of data passed between processes.
- Make inter-process data simple objects to make it easier to test with
alternatives to pickle.
- Make sources have the basic requirement to be able to find a content item
from an item spec (path).
- Make Hoedown the default Markdown formatter.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 19 Nov 2017 14:29:17 -0800 |
parents | 45ad976712ec |
children | 1857dbd4580f |
line wrap: on
line diff
--- a/piecrust/rendering.py Fri Nov 03 23:14:56 2017 -0700 +++ b/piecrust/rendering.py Sun Nov 19 14:29:17 2017 -0800 @@ -1,6 +1,5 @@ import re import os.path -import copy import logging from piecrust.data.builder import ( DataBuildingContext, build_page_data, add_layout_data) @@ -24,15 +23,14 @@ class RenderedSegments(object): - def __init__(self, segments, render_pass_info): + def __init__(self, segments, used_templating=False): self.segments = segments - self.render_pass_info = render_pass_info + self.used_templating = used_templating class RenderedLayout(object): - def __init__(self, content, render_pass_info): + def __init__(self, content): self.content = content - self.render_pass_info = render_pass_info class RenderedPage(object): @@ -41,37 +39,24 @@ self.sub_num = sub_num self.data = None self.content = None - self.render_info = [None, None] + self.render_info = {} @property def app(self): return self.page.app - def copyRenderInfo(self): - return copy.deepcopy(self.render_info) - -PASS_NONE = -1 -PASS_FORMATTING = 0 -PASS_RENDERING = 1 - - -RENDER_PASSES = [PASS_FORMATTING, PASS_RENDERING] - - -class RenderPassInfo(object): - def __init__(self): - self.used_source_names = set() - self.used_pagination = False - self.pagination_has_more = False - self.used_assets = False - self._custom_info = {} - - def setCustomInfo(self, key, info): - self._custom_info[key] = info - - def getCustomInfo(self, key, default=None): - return self._custom_info.get(key, default) +def create_render_info(): + """ Creates a bag of rendering properties. It's a dictionary because + it will be passed between workers during the bake process, and + saved to records. + """ + return { + 'used_source_names': set(), + 'used_pagination': False, + 'pagination_has_more': False, + 'used_assets': False, + } class RenderingContext(object): @@ -81,43 +66,25 @@ self.force_render = force_render self.pagination_source = None self.pagination_filter = None + self.render_info = create_render_info() self.custom_data = {} - self.render_passes = [None, None] # Same length as RENDER_PASSES - self._current_pass = PASS_NONE @property def app(self): return self.page.app - @property - def current_pass_info(self): - if self._current_pass != PASS_NONE: - return self.render_passes[self._current_pass] - return None - - def setCurrentPass(self, rdr_pass): - if rdr_pass != PASS_NONE: - self.render_passes[rdr_pass] = RenderPassInfo() - self._current_pass = rdr_pass - def setPagination(self, paginator): - self._raiseIfNoCurrentPass() - pass_info = self.current_pass_info - if pass_info.used_pagination: + ri = self.render_info + if ri.get('used_pagination'): raise Exception("Pagination has already been used.") assert paginator.is_loaded - pass_info.used_pagination = True - pass_info.pagination_has_more = paginator.has_more + ri['used_pagination'] = True + ri['pagination_has_more'] = paginator.has_more self.addUsedSource(paginator._source) def addUsedSource(self, source): - self._raiseIfNoCurrentPass() - pass_info = self.current_pass_info - pass_info.used_source_names.add(source.name) - - def _raiseIfNoCurrentPass(self): - if self._current_pass == PASS_NONE: - raise Exception("No rendering pass is currently active.") + ri = self.render_info + ri['used_source_names'].add(source.name) class RenderingContextStack(object): @@ -173,7 +140,6 @@ page_data = _build_render_data(ctx) # Render content segments. - ctx.setCurrentPass(PASS_FORMATTING) repo = env.rendered_segments_repository save_to_fs = True if env.fs_cache_only_for_main_page and not stack.is_main_ctx: @@ -191,7 +157,6 @@ repo.put(page_uri, render_result, save_to_fs) # Render layout. - ctx.setCurrentPass(PASS_RENDERING) layout_name = page.config.get('layout') if layout_name is None: layout_name = page.source.config.get( @@ -206,13 +171,12 @@ layout_name, page, page_data) else: layout_result = RenderedLayout( - render_result.segments['content'], None) + render_result.segments['content']) rp = RenderedPage(page, ctx.sub_num) rp.data = page_data rp.content = layout_result.content - rp.render_info[PASS_FORMATTING] = render_result.render_pass_info - rp.render_info[PASS_RENDERING] = layout_result.render_pass_info + rp.render_info = ctx.render_info return rp except AbortedSourceUseError: @@ -225,7 +189,6 @@ ctx.page.content_spec) from ex finally: - ctx.setCurrentPass(PASS_NONE) stack.popCtx() @@ -248,7 +211,6 @@ page_uri = page.getUri(ctx.sub_num) try: - ctx.setCurrentPass(PASS_FORMATTING) repo = env.rendered_segments_repository save_to_fs = True @@ -267,7 +229,6 @@ if repo: repo.put(page_uri, render_result, save_to_fs) finally: - ctx.setCurrentPass(PASS_NONE) stack.popCtx() return render_result @@ -297,13 +258,16 @@ engine = get_template_engine(app, engine_name) + used_templating = False formatted_segments = {} for seg_name, seg in page.segments.items(): try: with app.env.stats.timerScope( engine.__class__.__name__ + '_segment'): - seg_text = engine.renderSegment( + seg_text, was_rendered = engine.renderSegment( page.content_spec, seg, page_data) + if was_rendered: + used_templating = True except TemplatingError as err: err.lineno += seg.line raise err @@ -319,8 +283,7 @@ content_abstract = seg_text[:offset] formatted_segments['content.abstract'] = content_abstract - pass_info = ctx.render_passes[PASS_FORMATTING] - res = RenderedSegments(formatted_segments, pass_info) + res = RenderedSegments(formatted_segments, used_templating) app.env.stats.stepCounter('PageRenderSegments') @@ -355,8 +318,7 @@ msg += "Looked for: %s" % ', '.join(full_names) raise Exception(msg) from ex - pass_info = cur_ctx.render_passes[PASS_RENDERING] - res = RenderedLayout(output, pass_info) + res = RenderedLayout(output) app.env.stats.stepCounter('PageRenderLayout')