Mercurial > piecrust2
view piecrust/data/pagedata.py @ 550:6f216c1ab6b1
bake: Add a flag to know which record entries got collapsed from last run.
This makes it possible to find entries for things that were actually baked
during the current run, as opposed to skipped because they were "clean".
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 04 Aug 2015 21:22:30 -0700 |
parents | 785dea918ad8 |
children | ab5c6a8ae90a |
line wrap: on
line source
import time import collections.abc class LazyPageConfigLoaderHasNoValue(Exception): """ An exception that can be returned when a loader for `LazyPageConfig` can't return any value. """ pass class LazyPageConfigData(collections.abc.Mapping): """ An object that represents the configuration header of a page, but also allows for additional data. It's meant to be exposed to the templating system. """ debug_render = [] debug_render_invoke = [] debug_render_dynamic = ['_debugRenderKeys'] debug_render_invoke_dynamic = ['_debugRenderKeys'] def __init__(self, page): self._page = page self._values = {} self._loaders = {} self._is_loaded = False def __getattr__(self, name): try: return self._getValue(name) except LazyPageConfigLoaderHasNoValue as ex: raise AttributeError("No such attribute: %s" % name) from ex def __getitem__(self, name): try: return self._getValue(name) except LazyPageConfigLoaderHasNoValue as ex: raise KeyError("No such key: %s" % name) from ex def __iter__(self): keys = set(self._page.config.keys()) keys |= set(self._values.keys()) keys |= set(self._loaders.keys()) keys.discard('*') return iter(keys) def __len__(self): return len(self._page.config) + len(self._values) + len(self._loaders) def _getValue(self, name): # First try the page configuration itself. try: return self._page.config[name] except KeyError: pass # Then try loaded values. self._ensureLoaded() try: return self._values[name] except KeyError: pass # Try a loader for a new value. loader = self._loaders.get(name) if loader is not None: try: self._values[name] = loader(self, name) except LazyPageConfigLoaderHasNoValue: raise except Exception as ex: raise Exception( "Error while loading attribute '%s' for: %s" % (name, self._page.rel_path)) from ex # Forget this loader now that it served its purpose. try: del self._loaders[name] except KeyError: pass return self._values[name] # Try the wildcard loader if it exists. loader = self._loaders.get('*') if loader is not None: try: self._values[name] = loader(self, name) except LazyPageConfigLoaderHasNoValue: raise except Exception as ex: raise Exception( "Error while loading attribute '%s' for: %s" % (name, self._page.rel_path)) from ex # We always keep the wildcard loader in the loaders list. return self._values[name] raise LazyPageConfigLoaderHasNoValue() def _setValue(self, name, value): self._values[name] = value def _unmapLoader(self, attr_name): try: del self._loaders[attr_name] except KeyError: pass def _mapLoader(self, attr_name, loader, override_existing=False): assert loader is not None if not override_existing and attr_name in self._loaders: raise Exception( "A loader has already been mapped for: %s" % attr_name) self._loaders[attr_name] = loader def _mapValue(self, attr_name, value, override_existing=False): loader = lambda _, __: value self._mapLoader(attr_name, loader, override_existing=override_existing) def _ensureLoaded(self): if self._is_loaded: return self._is_loaded = True try: self._load() except Exception as ex: raise Exception( "Error while loading data for: %s" % self._page.rel_path) from ex def _load(self): pass def _debugRenderKeys(self): self._ensureLoaded() keys = set(self._values.keys()) if self._loaders: keys |= set(self._loaders.keys()) keys.discard('*') return list(keys) class PageData(LazyPageConfigData): """ Template data for a page. """ def __init__(self, page, ctx): super(PageData, self).__init__(page) self._ctx = ctx def _load(self): page = self._page for k, v in page.source_metadata.items(): self._setValue(k, v) self._setValue('url', self._ctx.uri) 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))