Mercurial > piecrust2
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 |