Mercurial > wikked
view wikked/page.py @ 84:ca57fef14d04
Formatter/resolver changes:
- Formatting is done after resolving.
- Resolving includes passing text through the template engine.
- Using Jinja2 for templating now.
- Added unit tests.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 03 Apr 2013 23:30:23 -0700 |
parents | 65f83a9b42f1 |
children | ba440e5e4059 |
line wrap: on
line source
import os import os.path import re import datetime import unicodedata from formatter import PageFormatter, FormattingContext from resolver import PageResolver, CircularIncludeError class PageData(object): def __init__(self): self.path = None self.title = None self.raw_text = None self.formatted_text = None self.text = None self.local_meta = {} self.local_links = [] self.ext_meta = {} self.ext_links = [] self.has_extended_data = False class Page(object): """ A wiki page. """ def __init__(self, wiki, url): self.wiki = wiki self.url = url self._data = None @property def path(self): self._ensureData() return self._data.path @property def extension(self): self._ensureData() return self._data.extension @property def filename(self): self._ensureData() return self._data.filename @property def title(self): self._ensureData() return self._data.title @property def raw_text(self): self._ensureData() return self._data.raw_text @property def text(self): self._ensureExtendedData() return self._data.text @property def meta(self): self._ensureExtendedData() return self._data.ext_meta @property def links(self): self._ensureExtendedData() return self._data.ext_links def getIncomingLinks(self): return self.wiki.db.getLinksTo(self.url) def getHistory(self): return self.wiki.scm.getHistory(self.path) def getState(self): return self.wiki.scm.getState(self.path) def getRevision(self, rev): return self.wiki.scm.getRevision(self.path, rev) def getDiff(self, rev1, rev2): return self.wiki.scm.diff(self.path, rev1, rev2) def _getFormattedText(self): self._ensureData() return self._data.formatted_text def _getLocalMeta(self): self._ensureData() return self._data.local_meta def _getLocalLinks(self): self._ensureData() return self._data.local_links def _ensureData(self): if self._data is not None: return self._data = self._loadCachedData() if self._data is not None: return self._data = self._loadOriginalData() self._saveCachedData(self._data) def _loadCachedData(self): return None def _saveCachedData(self, meta): pass def _loadOriginalData(self): data = PageData() # Get info from the file-system. page_info = self.wiki.fs.getPage(self.url) data.path = page_info.path data.raw_text = page_info.content split = os.path.splitext(data.path) data.filename = split[0] data.extension = split[1].lstrip('.') # Format the page and get the meta properties. filename = os.path.basename(data.path) filename_split = os.path.splitext(filename) ctx = FormattingContext(self.url, slugify=Page.title_to_url) f = PageFormatter(self.wiki) data.formatted_text = f.formatText(ctx, data.raw_text) data.local_meta = ctx.meta data.local_links = ctx.out_links # Add some common meta. data.title = re.sub(r'\-', ' ', filename_split[0]) if 'title' in data.local_meta: data.title = data.local_meta['title'][0] return data def _ensureExtendedData(self): if self._data is not None and self._data.has_extended_data: return self._ensureData() try: r = PageResolver(self) out = r.run() self._data.text = out.text self._data.ext_meta = out.meta self._data.ext_links = out.out_links except CircularIncludeError as cie: template_path = os.path.join( os.path.dirname(__file__), 'templates', 'circular_include_error.html' ) with open(template_path, 'r') as f: env = jinja2.Environment() template = env.from_string(f.read()) self._data.text = template.render({ 'message': str(cie), 'url_trail': cie.url_trail }) @staticmethod def title_to_url(title): # Remove diacritics (accents, etc.) and replace them with ASCII # equivelent. ansi_title = ''.join((c for c in unicodedata.normalize('NFD', unicode(title)) if unicodedata.category(c) != 'Mn')) # Now replace spaces and punctuation with a hyphen. return re.sub(r'[^A-Za-z0-9_\.\-\(\)]+', '-', ansi_title.lower()) @staticmethod def url_to_title(url): def upperChar(m): return m.group(0).upper() return re.sub(r'^.|\s\S', upperChar, url.lower().replace('-', ' ')) @staticmethod def factory(wiki, url): return Page(wiki, url) class DatabasePage(Page): """ A page that can load its properties from a database. """ def __init__(self, wiki, url): Page.__init__(self, wiki, url) if getattr(wiki, 'db', None) is None: raise Exception("The wiki doesn't have a database.") self.auto_update = wiki.config.get('wiki', 'auto_update') def _loadCachedData(self): if self.wiki.db is None: return None db_page = self.wiki.db.getPage(self.url) if db_page is None: return None if self.auto_update: path_time = datetime.datetime.fromtimestamp( os.path.getmtime(db_page.path)) if path_time >= db_page.time: return None data = PageData() data.path = db_page.path split = os.path.splitext(data.path) data.filename = split[0] data.extension = split[1] data.title = db_page.title data.raw_text = db_page.raw_text data.formatted_text = db_page.formatted_text data.local_meta = db_page.meta data.local_links = db_page.links return data def _saveCachedData(self, meta): if self.wiki.db is not None: self.wiki.logger.debug( "Updated database cache for page '%s'." % self.url) self.wiki.db.update([self]) @staticmethod def factory(wiki, url): return DatabasePage(wiki, url)