comparison piecrust/data/base.py @ 3:f485ba500df3

Gigantic change to basically make PieCrust 2 vaguely functional. - Serving works, with debug window. - Baking works, multi-threading, with dependency handling. - Various things not implemented yet.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 10 Aug 2014 23:43:16 -0700
parents
children 474c9882decf
comparison
equal deleted inserted replaced
2:40fa08b261b9 3:f485ba500df3
1 import time
2 import logging
3 from piecrust.data.assetor import Assetor
4
5
6 logger = logging.getLogger(__name__)
7
8
9 class LazyPageConfigData(object):
10 """ An object that represents the configuration header of a page,
11 but also allows for additional data. It's meant to be exposed
12 to the templating system.
13 """
14 def __init__(self, page):
15 self._page = page
16 self._values = None
17 self._loaders = None
18
19 @property
20 def page(self):
21 return self._page
22
23 def __getitem__(self, name):
24 self._load()
25
26 if self._loaders:
27 loader = self._loaders.get(name)
28 if loader is not None:
29 try:
30 self._values[name] = loader(self, name)
31 except Exception as ex:
32 logger.error("Error while loading attribute '%s' for: %s"
33 % (name, self._page.path))
34 logger.exception(ex)
35 raise Exception("Internal Error: %s" % ex)
36
37 # We need to double-check `_loaders` here because
38 # the loader could have removed all loaders, which
39 # would set this back to `None`.
40 if self._loaders is not None:
41 del self._loaders[name]
42 if len(self._loaders) == 0:
43 self._loaders = None
44
45 return self._values[name]
46
47 def setValue(self, name, value):
48 self._values[name] = value
49
50 def mapLoader(self, attr_name, loader):
51 if loader is None:
52 if self._loaders is None or attr_name not in self._loaders:
53 return
54 del self._loaders[attr_name]
55 if len(self._loaders) == 0:
56 self._loaders = None
57 return
58
59 if self._loaders is None:
60 self._loaders = {}
61 if attr_name in self._loaders:
62 raise Exception("A loader has already been mapped for: %s" %
63 attr_name)
64 self._loaders[attr_name] = loader
65
66 def _load(self):
67 if self._values is not None:
68 return
69 self._values = dict(self._page.config.get())
70 try:
71 self._loadCustom()
72 except Exception as ex:
73 logger.error("Error while loading data for: %s" % self._page.path)
74 logger.exception(ex)
75 raise Exception("Internal Error: %s" % ex)
76
77 def _loadCustom(self):
78 pass
79
80
81 def build_uri(page):
82 route = page.app.getRoute(page.source.name, page.source_metadata)
83 if route is None:
84 raise Exception("Can't get route for page: %s" % page.path)
85 return route.getUri(page.source_metadata)
86
87
88 def load_rendered_segment(data, name):
89 from piecrust.rendering import PageRenderingContext, render_page_segments
90
91 uri = build_uri(data.page)
92 try:
93 ctx = PageRenderingContext(data.page, uri)
94 segs = render_page_segments(ctx)
95 except Exception as e:
96 logger.exception("Error rendering segments for '%s': %s" % (uri, e))
97 raise
98
99 for k, v in segs.iteritems():
100 data.mapLoader(k, None)
101 data.setValue(k, v)
102
103 if 'content.abstract' in segs:
104 data.setValue('content', segs['content.abstract'])
105 data.setValue('has_more', True)
106 if name == 'content':
107 return segs['content.abstract']
108
109 return segs[name]
110
111
112 class PaginationData(LazyPageConfigData):
113 def __init__(self, page):
114 super(PaginationData, self).__init__(page)
115
116 def _loadCustom(self):
117 page_url = build_uri(self.page)
118 self.setValue('url', page_url)
119 self.setValue('slug', page_url)
120 self.setValue('timestamp',
121 time.mktime(self.page.datetime.timetuple()))
122 date_format = self.page.app.config.get('site/date_format')
123 if date_format:
124 self.setValue('date', self.page.datetime.strftime(date_format))
125
126 assetor = Assetor(self.page, page_url)
127 self.setValue('assets', assetor)
128
129 segment_names = self.page.config.get('segments')
130 for name in segment_names:
131 self.mapLoader(name, load_rendered_segment)
132