1
0
Fork 0
forked from github/pelican
pelican-theme/pelican/readers.py

174 lines
5.1 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
try:
2011-05-10 07:55:30 +06:00
import docutils
import docutils.core
import docutils.io
from docutils.writers.html4css1 import HTMLTranslator
# import the directives to have pygments support
from pelican import rstdirectives # NOQA
except ImportError:
core = False
try:
from markdown import Markdown
except ImportError:
Markdown = False # NOQA
import re
from pelican.contents import Category, Tag, Author
from pelican.utils import get_date, open
2011-05-07 20:00:30 +01:00
_METADATA_PROCESSORS = {
'tags': lambda x, y: [Tag(tag, y) for tag in unicode(x).split(',')],
'date': lambda x, y: get_date(x),
'status': lambda x, y: unicode.strip(x),
'category': Category,
'author': Author,
}
class Reader(object):
enabled = True
extensions = None
2011-05-10 07:55:30 +06:00
def __init__(self, settings):
self.settings = settings
def process_metadata(self, name, value):
2012-03-12 01:33:30 +09:00
if name in _METADATA_PROCESSORS:
return _METADATA_PROCESSORS[name](value, self.settings)
return value
2011-05-10 07:55:30 +06:00
class _FieldBodyTranslator(HTMLTranslator):
def __init__(self, document):
HTMLTranslator.__init__(self, document)
self.compact_p = None
2011-05-10 07:55:30 +06:00
def astext(self):
return ''.join(self.body)
def visit_field_body(self, node):
pass
def depart_field_body(self, node):
pass
def render_node_to_html(document, node):
visitor = _FieldBodyTranslator(document)
node.walkabout(visitor)
return visitor.astext()
class RstReader(Reader):
2011-05-10 07:55:30 +06:00
enabled = bool(docutils)
extension = ['rst']
2011-05-10 07:55:30 +06:00
def _parse_metadata(self, document):
"""Return the dict containing document metadata"""
output = {}
for docinfo in document.traverse(docutils.nodes.docinfo):
for element in docinfo.children:
if element.tagname == 'field': # custom fields (e.g. summary)
name_elem, body_elem = element.children
name = name_elem.astext()
if name == 'summary':
value = render_node_to_html(document, body_elem)
else:
value = body_elem.astext()
else: # standard fields (e.g. address)
name = element.tagname
value = element.astext()
2012-03-12 01:33:30 +09:00
name = name.lower()
output[name] = self.process_metadata(name, value)
return output
2011-05-10 07:55:30 +06:00
def _get_publisher(self, filename):
extra_params = {'initial_header_level': '2'}
pub = docutils.core.Publisher(
destination_class=docutils.io.StringOutput)
2011-05-10 07:55:30 +06:00
pub.set_components('standalone', 'restructuredtext', 'html')
pub.process_programmatic_settings(None, extra_params, None)
pub.set_source(source_path=filename)
pub.publish()
return pub
def read(self, filename):
2011-05-10 07:55:30 +06:00
"""Parses restructured text"""
pub = self._get_publisher(filename)
parts = pub.writer.parts
content = parts.get('body')
metadata = self._parse_metadata(pub.document)
metadata.setdefault('title', parts.get('title'))
2011-05-07 20:00:30 +01:00
return content, metadata
2011-05-10 07:55:30 +06:00
class MarkdownReader(Reader):
enabled = bool(Markdown)
extension = ['md', 'markdown', 'mkd']
extensions = ['codehilite', 'extra']
def read(self, filename):
"""Parse content and metadata of markdown files"""
text = open(filename)
2011-08-11 22:42:20 +02:00
md = Markdown(extensions=set(self.extensions + ['meta']))
content = md.convert(text)
2011-05-10 07:55:30 +06:00
2011-05-07 20:00:30 +01:00
metadata = {}
for name, value in md.Meta.items():
name = name.lower()
metadata[name] = self.process_metadata(name, value[0])
2011-05-07 20:00:30 +01:00
return content, metadata
2011-02-14 19:10:01 +01:00
class HtmlReader(Reader):
extension = ['html', 'htm']
2011-02-14 19:10:01 +01:00
_re = re.compile('\<\!\-\-\#\s?[A-z0-9_-]*\s?\:s?[A-z0-9\s_-]*\s?\-\-\>')
def read(self, filename):
"""Parse content and metadata of (x)HTML files"""
with open(filename) as content:
metadata = {'title': 'unnamed'}
for i in self._re.findall(content):
key = i.split(':')[0][5:].strip()
value = i.split(':')[-1][:-3].strip()
name = key.lower()
metadata[name] = self.process_metadata(name, value)
2011-02-14 19:10:01 +01:00
return content, metadata
2011-02-14 19:10:01 +01:00
_EXTENSIONS = dict((cls.extension, cls) for cls in Reader.__subclasses__())
def read_file(filename, fmt=None, settings=None):
"""Return a reader object using the given format."""
if not fmt:
fmt = filename.split('.')[-1]
if fmt not in _EXTENSIONS:
raise TypeError('Pelican does not know how to parse %s' % filename)
reader = _EXTENSIONS[fmt](settings)
settings_key = '%s_EXTENSIONS' % fmt.upper()
if settings and settings_key in settings:
reader.extensions = settings[settings_key]
if not reader.enabled:
raise ValueError("Missing dependencies for %s" % fmt)
content, metadata = reader.read(filename)
# eventually filter the content with typogrify if asked so
if settings and settings['TYPOGRIFY']:
from typogrify import Typogrify
content = Typogrify.typogrify(content)
return content, metadata