comparison 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
comparison
equal deleted inserted replaced
439:c0700c6d9545 440:32c7c2d219d2
1 import time
2 from piecrust.data.assetor import Assetor
3 from piecrust.data.pagedata import LazyPageConfigData
4 from piecrust.routing import create_route_metadata
5 from piecrust.uriutil import split_uri
6
7
8 class PaginationData(LazyPageConfigData):
9 def __init__(self, page):
10 super(PaginationData, self).__init__(page)
11 self._route = None
12 self._route_metadata = None
13
14 def _get_uri(self):
15 page = self._page
16 if self._route is None:
17 # TODO: this is not quite correct, as we're missing parts of the
18 # route metadata if the current page is a taxonomy page.
19 route_metadata = create_route_metadata(page)
20 self._route = page.app.getRoute(page.source.name, route_metadata)
21 self._route_metadata = route_metadata
22 if self._route is None:
23 raise Exception("Can't get route for page: %s" % page.path)
24 return self._route.getUri(self._route_metadata)
25
26 def _load(self):
27 page = self._page
28 page_url = self._get_uri()
29 _, slug = split_uri(page.app, page_url)
30 self._setValue('url', page_url)
31 self._setValue('slug', slug)
32 self._setValue(
33 'timestamp',
34 time.mktime(page.datetime.timetuple()))
35 date_format = page.app.config.get('site/date_format')
36 if date_format:
37 self._setValue('date', page.datetime.strftime(date_format))
38 self._setValue('mtime', page.path_mtime)
39
40 assetor = Assetor(page, page_url)
41 self._setValue('assets', assetor)
42
43 segment_names = page.config.get('segments')
44 for name in segment_names:
45 self._mapLoader(name, self._load_rendered_segment)
46
47 def _load_rendered_segment(self, data, name):
48 do_render = True
49 eis = self._page.app.env.exec_info_stack
50 if eis is not None and eis.hasPage(self._page):
51 # This is the pagination data for the page that is currently
52 # being rendered! Inception! But this is possible... so just
53 # prevent infinite recursion.
54 do_render = False
55
56 assert self is data
57
58 if do_render:
59 uri = self._get_uri()
60 try:
61 from piecrust.rendering import (
62 QualifiedPage, PageRenderingContext,
63 render_page_segments)
64 qp = QualifiedPage(self._page, self._route,
65 self._route_metadata)
66 ctx = PageRenderingContext(qp)
67 render_result = render_page_segments(ctx)
68 segs = render_result.segments
69 except Exception as e:
70 raise Exception(
71 "Error rendering segments for '%s'" % uri) from e
72 else:
73 segs = {}
74 for name in self._page.config.get('segments'):
75 segs[name] = "<unavailable: current page>"
76
77 for k, v in segs.items():
78 self._unmapLoader(k)
79 self._setValue(k, v)
80
81 if 'content.abstract' in segs:
82 self._setValue('content', segs['content.abstract'])
83 self._setValue('has_more', True)
84 if name == 'content':
85 return segs['content.abstract']
86
87 return segs[name]
88