mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
git merge upstream/master
This commit is contained in:
commit
bc2bc7a330
230 changed files with 7831 additions and 7255 deletions
|
|
@ -1,4 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals, print_function
|
||||
import six
|
||||
|
||||
import os
|
||||
import re
|
||||
try:
|
||||
import docutils
|
||||
import docutils.core
|
||||
|
|
@ -13,19 +18,24 @@ try:
|
|||
from markdown import Markdown
|
||||
except ImportError:
|
||||
Markdown = False # NOQA
|
||||
try:
|
||||
from asciidocapi import AsciiDocAPI
|
||||
asciidoc = True
|
||||
except ImportError:
|
||||
asciidoc = False
|
||||
import re
|
||||
|
||||
import cgi
|
||||
from HTMLParser import HTMLParser
|
||||
|
||||
from pelican.contents import Category, Tag, Author
|
||||
from pelican.utils import get_date, open
|
||||
from pelican.utils import get_date, pelican_open
|
||||
|
||||
|
||||
_METADATA_PROCESSORS = {
|
||||
'tags': lambda x, y: [Tag(tag, y) for tag in unicode(x).split(',')],
|
||||
'tags': lambda x, y: [Tag(tag, y) for tag in x.split(',')],
|
||||
'date': lambda x, y: get_date(x),
|
||||
'status': lambda x, y: unicode.strip(x),
|
||||
'status': lambda x, y: x.strip(),
|
||||
'category': Category,
|
||||
'author': Author,
|
||||
}
|
||||
|
|
@ -66,6 +76,18 @@ def render_node_to_html(document, node):
|
|||
return visitor.astext()
|
||||
|
||||
|
||||
class PelicanHTMLTranslator(HTMLTranslator):
|
||||
|
||||
def visit_abbreviation(self, node):
|
||||
attrs = {}
|
||||
if node.hasattr('explanation'):
|
||||
attrs['title'] = node['explanation']
|
||||
self.body.append(self.starttag(node, 'abbr', '', **attrs))
|
||||
|
||||
def depart_abbreviation(self, node):
|
||||
self.body.append('</abbr>')
|
||||
|
||||
|
||||
class RstReader(Reader):
|
||||
enabled = bool(docutils)
|
||||
file_extensions = ['rst']
|
||||
|
|
@ -90,19 +112,20 @@ class RstReader(Reader):
|
|||
output[name] = self.process_metadata(name, value)
|
||||
return output
|
||||
|
||||
def _get_publisher(self, filename):
|
||||
def _get_publisher(self, source_path):
|
||||
extra_params = {'initial_header_level': '2'}
|
||||
pub = docutils.core.Publisher(
|
||||
destination_class=docutils.io.StringOutput)
|
||||
destination_class=docutils.io.StringOutput)
|
||||
pub.set_components('standalone', 'restructuredtext', 'html')
|
||||
pub.writer.translator_class = PelicanHTMLTranslator
|
||||
pub.process_programmatic_settings(None, extra_params, None)
|
||||
pub.set_source(source_path=filename)
|
||||
pub.set_source(source_path=source_path)
|
||||
pub.publish()
|
||||
return pub
|
||||
|
||||
def read(self, filename):
|
||||
def read(self, source_path):
|
||||
"""Parses restructured text"""
|
||||
pub = self._get_publisher(filename)
|
||||
pub = self._get_publisher(source_path)
|
||||
parts = pub.writer.parts
|
||||
content = parts.get('body')
|
||||
|
||||
|
|
@ -117,16 +140,28 @@ class MarkdownReader(Reader):
|
|||
file_extensions = ['md', 'markdown', 'mkd']
|
||||
extensions = ['codehilite', 'extra']
|
||||
|
||||
def read(self, filename):
|
||||
def _parse_metadata(self, meta):
|
||||
"""Return the dict containing document metadata"""
|
||||
md = Markdown(extensions=set(self.extensions + ['meta']))
|
||||
output = {}
|
||||
for name, value in meta.items():
|
||||
name = name.lower()
|
||||
if name == "summary":
|
||||
summary_values = "\n".join(str(item) for item in value)
|
||||
summary = md.convert(summary_values)
|
||||
output[name] = self.process_metadata(name, summary)
|
||||
else:
|
||||
output[name] = self.process_metadata(name, value[0])
|
||||
return output
|
||||
|
||||
def read(self, source_path):
|
||||
"""Parse content and metadata of markdown files"""
|
||||
with open(filename) as text:
|
||||
|
||||
with pelican_open(source_path) as text:
|
||||
md = Markdown(extensions=set(self.extensions + ['meta']))
|
||||
content = md.convert(text)
|
||||
|
||||
metadata = {}
|
||||
for name, value in md.Meta.items():
|
||||
name = name.lower()
|
||||
metadata[name] = self.process_metadata(name, value[0])
|
||||
metadata = self._parse_metadata(md.Meta)
|
||||
return content, metadata
|
||||
|
||||
class HTMLReader(Reader):
|
||||
|
|
@ -223,7 +258,7 @@ class HTMLReader(Reader):
|
|||
|
||||
def read(self, filename):
|
||||
"""Parse content and metadata of markdown files"""
|
||||
with open(filename) as content:
|
||||
with pelican_open(filename) as content:
|
||||
parser = self._HTMLParser(self.settings)
|
||||
parser.feed(content)
|
||||
parser.close()
|
||||
|
|
@ -233,6 +268,37 @@ class HTMLReader(Reader):
|
|||
metadata[k] = self.process_metadata(k, parser.metadata[k])
|
||||
return parser.body, metadata
|
||||
|
||||
class AsciiDocReader(Reader):
|
||||
enabled = bool(asciidoc)
|
||||
file_extensions = ['asc']
|
||||
default_options = ["--no-header-footer", "-a newline=\\n"]
|
||||
|
||||
def read(self, source_path):
|
||||
"""Parse content and metadata of asciidoc files"""
|
||||
from cStringIO import StringIO
|
||||
text = StringIO(pelican_open(source_path))
|
||||
content = StringIO()
|
||||
ad = AsciiDocAPI()
|
||||
|
||||
options = self.settings.get('ASCIIDOC_OPTIONS', [])
|
||||
if isinstance(options, (str, unicode)):
|
||||
options = [m.strip() for m in options.split(',')]
|
||||
options = self.default_options + options
|
||||
for o in options:
|
||||
ad.options(*o.split())
|
||||
|
||||
ad.execute(text, content, backend="html4")
|
||||
content = content.getvalue()
|
||||
|
||||
metadata = {}
|
||||
for name, value in ad.asciidoc.document.attributes.items():
|
||||
name = name.lower()
|
||||
metadata[name] = self.process_metadata(name, value)
|
||||
if 'doctitle' in metadata:
|
||||
metadata['title'] = metadata['doctitle']
|
||||
return content, metadata
|
||||
|
||||
|
||||
_EXTENSIONS = {}
|
||||
|
||||
for cls in Reader.__subclasses__():
|
||||
|
|
@ -240,13 +306,14 @@ for cls in Reader.__subclasses__():
|
|||
_EXTENSIONS[ext] = cls
|
||||
|
||||
|
||||
def read_file(filename, fmt=None, settings=None):
|
||||
def read_file(path, fmt=None, settings=None):
|
||||
"""Return a reader object using the given format."""
|
||||
base, ext = os.path.splitext(os.path.basename(path))
|
||||
if not fmt:
|
||||
fmt = filename.split('.')[-1]
|
||||
fmt = ext[1:]
|
||||
|
||||
if fmt not in _EXTENSIONS:
|
||||
raise TypeError('Pelican does not know how to parse %s' % filename)
|
||||
raise TypeError('Pelican does not know how to parse {}'.format(path))
|
||||
|
||||
reader = _EXTENSIONS[fmt](settings)
|
||||
settings_key = '%s_EXTENSIONS' % fmt.upper()
|
||||
|
|
@ -257,12 +324,22 @@ def read_file(filename, fmt=None, settings=None):
|
|||
if not reader.enabled:
|
||||
raise ValueError("Missing dependencies for %s" % fmt)
|
||||
|
||||
content, metadata = reader.read(filename)
|
||||
content, metadata = reader.read(path)
|
||||
|
||||
# eventually filter the content with typogrify if asked so
|
||||
if settings and settings['TYPOGRIFY']:
|
||||
from typogrify import Typogrify
|
||||
content = Typogrify.typogrify(content)
|
||||
metadata['title'] = Typogrify.typogrify(metadata['title'])
|
||||
if settings and settings.get('TYPOGRIFY'):
|
||||
from typogrify.filters import typogrify
|
||||
content = typogrify(content)
|
||||
metadata['title'] = typogrify(metadata['title'])
|
||||
|
||||
file_metadata = settings and settings.get('FILENAME_METADATA')
|
||||
if file_metadata:
|
||||
match = re.match(file_metadata, base)
|
||||
if match:
|
||||
# .items() for py3k compat.
|
||||
for k, v in match.groupdict().items():
|
||||
if k not in metadata:
|
||||
k = k.lower() # metadata must be lowercase
|
||||
metadata[k] = reader.process_metadata(k, v)
|
||||
|
||||
return content, metadata
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue