def redirects(self): dct = NestedProperties() alist = [1, 2, 3] dct['foo'] = alist dct.redirect('foo', 'baz') assert 'foo' in dct assert 'baz' in dct assert dct['baz'] == alist
def test_redirects(self): dct = NestedProperties() alist = [1, 2, 3] dct['foo'] = alist dct.redirect('foo', 'baz') assert 'foo' in dct assert 'baz' in dct assert dct['baz'] == alist
class Reader(object): __metaclass__ = abc.ABCMeta def __init__(self, conf, meta): self.props = NestedProperties((k, v) for k, v in conf.iteritems() if k in ['author', 'lang', 'encoding', 'email', 'date_format', 'entry_permalink', 'page_permalink']) self.props.update(meta) self.type = meta.get('type', 'entry') # redirect singular -> plural for key, to in {'tag': 'tags', 'filter': 'filters'}.iteritems(): if key in self.props: self.props.redirect(key, to) self.filters = self.props.get('filters', []) @abc.abstractproperty def md5(self): return @abc.abstractproperty def source(self): return @abc.abstractproperty def has_changed(self): return @abc.abstractproperty def lastmodified(self): return def getfilters(self): return self._filters def setfilters(self, filters): if isinstance(filters, basestring): filters = [filters] self._filters = FilterTree(filters) filters = property(getfilters, setfilters) def gettype(self): """="Type of this entry. Can be either ``'entry'`` or ``'page'``""" return self._type def settype(self, value): if value not in ('entry', 'page'): raise ValueError("item type must be 'entry' or 'page'") self._type = value type = property(gettype, settype, doc=gettype.__doc__) def hasproperty(self, prop): """Test whether BaseEntry has prop in `self.props`.""" return prop in self.props @property def date(self): return datetime.now() def __iter__(self): for key in self.props: yield key for key in (attr for attr in dir(self) if not attr.startswith('_')): yield key def __contains__(self, other): return other in self.props or other in self.__dict__ def __getattr__(self, attr): try: return self.props[attr] except KeyError: raise AttributeError(attr) __getitem__ = lambda self, attr: getattr(self, attr)
class Reader(object): __metaclass__ = abc.ABCMeta def __init__(self, conf, meta): self.props = NestedProperties( (k, v) for k, v in conf.iteritems() if k in [ 'author', 'lang', 'encoding', 'email', 'date_format', 'entry_permalink', 'page_permalink' ]) self.props.update(meta) self.type = meta.get('type', 'entry') # redirect singular -> plural for key, to in {'tag': 'tags', 'filter': 'filters'}.iteritems(): if key in self.props: self.props.redirect(key, to) self.filters = self.props.get('filters', []) @abc.abstractproperty def md5(self): return @abc.abstractproperty def source(self): return @abc.abstractproperty def has_changed(self): return @abc.abstractproperty def lastmodified(self): return def getfilters(self): return self._filters def setfilters(self, filters): if isinstance(filters, basestring): filters = [filters] self._filters = FilterTree(filters) filters = property(getfilters, setfilters) def gettype(self): """="Type of this entry. Can be either ``'entry'`` or ``'page'``""" return self._type def settype(self, value): if value not in ('entry', 'page'): raise ValueError("item type must be 'entry' or 'page'") self._type = value type = property(gettype, settype, doc=gettype.__doc__) def hasproperty(self, prop): """Test whether BaseEntry has prop in `self.props`.""" return prop in self.props @property def date(self): return datetime.now() def __iter__(self): for key in self.props: yield key for key in (attr for attr in dir(self) if not attr.startswith('_')): yield key def __contains__(self, other): return other in self.props or other in self.__dict__ def __getattr__(self, attr): try: return self.props[attr] except KeyError: raise AttributeError(attr) __getitem__ = lambda self, attr: getattr(self, attr)
class FileEntry(BaseEntry): def __init__(self, path, conf): self.filename = path self.mtime = os.path.getmtime(path) self.props = NestedProperties((k, v) for k, v in conf.iteritems() if k in ['author', 'lang', 'encoding', 'email', 'date_format', 'entry_permalink', 'page_permalink']) native = conf.get('metastyle', '').lower() == 'native' with io.open(path, 'r', encoding=conf['encoding'], errors='replace') as fp: if native and path.endswith(('.md', '.mkdown')): i, meta = markdownstyle(fp) elif native and path.endswith(('.rst', '.rest')): i, meta = reststyle(fp) else: i, meta = yamlstyle(fp) meta['title'] = unicode(meta['title']) # YAML can convert 42 to an int self.offset = i self.type = meta.get('type', 'entry') self.props.update(meta) # redirect singular -> plural for key, to in {'tag': 'tags', 'filter': 'filters'}.iteritems(): if key in self.props: self.props.redirect(key, to) self.filters = self.props.get('filters', []) def __repr__(self): return "<FileEntry f'%s'>" % self.filename @cached_property def date(self): """parse date value and return :class:`datetime.datetime` object, fallback to modification timestamp of the file if unset. You can set a ``DATE_FORMAT`` in your :doc:`../conf.py` otherwise Acrylamid tries several format strings and throws an exception if no pattern works. As shortcut you can access ``date.day``, ``date.month``, ``date.year`` via ``entry.day``, ``entry.month`` and ``entry.year``.""" # alternate formats from pelican.utils, thank you! # https://github.com/ametaireau/pelican/blob/master/pelican/utils.py formats = ['%Y-%m-%d %H:%M', '%Y/%m/%d %H:%M', '%Y-%m-%d', '%Y/%m/%d', '%d-%m-%Y', '%Y-%d-%m', # Weird ones '%d/%m/%Y', '%d.%m.%Y', '%d.%m.%Y %H:%M', '%Y-%m-%d %H:%M:%S'] if 'date' not in self.props: if self.type == 'entry': log.warn("using mtime from %r" % self.filename) return Date.fromtimestamp(self.mtime) string = re.sub(' +', ' ', self.props['date']) formats.insert(0, self.props['date_format']) for date_format in formats: try: return Date.strptime(string, date_format) except ValueError: pass else: raise AcrylamidException("%r is not a valid date" % string) @property def extension(self): """Filename's extension without leading dot""" return os.path.splitext(self.filename)[1][1:] @property def source(self): """Returns the actual, unmodified content.""" with io.open(self.filename, 'r', encoding=self.props['encoding'], errors='replace') as f: return u''.join(f.readlines()[self.offset:]).strip() @cached_property def md5(self): return md5(self.filename, self.title, self.date) @property def content(self): # previous value res = self.source # growing dependencies of the filter chain deps = [] for fxs in self.filters.iter(context=self.context): # extend dependencies deps.extend(fxs) try: for f in fxs: res = f.transform(res, self, *f.args) except (IndexError, AttributeError): # jinja2 will ignore these Exceptions, better to catch them before traceback.print_exc(file=sys.stdout) return res @property def has_changed(self): return True @has_changed.setter def has_changed(self, value): self._has_changed = value