Mercurial > piecrust2
diff piecrust/data/paginationdata.py @ 440:32c7c2d219d2
performance: Refactor how data is managed to reduce copying.
* Make use of `collections.abc.Mapping` to better identify things that are
supposed to look like dictionaries.
* Instead of handling "overlay" of data in a dict tree in each different data
object, make all objects `Mapping`s and handle merging at a higher level
with the new `MergedMapping` object.
* Since this new object is read-only, remove the need for deep-copying of
app and page configurations.
* Split data classes into separate modules.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 28 Jun 2015 08:22:39 -0700 |
parents | |
children | ab5c6a8ae90a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piecrust/data/paginationdata.py Sun Jun 28 08:22:39 2015 -0700 @@ -0,0 +1,88 @@ +import time +from piecrust.data.assetor import Assetor +from piecrust.data.pagedata import LazyPageConfigData +from piecrust.routing import create_route_metadata +from piecrust.uriutil import split_uri + + +class PaginationData(LazyPageConfigData): + def __init__(self, page): + super(PaginationData, self).__init__(page) + self._route = None + self._route_metadata = None + + def _get_uri(self): + page = self._page + if self._route is None: + # TODO: this is not quite correct, as we're missing parts of the + # route metadata if the current page is a taxonomy page. + route_metadata = create_route_metadata(page) + self._route = page.app.getRoute(page.source.name, route_metadata) + self._route_metadata = route_metadata + if self._route is None: + raise Exception("Can't get route for page: %s" % page.path) + return self._route.getUri(self._route_metadata) + + def _load(self): + page = self._page + page_url = self._get_uri() + _, slug = split_uri(page.app, page_url) + self._setValue('url', page_url) + self._setValue('slug', slug) + self._setValue( + 'timestamp', + time.mktime(page.datetime.timetuple())) + date_format = page.app.config.get('site/date_format') + if date_format: + self._setValue('date', page.datetime.strftime(date_format)) + self._setValue('mtime', page.path_mtime) + + assetor = Assetor(page, page_url) + self._setValue('assets', assetor) + + segment_names = page.config.get('segments') + for name in segment_names: + self._mapLoader(name, self._load_rendered_segment) + + def _load_rendered_segment(self, data, name): + do_render = True + eis = self._page.app.env.exec_info_stack + if eis is not None and eis.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 + + assert self is data + + if do_render: + uri = self._get_uri() + try: + from piecrust.rendering import ( + QualifiedPage, PageRenderingContext, + render_page_segments) + qp = QualifiedPage(self._page, self._route, + self._route_metadata) + ctx = PageRenderingContext(qp) + render_result = render_page_segments(ctx) + segs = render_result.segments + except Exception as e: + raise Exception( + "Error rendering segments for '%s'" % uri) from e + else: + segs = {} + for name in self._page.config.get('segments'): + segs[name] = "<unavailable: current page>" + + for k, v in segs.items(): + self._unmapLoader(k) + self._setValue(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'] + + return segs[name] +