mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
575947c5d5
37 changed files with 797 additions and 240 deletions
|
|
@ -48,7 +48,7 @@ Markdown library as well::
|
|||
|
||||
$ pip install Markdown
|
||||
|
||||
If you want to use AsciiDoc you need to install it from `source
|
||||
If you want to use AsciiDoc_ you need to install it from `source
|
||||
<http://www.methods.co.nz/asciidoc/INSTALL.html>`_ or use your operating
|
||||
system's package manager.
|
||||
|
||||
|
|
@ -323,6 +323,9 @@ pattern::
|
|||
|
||||
This is the content of my super blog post.
|
||||
|
||||
Conventions for AsciiDoc_ posts, which should have an ``.asc`` extension, can
|
||||
be found on the AsciiDoc_ site.
|
||||
|
||||
Pelican can also process HTML files ending in ``.html`` and ``.htm``. Pelican
|
||||
interprets the HTML in a very straightforward manner, reading metadata from
|
||||
``meta`` tags, the title from the ``title`` tag, and the body out from the
|
||||
|
|
@ -551,3 +554,4 @@ listed on the index page nor on any category page.
|
|||
.. _virtualenv: http://www.virtualenv.org/
|
||||
.. _W3C ISO 8601: http://www.w3.org/TR/NOTE-datetime
|
||||
.. _Fabric: http://fabfile.org/
|
||||
.. _AsciiDoc: http://www.methods.co.nz/asciidoc/
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ The logic is separated into different classes and concepts:
|
|||
then passed to the generators.
|
||||
|
||||
* **Readers** are used to read from various formats (AsciiDoc, HTML, Markdown and
|
||||
reStructuredText for now, but the system is extensible). Given a file, they
|
||||
reStructuredText for now, but the system is extensible). Given a file, they
|
||||
return metadata (author, tags, category, etc.) and content (HTML-formatted).
|
||||
|
||||
* **Generators** generate the different outputs. For instance, Pelican comes with
|
||||
|
|
@ -44,7 +44,7 @@ method that returns HTML content and some metadata.
|
|||
|
||||
Take a look at the Markdown reader::
|
||||
|
||||
class MarkdownReader(Reader):
|
||||
class MarkdownReader(BaseReader):
|
||||
enabled = bool(Markdown)
|
||||
|
||||
def read(self, source_path):
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ finalized pelican object invoked after al
|
|||
- minifying js/css assets.
|
||||
- notify/ping search engines with an updated sitemap.
|
||||
generator_init generator invoked in the Generator.__init__
|
||||
readers_init readers invoked in the Readers.__init__
|
||||
article_generate_context article_generator, metadata
|
||||
article_generate_preread article_generator invoked before a article is read in ArticlesGenerator.generate_context;
|
||||
use if code needs to do something before every article is parsed
|
||||
|
|
@ -144,13 +145,13 @@ write and don't slow down pelican itself when they're not active.
|
|||
No more talking, here is the example::
|
||||
|
||||
from pelican import signals
|
||||
from pelican.readers import EXTENSIONS, Reader
|
||||
from pelican.readers import BaseReader
|
||||
|
||||
# Create a new reader class, inheriting from the pelican.reader.Reader
|
||||
class NewReader(Reader):
|
||||
# Create a new reader class, inheriting from the pelican.reader.BaseReader
|
||||
class NewReader(BaseReader):
|
||||
enabled = True # Yeah, you probably want that :-)
|
||||
|
||||
# The list of extensions you want this reader to match with.
|
||||
# The list of file extensions you want this reader to match with.
|
||||
# In the case multiple readers use the same extensions, the latest will
|
||||
# win (so the one you're defining here, most probably).
|
||||
file_extensions = ['yeah']
|
||||
|
|
@ -168,12 +169,12 @@ No more talking, here is the example::
|
|||
|
||||
return "Some content", parsed
|
||||
|
||||
def add_reader(arg):
|
||||
EXTENSIONS['yeah'] = NewReader
|
||||
def add_reader(readers):
|
||||
readers.reader_classes['yeah'] = NewReader
|
||||
|
||||
# this is how pelican works.
|
||||
def register():
|
||||
signals.initialized.connect(add_reader)
|
||||
signals.readers_init.connect(add_reader)
|
||||
|
||||
|
||||
Adding a new generator
|
||||
|
|
|
|||
|
|
@ -84,9 +84,10 @@ Setting name (default value) What doe
|
|||
here or a single string representing one locale.
|
||||
When providing a list, all the locales will be tried
|
||||
until one works.
|
||||
`MARKUP` (``('rst', 'md')``) A list of available markup languages you want
|
||||
to use. For the moment, the only available values
|
||||
are `rst`, `md`, `markdown`, `mkd`, `mdown`, `html`, and `htm`.
|
||||
`READERS` (``{}``) A dict of file extensions / Reader classes to overwrite or
|
||||
add file readers. for instance, to avoid processing .html files:
|
||||
``READERS = {'html': None}``. Or to add a custom reader for the
|
||||
`foo` extension: ``READERS = {'foo': FooReader}``
|
||||
`IGNORE_FILES` (``['.#*']``) A list of file globbing patterns to match against the
|
||||
source files to be ignored by the processor. For example,
|
||||
the default ``['.#*']`` will ignore emacs lock files.
|
||||
|
|
@ -244,7 +245,7 @@ Setting name (default value) What does it do?
|
|||
`CATEGORY_SAVE_AS` (``'category/{slug}.html'``) The location to save a category.
|
||||
`TAG_URL` (``'tag/{slug}.html'``) The URL to use for a tag.
|
||||
`TAG_SAVE_AS` (``'tag/{slug}.html'``) The location to save the tag page.
|
||||
`TAGS_URL` (``'tag/{slug}.html'``) The URL to use for the tag list.
|
||||
`TAGS_URL` (``'tags.html'``) The URL to use for the tag list.
|
||||
`TAGS_SAVE_AS` (``'tags.html'``) The location to save the tag list.
|
||||
`AUTHOR_URL` (``'author/{slug}.html'``) The URL to use for an author.
|
||||
`AUTHOR_SAVE_AS` (``'author/{slug}.html'``) The location to save an author.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
|||
StaticGenerator, SourceFileGenerator,
|
||||
TemplatePagesGenerator)
|
||||
from pelican.log import init
|
||||
from pelican.readers import Readers
|
||||
from pelican.settings import read_settings
|
||||
from pelican.utils import clean_output_dir, folder_watcher, file_watcher
|
||||
from pelican.writers import Writer
|
||||
|
|
@ -46,7 +47,6 @@ class Pelican(object):
|
|||
self.path = settings['PATH']
|
||||
self.theme = settings['THEME']
|
||||
self.output_path = settings['OUTPUT_PATH']
|
||||
self.markup = settings['MARKUP']
|
||||
self.ignore_files = settings['IGNORE_FILES']
|
||||
self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY']
|
||||
self.output_retention = settings['OUTPUT_RETENTION']
|
||||
|
|
@ -164,7 +164,6 @@ class Pelican(object):
|
|||
path=self.path,
|
||||
theme=self.theme,
|
||||
output_path=self.output_path,
|
||||
markup=self.markup,
|
||||
) for cls in self.get_generator_classes()
|
||||
]
|
||||
|
||||
|
|
@ -236,10 +235,6 @@ def parse_arguments():
|
|||
help='Where to output the generated files. If not specified, a '
|
||||
'directory will be created, named "output" in the current path.')
|
||||
|
||||
parser.add_argument('-m', '--markup', dest='markup',
|
||||
help='The list of markup language to use (rst or md). Please indicate '
|
||||
'them separated by commas.')
|
||||
|
||||
parser.add_argument('-s', '--settings', dest='settings',
|
||||
help='The settings of the application, this is automatically set to '
|
||||
'{0} if a file exists with this name.'.format(DEFAULT_CONFIG_NAME))
|
||||
|
|
@ -279,8 +274,6 @@ def get_config(args):
|
|||
if args.output:
|
||||
config['OUTPUT_PATH'] = \
|
||||
os.path.abspath(os.path.expanduser(args.output))
|
||||
if args.markup:
|
||||
config['MARKUP'] = [a.strip().lower() for a in args.markup.split(',')]
|
||||
if args.theme:
|
||||
abstheme = os.path.abspath(os.path.expanduser(args.theme))
|
||||
config['THEME'] = abstheme if os.path.exists(abstheme) else args.theme
|
||||
|
|
@ -296,8 +289,6 @@ def get_config(args):
|
|||
for key in config:
|
||||
if key in ('PATH', 'OUTPUT_PATH', 'THEME'):
|
||||
config[key] = config[key].decode(enc)
|
||||
if key == "MARKUP":
|
||||
config[key] = [a.decode(enc) for a in config[key]]
|
||||
return config
|
||||
|
||||
|
||||
|
|
@ -315,16 +306,17 @@ def get_instance(args):
|
|||
module = __import__(module)
|
||||
cls = getattr(module, cls_name)
|
||||
|
||||
return cls(settings)
|
||||
return cls(settings), settings
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_arguments()
|
||||
init(args.verbosity)
|
||||
pelican = get_instance(args)
|
||||
pelican, settings = get_instance(args)
|
||||
readers = Readers(settings)
|
||||
|
||||
watchers = {'content': folder_watcher(pelican.path,
|
||||
pelican.markup,
|
||||
readers.extensions,
|
||||
pelican.ignore_files),
|
||||
'theme': folder_watcher(pelican.theme,
|
||||
[''],
|
||||
|
|
@ -333,8 +325,8 @@ def main():
|
|||
|
||||
try:
|
||||
if args.autoreload:
|
||||
print(' --- AutoReload Mode: Monitoring `content`, `theme` and `settings`'
|
||||
' for changes. ---')
|
||||
print(' --- AutoReload Mode: Monitoring `content`, `theme` and'
|
||||
' `settings` for changes. ---')
|
||||
|
||||
while True:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -13,16 +13,13 @@ from functools import partial
|
|||
from itertools import chain, groupby
|
||||
from operator import attrgetter, itemgetter
|
||||
|
||||
from jinja2 import (
|
||||
Environment, FileSystemLoader, PrefixLoader, ChoiceLoader, BaseLoader,
|
||||
TemplateNotFound
|
||||
)
|
||||
from jinja2 import (Environment, FileSystemLoader, PrefixLoader, ChoiceLoader,
|
||||
BaseLoader, TemplateNotFound)
|
||||
|
||||
from pelican.contents import Article, Page, Static, is_valid_content
|
||||
from pelican.readers import read_file
|
||||
from pelican.readers import Readers
|
||||
from pelican.utils import copy, process_translations, mkdir_p, DateFormatter
|
||||
from pelican import signals
|
||||
import pelican.utils
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -31,23 +28,23 @@ logger = logging.getLogger(__name__)
|
|||
class Generator(object):
|
||||
"""Baseclass generator"""
|
||||
|
||||
def __init__(self, context, settings, path, theme, output_path, markup,
|
||||
**kwargs):
|
||||
def __init__(self, context, settings, path, theme, output_path, **kwargs):
|
||||
self.context = context
|
||||
self.settings = settings
|
||||
self.path = path
|
||||
self.theme = theme
|
||||
self.output_path = output_path
|
||||
self.markup = markup
|
||||
|
||||
for arg, value in kwargs.items():
|
||||
setattr(self, arg, value)
|
||||
|
||||
self.readers = Readers(self.settings)
|
||||
|
||||
# templates cache
|
||||
self._templates = {}
|
||||
self._templates_path = []
|
||||
self._templates_path.append(os.path.expanduser(
|
||||
os.path.join(self.theme, 'templates')))
|
||||
os.path.join(self.theme, 'templates')))
|
||||
self._templates_path += self.settings['EXTRA_TEMPLATES_PATHS']
|
||||
|
||||
theme_path = os.path.dirname(os.path.abspath(__file__))
|
||||
|
|
@ -85,9 +82,8 @@ class Generator(object):
|
|||
try:
|
||||
self._templates[name] = self.env.get_template(name + '.html')
|
||||
except TemplateNotFound:
|
||||
raise Exception(
|
||||
('[templates] unable to load %s.html from %s'
|
||||
% (name, self._templates_path)))
|
||||
raise Exception('[templates] unable to load %s.html from %s'
|
||||
% (name, self._templates_path))
|
||||
return self._templates[name]
|
||||
|
||||
def _include_path(self, path, extensions=None):
|
||||
|
|
@ -98,7 +94,7 @@ class Generator(object):
|
|||
extensions are allowed)
|
||||
"""
|
||||
if extensions is None:
|
||||
extensions = tuple(self.markup)
|
||||
extensions = tuple(self.readers.extensions)
|
||||
basename = os.path.basename(path)
|
||||
if extensions is False or basename.endswith(extensions):
|
||||
return True
|
||||
|
|
@ -388,9 +384,9 @@ class ArticlesGenerator(Generator):
|
|||
self.settings['ARTICLE_DIR'],
|
||||
exclude=self.settings['ARTICLE_EXCLUDES']):
|
||||
try:
|
||||
article = read_file(
|
||||
article = self.readers.read_file(
|
||||
base_path=self.path, path=f, content_class=Article,
|
||||
settings=self.settings, context=self.context,
|
||||
context=self.context,
|
||||
preread_signal=signals.article_generator_preread,
|
||||
preread_sender=self,
|
||||
context_signal=signals.article_generator_context,
|
||||
|
|
@ -496,9 +492,9 @@ class PagesGenerator(Generator):
|
|||
self.settings['PAGE_DIR'],
|
||||
exclude=self.settings['PAGE_EXCLUDES']):
|
||||
try:
|
||||
page = read_file(
|
||||
page = self.readers.read_file(
|
||||
base_path=self.path, path=f, content_class=Page,
|
||||
settings=self.settings, context=self.context,
|
||||
context=self.context,
|
||||
preread_signal=signals.page_generator_preread,
|
||||
preread_sender=self,
|
||||
context_signal=signals.page_generator_context,
|
||||
|
|
@ -557,10 +553,9 @@ class StaticGenerator(Generator):
|
|||
for static_path in self.settings['STATIC_PATHS']:
|
||||
for f in self.get_files(
|
||||
static_path, extensions=False):
|
||||
static = read_file(
|
||||
static = self.readers.read_file(
|
||||
base_path=self.path, path=f, content_class=Static,
|
||||
fmt='static',
|
||||
settings=self.settings, context=self.context,
|
||||
fmt='static', context=self.context,
|
||||
preread_signal=signals.static_generator_preread,
|
||||
preread_sender=self,
|
||||
context_signal=signals.static_generator_context,
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ try:
|
|||
except ImportError:
|
||||
from HTMLParser import HTMLParser
|
||||
|
||||
from pelican import signals
|
||||
from pelican.contents import Page, Category, Tag, Author
|
||||
from pelican.utils import get_date, pelican_open
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
METADATA_PROCESSORS = {
|
||||
'tags': lambda x, y: [Tag(tag, y) for tag in x.split(',')],
|
||||
|
|
@ -50,7 +50,19 @@ METADATA_PROCESSORS = {
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Reader(object):
|
||||
class BaseReader(object):
|
||||
"""Base class to read files.
|
||||
|
||||
This class is used to process static files, and it can be inherited for
|
||||
other types of file. A Reader class must have the following attributes:
|
||||
|
||||
- enabled: (boolean) tell if the Reader class is enabled. It
|
||||
generally depends on the import of some dependency.
|
||||
- file_extensions: a list of file extensions that the Reader will process.
|
||||
- extensions: a list of extensions to use in the reader (typical use is
|
||||
Markdown).
|
||||
|
||||
"""
|
||||
enabled = True
|
||||
file_extensions = ['static']
|
||||
extensions = None
|
||||
|
|
@ -110,7 +122,9 @@ class PelicanHTMLTranslator(HTMLTranslator):
|
|||
return HTMLTranslator.visit_image(self, node)
|
||||
|
||||
|
||||
class RstReader(Reader):
|
||||
class RstReader(BaseReader):
|
||||
"""Reader for reStructuredText files"""
|
||||
|
||||
enabled = bool(docutils)
|
||||
file_extensions = ['rst']
|
||||
|
||||
|
|
@ -166,7 +180,9 @@ class RstReader(Reader):
|
|||
return content, metadata
|
||||
|
||||
|
||||
class MarkdownReader(Reader):
|
||||
class MarkdownReader(BaseReader):
|
||||
"""Reader for Markdown files"""
|
||||
|
||||
enabled = bool(Markdown)
|
||||
file_extensions = ['md', 'markdown', 'mkd', 'mdown']
|
||||
|
||||
|
|
@ -174,7 +190,6 @@ class MarkdownReader(Reader):
|
|||
super(MarkdownReader, self).__init__(*args, **kwargs)
|
||||
self.extensions = self.settings['MD_EXTENSIONS']
|
||||
self.extensions.append('meta')
|
||||
self._md = Markdown(extensions=self.extensions)
|
||||
|
||||
def _parse_metadata(self, meta):
|
||||
"""Return the dict containing document metadata"""
|
||||
|
|
@ -194,6 +209,7 @@ class MarkdownReader(Reader):
|
|||
def read(self, source_path):
|
||||
"""Parse content and metadata of markdown files"""
|
||||
|
||||
self._md = Markdown(extensions=self.extensions)
|
||||
with pelican_open(source_path) as text:
|
||||
content = self._md.convert(text)
|
||||
|
||||
|
|
@ -201,8 +217,9 @@ class MarkdownReader(Reader):
|
|||
return content, metadata
|
||||
|
||||
|
||||
class HTMLReader(Reader):
|
||||
class HTMLReader(BaseReader):
|
||||
"""Parses HTML files as input, looking for meta, title, and body tags"""
|
||||
|
||||
file_extensions = ['htm', 'html']
|
||||
enabled = True
|
||||
|
||||
|
|
@ -312,7 +329,9 @@ class HTMLReader(Reader):
|
|||
return parser.body, metadata
|
||||
|
||||
|
||||
class AsciiDocReader(Reader):
|
||||
class AsciiDocReader(BaseReader):
|
||||
"""Reader for AsciiDoc files"""
|
||||
|
||||
enabled = bool(asciidoc)
|
||||
file_extensions = ['asc']
|
||||
default_options = ["--no-header-footer", "-a newline=\\n"]
|
||||
|
|
@ -344,109 +363,151 @@ class AsciiDocReader(Reader):
|
|||
return content, metadata
|
||||
|
||||
|
||||
EXTENSIONS = {}
|
||||
class Readers(object):
|
||||
"""Interface for all readers.
|
||||
|
||||
for cls in [Reader] + Reader.__subclasses__():
|
||||
for ext in cls.file_extensions:
|
||||
EXTENSIONS[ext] = cls
|
||||
This class contains a mapping of file extensions / Reader classes, to know
|
||||
which Reader class must be used to read a file (based on its extension).
|
||||
This is customizable both with the 'READERS' setting, and with the
|
||||
'readers_init' signall for plugins.
|
||||
|
||||
"""
|
||||
|
||||
def read_file(base_path, path, content_class=Page, fmt=None,
|
||||
settings=None, context=None,
|
||||
preread_signal=None, preread_sender=None,
|
||||
context_signal=None, context_sender=None):
|
||||
"""Return a content object parsed with the given format."""
|
||||
path = os.path.abspath(os.path.join(base_path, path))
|
||||
source_path = os.path.relpath(path, base_path)
|
||||
base, ext = os.path.splitext(os.path.basename(path))
|
||||
logger.debug('read file {} -> {}'.format(
|
||||
# used to warn about missing dependencies only once, at the first
|
||||
# instanciation of a Readers object.
|
||||
warn_missing_deps = True
|
||||
|
||||
def __init__(self, settings=None):
|
||||
self.settings = settings or {}
|
||||
self.readers = {}
|
||||
self.reader_classes = {}
|
||||
|
||||
for cls in [BaseReader] + BaseReader.__subclasses__():
|
||||
if not cls.enabled:
|
||||
if self.__class__.warn_missing_deps:
|
||||
logger.debug('Missing dependencies for {}'
|
||||
.format(', '.join(cls.file_extensions)))
|
||||
continue
|
||||
|
||||
for ext in cls.file_extensions:
|
||||
self.reader_classes[ext] = cls
|
||||
|
||||
self.__class__.warn_missing_deps = False
|
||||
|
||||
if self.settings['READERS']:
|
||||
self.reader_classes.update(self.settings['READERS'])
|
||||
|
||||
signals.readers_init.send(self)
|
||||
|
||||
for fmt, reader_class in self.reader_classes.items():
|
||||
if not reader_class:
|
||||
continue
|
||||
|
||||
self.readers[fmt] = reader_class(self.settings)
|
||||
|
||||
settings_key = '%s_EXTENSIONS' % fmt.upper()
|
||||
|
||||
if settings_key in self.settings:
|
||||
self.readers[fmt].extensions = self.settings[settings_key]
|
||||
|
||||
@property
|
||||
def extensions(self):
|
||||
return self.readers.keys()
|
||||
|
||||
def read_file(self, base_path, path, content_class=Page, fmt=None,
|
||||
context=None, preread_signal=None, preread_sender=None,
|
||||
context_signal=None, context_sender=None):
|
||||
"""Return a content object parsed with the given format."""
|
||||
|
||||
path = os.path.abspath(os.path.join(base_path, path))
|
||||
source_path = os.path.relpath(path, base_path)
|
||||
logger.debug('read file {} -> {}'.format(
|
||||
source_path, content_class.__name__))
|
||||
if not fmt:
|
||||
fmt = ext[1:]
|
||||
|
||||
if fmt not in EXTENSIONS:
|
||||
raise TypeError('Pelican does not know how to parse {}'.format(path))
|
||||
if not fmt:
|
||||
_, ext = os.path.splitext(os.path.basename(path))
|
||||
fmt = ext[1:]
|
||||
|
||||
if preread_signal:
|
||||
logger.debug('signal {}.send({})'.format(
|
||||
if fmt not in self.readers:
|
||||
raise TypeError(
|
||||
'Pelican does not know how to parse {}'.format(path))
|
||||
|
||||
if preread_signal:
|
||||
logger.debug('signal {}.send({})'.format(
|
||||
preread_signal, preread_sender))
|
||||
preread_signal.send(preread_sender)
|
||||
preread_signal.send(preread_sender)
|
||||
|
||||
if settings is None:
|
||||
settings = {}
|
||||
reader = self.readers[fmt]
|
||||
|
||||
reader_class = EXTENSIONS[fmt]
|
||||
if not reader_class.enabled:
|
||||
raise ValueError('Missing dependencies for {}'.format(fmt))
|
||||
|
||||
reader = reader_class(settings)
|
||||
|
||||
settings_key = '%s_EXTENSIONS' % fmt.upper()
|
||||
|
||||
if settings and settings_key in settings:
|
||||
reader.extensions = settings[settings_key]
|
||||
|
||||
metadata = default_metadata(
|
||||
settings=settings, process=reader.process_metadata)
|
||||
metadata.update(path_metadata(
|
||||
full_path=path, source_path=source_path, settings=settings))
|
||||
metadata.update(parse_path_metadata(
|
||||
source_path=source_path, settings=settings,
|
||||
metadata = default_metadata(
|
||||
settings=self.settings, process=reader.process_metadata)
|
||||
metadata.update(path_metadata(
|
||||
full_path=path, source_path=source_path,
|
||||
settings=self.settings))
|
||||
metadata.update(parse_path_metadata(
|
||||
source_path=source_path, settings=self.settings,
|
||||
process=reader.process_metadata))
|
||||
content, reader_metadata = reader.read(path)
|
||||
metadata.update(reader_metadata)
|
||||
|
||||
# create warnings for all images with empty alt (up to a certain number)
|
||||
# as they are really likely to be accessibility flaws
|
||||
if content:
|
||||
# find images with empty alt
|
||||
imgs = re.compile(r"""
|
||||
(?:
|
||||
# src before alt
|
||||
<img
|
||||
[^\>]*
|
||||
src=(['"])(.*)\1
|
||||
[^\>]*
|
||||
alt=(['"])\3
|
||||
)|(?:
|
||||
# alt before src
|
||||
<img
|
||||
[^\>]*
|
||||
alt=(['"])\4
|
||||
[^\>]*
|
||||
src=(['"])(.*)\5
|
||||
)
|
||||
""", re.X)
|
||||
matches = re.findall(imgs, content)
|
||||
# find a correct threshold
|
||||
nb_warnings = 10
|
||||
if len(matches) == nb_warnings + 1:
|
||||
nb_warnings += 1 # avoid bad looking case
|
||||
# print one warning per image with empty alt until threshold
|
||||
for match in matches[:nb_warnings]:
|
||||
logger.warning('Empty alt attribute for image {} in {}'.format(
|
||||
os.path.basename(match[1] + match[5]), path))
|
||||
# print one warning for the other images with empty alt
|
||||
if len(matches) > nb_warnings:
|
||||
logger.warning('{} other images with empty alt attributes'.format(
|
||||
len(matches) - nb_warnings))
|
||||
content, reader_metadata = reader.read(path)
|
||||
metadata.update(reader_metadata)
|
||||
|
||||
# eventually filter the content with typogrify if asked so
|
||||
if content and settings and settings['TYPOGRIFY']:
|
||||
from typogrify.filters import typogrify
|
||||
content = typogrify(content)
|
||||
metadata['title'] = typogrify(metadata['title'])
|
||||
if content:
|
||||
# find images with empty alt
|
||||
find_empty_alt(content, path)
|
||||
|
||||
if context_signal:
|
||||
logger.debug('signal {}.send({}, <metadata>)'.format(
|
||||
# eventually filter the content with typogrify if asked so
|
||||
if content and self.settings['TYPOGRIFY']:
|
||||
from typogrify.filters import typogrify
|
||||
content = typogrify(content)
|
||||
metadata['title'] = typogrify(metadata['title'])
|
||||
|
||||
if context_signal:
|
||||
logger.debug('signal {}.send({}, <metadata>)'.format(
|
||||
context_signal, context_sender))
|
||||
context_signal.send(context_sender, metadata=metadata)
|
||||
return content_class(
|
||||
content=content,
|
||||
metadata=metadata,
|
||||
settings=settings,
|
||||
source_path=path,
|
||||
context=context)
|
||||
context_signal.send(context_sender, metadata=metadata)
|
||||
|
||||
return content_class(content=content, metadata=metadata,
|
||||
settings=self.settings, source_path=path,
|
||||
context=context)
|
||||
|
||||
|
||||
def find_empty_alt(content, path):
|
||||
"""Find images with empty alt
|
||||
|
||||
Create warnings for all images with empty alt (up to a certain number),
|
||||
as they are really likely to be accessibility flaws.
|
||||
|
||||
"""
|
||||
imgs = re.compile(r"""
|
||||
(?:
|
||||
# src before alt
|
||||
<img
|
||||
[^\>]*
|
||||
src=(['"])(.*)\1
|
||||
[^\>]*
|
||||
alt=(['"])\3
|
||||
)|(?:
|
||||
# alt before src
|
||||
<img
|
||||
[^\>]*
|
||||
alt=(['"])\4
|
||||
[^\>]*
|
||||
src=(['"])(.*)\5
|
||||
)
|
||||
""", re.X)
|
||||
matches = re.findall(imgs, content)
|
||||
# find a correct threshold
|
||||
nb_warnings = 10
|
||||
if len(matches) == nb_warnings + 1:
|
||||
nb_warnings += 1 # avoid bad looking case
|
||||
# print one warning per image with empty alt until threshold
|
||||
for match in matches[:nb_warnings]:
|
||||
logger.warning('Empty alt attribute for image {} in {}'.format(
|
||||
os.path.basename(match[1] + match[5]), path))
|
||||
# print one warning for the other images with empty alt
|
||||
if len(matches) > nb_warnings:
|
||||
logger.warning('{} other images with empty alt attributes'
|
||||
.format(len(matches) - nb_warnings))
|
||||
|
||||
|
||||
def default_metadata(settings=None, process=None):
|
||||
|
|
@ -469,7 +530,7 @@ def path_metadata(full_path, source_path, settings=None):
|
|||
metadata['date'] = datetime.datetime.fromtimestamp(
|
||||
os.stat(full_path).st_ctime)
|
||||
metadata.update(settings.get('EXTRA_PATH_METADATA', {}).get(
|
||||
source_path, {}))
|
||||
source_path, {}))
|
||||
return metadata
|
||||
|
||||
|
||||
|
|
@ -482,7 +543,7 @@ def parse_path_metadata(source_path, settings=None, process=None):
|
|||
... 'PATH_METADATA':
|
||||
... '(?P<category>[^/]*)/(?P<date>\d{4}-\d{2}-\d{2})/.*',
|
||||
... }
|
||||
>>> reader = Reader(settings=settings)
|
||||
>>> reader = BaseReader(settings=settings)
|
||||
>>> metadata = parse_path_metadata(
|
||||
... source_path='my-cat/2013-01-01/my-slug.html',
|
||||
... settings=settings,
|
||||
|
|
@ -498,13 +559,12 @@ def parse_path_metadata(source_path, settings=None, process=None):
|
|||
subdir = os.path.basename(dirname)
|
||||
if settings:
|
||||
checks = []
|
||||
for key,data in [('FILENAME_METADATA', base),
|
||||
('PATH_METADATA', source_path),
|
||||
]:
|
||||
for key, data in [('FILENAME_METADATA', base),
|
||||
('PATH_METADATA', source_path)]:
|
||||
checks.append((settings.get(key, None), data))
|
||||
if settings.get('USE_FOLDER_AS_CATEGORY', None):
|
||||
checks.insert(0, ('(?P<category>.*)', subdir))
|
||||
for regexp,data in checks:
|
||||
for regexp, data in checks:
|
||||
if regexp and data:
|
||||
match = re.match(regexp, data)
|
||||
if match:
|
||||
|
|
|
|||
|
|
@ -8,20 +8,29 @@ from pygments import highlight
|
|||
from pygments.lexers import get_lexer_by_name, TextLexer
|
||||
import re
|
||||
|
||||
INLINESTYLES = False
|
||||
DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)
|
||||
VARIANTS = {
|
||||
'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),
|
||||
}
|
||||
|
||||
|
||||
class Pygments(Directive):
|
||||
""" Source code syntax hightlighting.
|
||||
""" Source code syntax highlighting.
|
||||
"""
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = dict([(key, directives.flag) for key in VARIANTS])
|
||||
option_spec = {
|
||||
'anchorlinenos': directives.flag,
|
||||
'classprefix': directives.unchanged,
|
||||
'hl_lines': directives.unchanged,
|
||||
'lineanchors': directives.unchanged,
|
||||
'linenos': directives.unchanged,
|
||||
'linenospecial': directives.nonnegative_int,
|
||||
'linenostart': directives.nonnegative_int,
|
||||
'linenostep': directives.nonnegative_int,
|
||||
'lineseparator': directives.unchanged,
|
||||
'linespans': directives.unchanged,
|
||||
'nobackground': directives.flag,
|
||||
'nowrap': directives.flag,
|
||||
'tagsfile': directives.unchanged,
|
||||
'tagurlformat': directives.unchanged,
|
||||
}
|
||||
has_content = True
|
||||
|
||||
def run(self):
|
||||
|
|
@ -31,9 +40,17 @@ class Pygments(Directive):
|
|||
except ValueError:
|
||||
# no lexer found - use the text one instead of an exception
|
||||
lexer = TextLexer()
|
||||
# take an arbitrary option if more than one is given
|
||||
formatter = self.options and VARIANTS[list(self.options.keys())[0]] \
|
||||
or DEFAULT
|
||||
|
||||
if ('linenos' in self.options and
|
||||
self.options['linenos'] not in ('table', 'inline')):
|
||||
self.options['linenos'] = 'table'
|
||||
|
||||
for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
|
||||
if flag in self.options:
|
||||
self.options[flag] = True
|
||||
|
||||
# noclasses should already default to False, but just in case...
|
||||
formatter = HtmlFormatter(noclasses=False, **self.options)
|
||||
parsed = highlight('\n'.join(self.content), lexer, formatter)
|
||||
return [nodes.raw('', parsed, format='html')]
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ DEFAULT_CONFIG = {
|
|||
'PAGE_EXCLUDES': (),
|
||||
'THEME': DEFAULT_THEME,
|
||||
'OUTPUT_PATH': 'output',
|
||||
'MARKUP': ('rst', 'md'),
|
||||
'READERS': {},
|
||||
'STATIC_PATHS': ['images', ],
|
||||
'THEME_STATIC_DIR': 'theme',
|
||||
'THEME_STATIC_PATHS': ['static', ],
|
||||
|
|
@ -84,7 +84,7 @@ DEFAULT_CONFIG = {
|
|||
'DEFAULT_LANG': 'en',
|
||||
'TAG_CLOUD_STEPS': 4,
|
||||
'TAG_CLOUD_MAX_ITEMS': 100,
|
||||
'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'archives'),
|
||||
'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'authors', 'archives'),
|
||||
'EXTRA_TEMPLATES_PATHS': [],
|
||||
'PAGINATED_DIRECT_TEMPLATES': ('index', ),
|
||||
'PELICAN_CLASS': 'pelican.Pelican',
|
||||
|
|
@ -112,6 +112,7 @@ DEFAULT_CONFIG = {
|
|||
'SLUG_SUBSTITUTIONS': (),
|
||||
}
|
||||
|
||||
|
||||
def read_settings(path=None, override=None):
|
||||
if path:
|
||||
local_settings = get_settings_from_file(path)
|
||||
|
|
@ -120,7 +121,7 @@ def read_settings(path=None, override=None):
|
|||
if p in local_settings and local_settings[p] is not None \
|
||||
and not isabs(local_settings[p]):
|
||||
absp = os.path.abspath(os.path.normpath(os.path.join(
|
||||
os.path.dirname(path), local_settings[p])))
|
||||
os.path.dirname(path), local_settings[p])))
|
||||
if p not in ('THEME', 'PLUGIN_PATH') or os.path.exists(absp):
|
||||
local_settings[p] = absp
|
||||
else:
|
||||
|
|
@ -138,7 +139,7 @@ def get_settings_from_module(module=None, default_settings=DEFAULT_CONFIG):
|
|||
context = copy.deepcopy(default_settings)
|
||||
if module is not None:
|
||||
context.update(
|
||||
(k, v) for k, v in inspect.getmembers(module) if k.isupper())
|
||||
(k, v) for k, v in inspect.getmembers(module) if k.isupper())
|
||||
return context
|
||||
|
||||
|
||||
|
|
@ -221,17 +222,18 @@ def configure_settings(settings):
|
|||
settings['FEED_DOMAIN'] = settings['SITEURL']
|
||||
|
||||
# Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined
|
||||
feed_keys = ['FEED_ATOM', 'FEED_RSS',
|
||||
'FEED_ALL_ATOM', 'FEED_ALL_RSS',
|
||||
'CATEGORY_FEED_ATOM', 'CATEGORY_FEED_RSS',
|
||||
'TAG_FEED_ATOM', 'TAG_FEED_RSS',
|
||||
'TRANSLATION_FEED_ATOM', 'TRANSLATION_FEED_RSS',
|
||||
]
|
||||
feed_keys = [
|
||||
'FEED_ATOM', 'FEED_RSS',
|
||||
'FEED_ALL_ATOM', 'FEED_ALL_RSS',
|
||||
'CATEGORY_FEED_ATOM', 'CATEGORY_FEED_RSS',
|
||||
'TAG_FEED_ATOM', 'TAG_FEED_RSS',
|
||||
'TRANSLATION_FEED_ATOM', 'TRANSLATION_FEED_RSS',
|
||||
]
|
||||
|
||||
if any(settings.get(k) for k in feed_keys):
|
||||
if not settings.get('SITEURL'):
|
||||
logger.warning('Feeds generated without SITEURL set properly may not'
|
||||
' be valid')
|
||||
logger.warning('Feeds generated without SITEURL set properly may'
|
||||
' not be valid')
|
||||
|
||||
if not 'TIMEZONE' in settings:
|
||||
logger.warning(
|
||||
|
|
@ -255,26 +257,26 @@ def configure_settings(settings):
|
|||
|
||||
# Save people from accidentally setting a string rather than a list
|
||||
path_keys = (
|
||||
'ARTICLE_EXCLUDES',
|
||||
'DEFAULT_METADATA',
|
||||
'DIRECT_TEMPLATES',
|
||||
'EXTRA_TEMPLATES_PATHS',
|
||||
'FILES_TO_COPY',
|
||||
'IGNORE_FILES',
|
||||
'JINJA_EXTENSIONS',
|
||||
'MARKUP',
|
||||
'PAGINATED_DIRECT_TEMPLATES',
|
||||
'PLUGINS',
|
||||
'STATIC_PATHS',
|
||||
'THEME_STATIC_PATHS',)
|
||||
'ARTICLE_EXCLUDES',
|
||||
'DEFAULT_METADATA',
|
||||
'DIRECT_TEMPLATES',
|
||||
'EXTRA_TEMPLATES_PATHS',
|
||||
'FILES_TO_COPY',
|
||||
'IGNORE_FILES',
|
||||
'JINJA_EXTENSIONS',
|
||||
'PAGINATED_DIRECT_TEMPLATES',
|
||||
'PLUGINS',
|
||||
'STATIC_PATHS',
|
||||
'THEME_STATIC_PATHS',
|
||||
)
|
||||
for PATH_KEY in filter(lambda k: k in settings, path_keys):
|
||||
if isinstance(settings[PATH_KEY], six.string_types):
|
||||
logger.warning("Detected misconfiguration with %s setting (must "
|
||||
"be a list), falling back to the default"
|
||||
% PATH_KEY)
|
||||
logger.warning("Detected misconfiguration with %s setting "
|
||||
"(must be a list), falling back to the default"
|
||||
% PATH_KEY)
|
||||
settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY]
|
||||
|
||||
for old,new,doc in [
|
||||
for old, new, doc in [
|
||||
('LESS_GENERATOR', 'the Webassets plugin', None),
|
||||
('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA',
|
||||
'https://github.com/getpelican/pelican/blob/master/docs/settings.rst#path-metadata'),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ initialized = signal('pelican_initialized')
|
|||
get_generators = signal('get_generators')
|
||||
finalized = signal('pelican_finalized')
|
||||
|
||||
# Reader-level signals
|
||||
|
||||
readers_init = signal('readers_init')
|
||||
|
||||
# Generator-level signals
|
||||
|
||||
generator_init = signal('generator_init')
|
||||
|
|
|
|||
51
pelican/tests/output/basic/authors.html
Normal file
51
pelican/tests/output/basic/authors.html
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>A Pelican Blog - Authors</title>
|
||||
<link rel="stylesheet" href="/theme/css/main.css">
|
||||
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
|
||||
|
||||
<!--[if IE]>
|
||||
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body id="index" class="home">
|
||||
<header id="banner" class="body">
|
||||
<h1><a href="/">A Pelican Blog </a></h1>
|
||||
<nav><ul>
|
||||
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
|
||||
<li><a href="/override/">Override url/save_as</a></li>
|
||||
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
|
||||
<li><a href="/category/bar.html">bar</a></li>
|
||||
<li><a href="/category/cat1.html">cat1</a></li>
|
||||
<li><a href="/category/misc.html">misc</a></li>
|
||||
<li><a href="/category/yeah.html">yeah</a></li>
|
||||
</ul></nav>
|
||||
</header><!-- /#banner -->
|
||||
|
||||
<section id="content" class="body">
|
||||
<h1>Authors on A Pelican Blog</h1> <li><a href="/author/alexis-metaireau.html">Alexis Métaireau</a> (2)</li>
|
||||
</section>
|
||||
|
||||
<section id="extras" class="body">
|
||||
<div class="social">
|
||||
<h2>social</h2>
|
||||
<ul>
|
||||
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
|
||||
|
||||
</ul>
|
||||
</div><!-- /.social -->
|
||||
</section><!-- /#extras -->
|
||||
|
||||
<footer id="contentinfo" class="body">
|
||||
<address id="about" class="vcard body">
|
||||
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||
</address><!-- /#about -->
|
||||
|
||||
<p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
|
||||
</footer><!-- /#contentinfo -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -88,7 +88,9 @@
|
|||
</pre></div>
|
||||
</td></tr></table><p>Lovely.</p>
|
||||
</div>
|
||||
|
||||
<div class="section" id="testing-more-sourcecode-directives">
|
||||
<h2>Testing more sourcecode directives</h2>
|
||||
<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError ...</span></span></pre></div></div>
|
||||
<a class="readmore" href="/unbelievable.html">read more</a>
|
||||
</div><!-- /.entry-content -->
|
||||
</article></li>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -221,7 +221,9 @@ YEAH !</p>
|
|||
</pre></div>
|
||||
</td></tr></table><p>Lovely.</p>
|
||||
</div>
|
||||
|
||||
<div class="section" id="testing-more-sourcecode-directives">
|
||||
<h2>Testing more sourcecode directives</h2>
|
||||
<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError ...</span></span></pre></div></div>
|
||||
<a class="readmore" href="/unbelievable.html">read more</a>
|
||||
</div><!-- /.entry-content -->
|
||||
</article></li>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>A Pelican Blog - Tags</title>
|
||||
<link rel="stylesheet" href="/theme/css/main.css">
|
||||
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
|
||||
|
||||
<!--[if IE]>
|
||||
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body id="index" class="home">
|
||||
<header id="banner" class="body">
|
||||
<h1><a href="/">A Pelican Blog </a></h1>
|
||||
<nav><ul>
|
||||
<li><a href="/tag/oh.html">Oh Oh Oh</a></li>
|
||||
<li><a href="/override/">Override url/save_as</a></li>
|
||||
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
|
||||
<li><a href="/category/bar.html">bar</a></li>
|
||||
<li><a href="/category/cat1.html">cat1</a></li>
|
||||
<li><a href="/category/misc.html">misc</a></li>
|
||||
<li><a href="/category/yeah.html">yeah</a></li>
|
||||
</ul></nav>
|
||||
</header><!-- /#banner -->
|
||||
|
||||
<section id="content" class="body">
|
||||
<h1>Tags for A Pelican Blog</h1> <li><a href="/tag/bar.html">bar</a> (3)</li>
|
||||
<li><a href="/tag/baz.html">baz</a> (1)</li>
|
||||
<li><a href="/tag/foo.html">foo</a> (2)</li>
|
||||
<li><a href="/tag/foobar.html">foobar</a> (1)</li>
|
||||
<li><a href="/tag/oh.html">oh</a> (1)</li>
|
||||
<li><a href="/tag/yeah.html">yeah</a> (1)</li>
|
||||
</section>
|
||||
|
||||
<section id="extras" class="body">
|
||||
<div class="social">
|
||||
<h2>social</h2>
|
||||
<ul>
|
||||
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
|
||||
|
||||
</ul>
|
||||
</div><!-- /.social -->
|
||||
</section><!-- /#extras -->
|
||||
|
||||
<footer id="contentinfo" class="body">
|
||||
<address id="about" class="vcard body">
|
||||
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||
</address><!-- /#about -->
|
||||
|
||||
<p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
|
||||
</footer><!-- /#contentinfo -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -57,7 +57,9 @@
|
|||
</pre></div>
|
||||
</td></tr></table><p>Lovely.</p>
|
||||
</div>
|
||||
|
||||
<div class="section" id="testing-more-sourcecode-directives">
|
||||
<h2>Testing more sourcecode directives</h2>
|
||||
<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError ...</span></span></pre></div></div>
|
||||
<a class="readmore" href="../unbelievable.html">read more</a>
|
||||
<p>There are <a href="../unbelievable.html#disqus_thread">comments</a>.</p> </div><!-- /.entry-content -->
|
||||
</article></li>
|
||||
|
|
|
|||
79
pelican/tests/output/custom/authors.html
Normal file
79
pelican/tests/output/custom/authors.html
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Alexis' log - Authors</title>
|
||||
<link rel="stylesheet" href="./theme/css/main.css">
|
||||
<link href="http://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Alexis' log Atom Feed" />
|
||||
<link href="http://blog.notmyidea.org/feeds/all.rss.xml" type="application/rss+xml" rel="alternate" title="Alexis' log RSS Feed" />
|
||||
|
||||
<!--[if IE]>
|
||||
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body id="index" class="home">
|
||||
<a href="http://github.com/ametaireau/">
|
||||
<img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
|
||||
</a>
|
||||
<header id="banner" class="body">
|
||||
<h1><a href="./">Alexis' log </a></h1>
|
||||
<nav><ul>
|
||||
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
|
||||
<li><a href="./override/">Override url/save_as</a></li>
|
||||
<li><a href="./pages/this-is-a-test-page.html">This is a test page</a></li>
|
||||
<li><a href="./category/yeah.html">yeah</a></li>
|
||||
<li><a href="./category/misc.html">misc</a></li>
|
||||
<li><a href="./category/cat1.html">cat1</a></li>
|
||||
<li><a href="./category/bar.html">bar</a></li>
|
||||
</ul></nav>
|
||||
</header><!-- /#banner -->
|
||||
|
||||
<section id="content" class="body">
|
||||
<h1>Authors on Alexis' log</h1> <li><a href="./author/alexis-metaireau.html">Alexis Métaireau</a> (10)</li>
|
||||
</section>
|
||||
|
||||
<section id="extras" class="body">
|
||||
<div class="blogroll">
|
||||
<h2>blogroll</h2>
|
||||
<ul>
|
||||
<li><a href="http://biologeek.org">Biologeek</a></li>
|
||||
<li><a href="http://filyb.info/">Filyb</a></li>
|
||||
<li><a href="http://www.libert-fr.com">Libert-fr</a></li>
|
||||
<li><a href="http://prendreuncafe.com/blog/">N1k0</a></li>
|
||||
<li><a href="http://ziade.org/blog">Tarek Ziadé</a></li>
|
||||
<li><a href="http://zubin71.wordpress.com/">Zubin Mithra</a></li>
|
||||
</ul>
|
||||
</div><!-- /.blogroll -->
|
||||
<div class="social">
|
||||
<h2>social</h2>
|
||||
<ul>
|
||||
<li><a href="http://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
|
||||
<li><a href="http://blog.notmyidea.org/feeds/all.rss.xml" type="application/rss+xml" rel="alternate">rss feed</a></li>
|
||||
|
||||
<li><a href="http://twitter.com/ametaireau">twitter</a></li>
|
||||
<li><a href="http://lastfm.com/user/akounet">lastfm</a></li>
|
||||
<li><a href="http://github.com/ametaireau">github</a></li>
|
||||
</ul>
|
||||
</div><!-- /.social -->
|
||||
</section><!-- /#extras -->
|
||||
|
||||
<footer id="contentinfo" class="body">
|
||||
<address id="about" class="vcard body">
|
||||
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||
</address><!-- /#about -->
|
||||
|
||||
<p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
|
||||
</footer><!-- /#contentinfo -->
|
||||
|
||||
<script type="text/javascript">
|
||||
var disqus_shortname = 'blog-notmyidea';
|
||||
(function () {
|
||||
var s = document.createElement('script'); s.async = true;
|
||||
s.type = 'text/javascript';
|
||||
s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
|
||||
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -101,7 +101,9 @@
|
|||
</pre></div>
|
||||
</td></tr></table><p>Lovely.</p>
|
||||
</div>
|
||||
|
||||
<div class="section" id="testing-more-sourcecode-directives">
|
||||
<h2>Testing more sourcecode directives</h2>
|
||||
<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError ...</span></span></pre></div></div>
|
||||
<a class="readmore" href="../unbelievable.html">read more</a>
|
||||
<p>There are <a href="../unbelievable.html#disqus_thread">comments</a>.</p> </div><!-- /.entry-content -->
|
||||
</article></li>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -57,7 +57,9 @@
|
|||
</pre></div>
|
||||
</td></tr></table><p>Lovely.</p>
|
||||
</div>
|
||||
|
||||
<div class="section" id="testing-more-sourcecode-directives">
|
||||
<h2>Testing more sourcecode directives</h2>
|
||||
<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError ...</span></span></pre></div></div>
|
||||
<a class="readmore" href="./unbelievable.html">read more</a>
|
||||
<p>There are <a href="./unbelievable.html#disqus_thread">comments</a>.</p> </div><!-- /.entry-content -->
|
||||
</article></li>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Alexis' log - Tags</title>
|
||||
<link rel="stylesheet" href="./theme/css/main.css">
|
||||
<link href="http://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Alexis' log Atom Feed" />
|
||||
<link href="http://blog.notmyidea.org/feeds/all.rss.xml" type="application/rss+xml" rel="alternate" title="Alexis' log RSS Feed" />
|
||||
|
||||
<!--[if IE]>
|
||||
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body id="index" class="home">
|
||||
<a href="http://github.com/ametaireau/">
|
||||
<img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
|
||||
</a>
|
||||
<header id="banner" class="body">
|
||||
<h1><a href="./">Alexis' log </a></h1>
|
||||
<nav><ul>
|
||||
<li><a href="./tag/oh.html">Oh Oh Oh</a></li>
|
||||
<li><a href="./override/">Override url/save_as</a></li>
|
||||
<li><a href="./pages/this-is-a-test-page.html">This is a test page</a></li>
|
||||
<li><a href="./category/yeah.html">yeah</a></li>
|
||||
<li><a href="./category/misc.html">misc</a></li>
|
||||
<li><a href="./category/cat1.html">cat1</a></li>
|
||||
<li><a href="./category/bar.html">bar</a></li>
|
||||
</ul></nav>
|
||||
</header><!-- /#banner -->
|
||||
|
||||
<section id="content" class="body">
|
||||
<h1>Tags for Alexis' log</h1> <li><a href="./tag/bar.html">bar</a> (3)</li>
|
||||
<li><a href="./tag/baz.html">baz</a> (1)</li>
|
||||
<li><a href="./tag/foo.html">foo</a> (2)</li>
|
||||
<li><a href="./tag/foobar.html">foobar</a> (1)</li>
|
||||
<li><a href="./tag/oh.html">oh</a> (1)</li>
|
||||
<li><a href="./tag/yeah.html">yeah</a> (1)</li>
|
||||
</section>
|
||||
|
||||
<section id="extras" class="body">
|
||||
<div class="blogroll">
|
||||
<h2>blogroll</h2>
|
||||
<ul>
|
||||
<li><a href="http://biologeek.org">Biologeek</a></li>
|
||||
<li><a href="http://filyb.info/">Filyb</a></li>
|
||||
<li><a href="http://www.libert-fr.com">Libert-fr</a></li>
|
||||
<li><a href="http://prendreuncafe.com/blog/">N1k0</a></li>
|
||||
<li><a href="http://ziade.org/blog">Tarek Ziadé</a></li>
|
||||
<li><a href="http://zubin71.wordpress.com/">Zubin Mithra</a></li>
|
||||
</ul>
|
||||
</div><!-- /.blogroll -->
|
||||
<div class="social">
|
||||
<h2>social</h2>
|
||||
<ul>
|
||||
<li><a href="http://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
|
||||
<li><a href="http://blog.notmyidea.org/feeds/all.rss.xml" type="application/rss+xml" rel="alternate">rss feed</a></li>
|
||||
|
||||
<li><a href="http://twitter.com/ametaireau">twitter</a></li>
|
||||
<li><a href="http://lastfm.com/user/akounet">lastfm</a></li>
|
||||
<li><a href="http://github.com/ametaireau">github</a></li>
|
||||
</ul>
|
||||
</div><!-- /.social -->
|
||||
</section><!-- /#extras -->
|
||||
|
||||
<footer id="contentinfo" class="body">
|
||||
<address id="about" class="vcard body">
|
||||
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||
</address><!-- /#about -->
|
||||
|
||||
<p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
|
||||
</footer><!-- /#contentinfo -->
|
||||
|
||||
<script type="text/javascript">
|
||||
var disqus_shortname = 'blog-notmyidea';
|
||||
(function () {
|
||||
var s = document.createElement('script'); s.async = true;
|
||||
s.type = 'text/javascript';
|
||||
s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
|
||||
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -19,9 +19,9 @@ CONTENT_DIR = os.path.join(CUR_DIR, 'content')
|
|||
class TestGenerator(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.settings = get_settings()
|
||||
self.settings['READERS'] = {'asc': None}
|
||||
self.generator = Generator(self.settings.copy(), self.settings,
|
||||
CUR_DIR, self.settings['THEME'], None,
|
||||
self.settings['MARKUP'])
|
||||
CUR_DIR, self.settings['THEME'], None)
|
||||
|
||||
def test_include_path(self):
|
||||
filename = os.path.join(CUR_DIR, 'content', 'article.rst')
|
||||
|
|
@ -30,10 +30,6 @@ class TestGenerator(unittest.TestCase):
|
|||
self.assertTrue(include_path(filename, extensions=('rst',)))
|
||||
self.assertFalse(include_path(filename, extensions=('md',)))
|
||||
|
||||
# markup must be a tuple, test that this works also with a list
|
||||
self.generator.markup = ['rst', 'md']
|
||||
self.assertTrue(include_path(filename))
|
||||
|
||||
|
||||
class TestArticlesGenerator(unittest.TestCase):
|
||||
|
||||
|
|
@ -42,11 +38,11 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
settings = get_settings(filenames={})
|
||||
settings['DEFAULT_CATEGORY'] = 'Default'
|
||||
settings['DEFAULT_DATE'] = (1970, 1, 1)
|
||||
settings['READERS'] = {'asc': None}
|
||||
|
||||
cls.generator = ArticlesGenerator(
|
||||
context=settings.copy(), settings=settings,
|
||||
path=CONTENT_DIR, theme=settings['THEME'],
|
||||
output_path=None, markup=settings['MARKUP'])
|
||||
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
|
||||
cls.generator.generate_context()
|
||||
cls.articles = [[page.title, page.status, page.category.name,
|
||||
page.template] for page in cls.generator.articles]
|
||||
|
|
@ -55,8 +51,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
settings = get_settings()
|
||||
generator = ArticlesGenerator(
|
||||
context=settings, settings=settings,
|
||||
path=None, theme=settings['THEME'],
|
||||
output_path=None, markup=settings['MARKUP'])
|
||||
path=None, theme=settings['THEME'], output_path=None)
|
||||
writer = MagicMock()
|
||||
generator.generate_feeds(writer)
|
||||
writer.write_feed.assert_called_with([], settings,
|
||||
|
|
@ -64,8 +59,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
|
||||
generator = ArticlesGenerator(
|
||||
context=settings, settings=get_settings(FEED_ALL_ATOM=None),
|
||||
path=None, theme=settings['THEME'],
|
||||
output_path=None, markup=None)
|
||||
path=None, theme=settings['THEME'], output_path=None)
|
||||
writer = MagicMock()
|
||||
generator.generate_feeds(writer)
|
||||
self.assertFalse(writer.write_feed.called)
|
||||
|
|
@ -74,26 +68,33 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
|
||||
articles_expected = [
|
||||
['Article title', 'published', 'Default', 'article'],
|
||||
['Article with markdown and summary metadata single', 'published',
|
||||
'Default', 'article'],
|
||||
['Article with markdown and summary metadata multi', 'published',
|
||||
'Default', 'article'],
|
||||
['Article with markdown and summary metadata single', 'published',
|
||||
'Default', 'article'],
|
||||
['Article with markdown containing footnotes', 'published',
|
||||
'Default', 'article'],
|
||||
['Article with template', 'published', 'Default', 'custom'],
|
||||
['Test md File', 'published', 'test', 'article'],
|
||||
['Rst with filename metadata', 'published', 'yeah', 'article'],
|
||||
['Test Markdown extensions', 'published', 'Default', 'article'],
|
||||
['Test markdown File', 'published', 'test', 'article'],
|
||||
['Test md File', 'published', 'test', 'article'],
|
||||
['Test mdown File', 'published', 'test', 'article'],
|
||||
['Test mkd File', 'published', 'test', 'article'],
|
||||
['This is a super article !', 'published', 'Yeah', 'article'],
|
||||
['This is a super article !', 'published', 'Yeah', 'article'],
|
||||
['This is a super article !', 'published', 'yeah', 'article'],
|
||||
['This is a super article !', 'published', 'yeah', 'article'],
|
||||
['This is a super article !', 'published', 'yeah', 'article'],
|
||||
['This is a super article !', 'published', 'Default', 'article'],
|
||||
['This is an article with category !', 'published', 'yeah',
|
||||
'article'],
|
||||
'article'],
|
||||
['This is an article without category !', 'published', 'Default',
|
||||
'article'],
|
||||
['This is an article without category !', 'published',
|
||||
'TestCategory', 'article'],
|
||||
['This is a super article !', 'published', 'yeah', 'article'],
|
||||
['マックOS X 10.8でパイソンとVirtualenvをインストールと設定',
|
||||
'published', '指導書', 'article'],
|
||||
['Article with markdown containing footnotes', 'published',
|
||||
'Default', 'article']
|
||||
['マックOS X 10.8でパイソンとVirtualenvをインストールと設定', 'published',
|
||||
'指導書', 'article'],
|
||||
]
|
||||
self.assertEqual(sorted(articles_expected), sorted(self.articles))
|
||||
|
||||
|
|
@ -121,11 +122,11 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
settings['DEFAULT_CATEGORY'] = 'Default'
|
||||
settings['DEFAULT_DATE'] = (1970, 1, 1)
|
||||
settings['USE_FOLDER_AS_CATEGORY'] = False
|
||||
settings['READERS'] = {'asc': None}
|
||||
settings['filenames'] = {}
|
||||
generator = ArticlesGenerator(
|
||||
context=settings.copy(), settings=settings,
|
||||
path=CONTENT_DIR, theme=settings['THEME'],
|
||||
output_path=None, markup=settings['MARKUP'])
|
||||
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
|
||||
generator.generate_context()
|
||||
# test for name
|
||||
# categories are grouped by slug; if two categories have the same slug
|
||||
|
|
@ -147,8 +148,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
settings = get_settings(filenames={})
|
||||
generator = ArticlesGenerator(
|
||||
context=settings, settings=settings,
|
||||
path=None, theme=settings['THEME'],
|
||||
output_path=None, markup=settings['MARKUP'])
|
||||
path=None, theme=settings['THEME'], output_path=None)
|
||||
write = MagicMock()
|
||||
generator.generate_direct_templates(write)
|
||||
write.assert_called_with("archives.html",
|
||||
|
|
@ -162,8 +162,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
|
||||
generator = ArticlesGenerator(
|
||||
context=settings, settings=settings,
|
||||
path=None, theme=settings['THEME'],
|
||||
output_path=None, markup=settings['MARKUP'])
|
||||
path=None, theme=settings['THEME'], output_path=None)
|
||||
write = MagicMock()
|
||||
generator.generate_direct_templates(write)
|
||||
write.assert_called_with("archives/index.html",
|
||||
|
|
@ -178,8 +177,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
|
||||
generator = ArticlesGenerator(
|
||||
context=settings, settings=settings,
|
||||
path=None, theme=settings['THEME'],
|
||||
output_path=None, markup=settings['MARKUP'])
|
||||
path=None, theme=settings['THEME'], output_path=None)
|
||||
write = MagicMock()
|
||||
generator.generate_direct_templates(write)
|
||||
write.assert_called_count == 0
|
||||
|
|
@ -212,8 +210,7 @@ class TestPageGenerator(unittest.TestCase):
|
|||
|
||||
generator = PagesGenerator(
|
||||
context=settings.copy(), settings=settings,
|
||||
path=CUR_DIR, theme=settings['THEME'],
|
||||
output_path=None, markup=settings['MARKUP'])
|
||||
path=CUR_DIR, theme=settings['THEME'], output_path=None)
|
||||
generator.generate_context()
|
||||
pages = self.distill_pages(generator.pages)
|
||||
hidden_pages = self.distill_pages(generator.hidden_pages)
|
||||
|
|
@ -252,13 +249,12 @@ class TestTemplatePagesGenerator(unittest.TestCase):
|
|||
settings = get_settings()
|
||||
settings['STATIC_PATHS'] = ['static']
|
||||
settings['TEMPLATE_PAGES'] = {
|
||||
'template/source.html': 'generated/file.html'
|
||||
}
|
||||
'template/source.html': 'generated/file.html'
|
||||
}
|
||||
|
||||
generator = TemplatePagesGenerator(
|
||||
context={'foo': 'bar'}, settings=settings,
|
||||
path=self.temp_content, theme='',
|
||||
output_path=self.temp_output, markup=None)
|
||||
path=self.temp_content, theme='', output_path=self.temp_output)
|
||||
|
||||
# create a dummy template file
|
||||
template_dir = os.path.join(self.temp_content, 'template')
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ class ReaderTest(unittest.TestCase):
|
|||
|
||||
def read_file(self, path, **kwargs):
|
||||
# Isolate from future API changes to readers.read_file
|
||||
return readers.read_file(
|
||||
base_path=CONTENT_PATH, path=path, settings=get_settings(**kwargs))
|
||||
r = readers.Readers(settings=get_settings(**kwargs))
|
||||
return r.read_file(base_path=CONTENT_PATH, path=path)
|
||||
|
||||
|
||||
class RstReaderTest(ReaderTest):
|
||||
|
|
@ -160,7 +160,7 @@ class MdReaderTest(ReaderTest):
|
|||
' with some footnotes'
|
||||
'<sup id="fnref:footnote"><a class="footnote-ref" '
|
||||
'href="#fn:footnote" rel="footnote">2</a></sup></p>\n'
|
||||
|
||||
|
||||
'<div class="footnote">\n'
|
||||
'<hr />\n<ol>\n<li id="fn:1">\n'
|
||||
'<p>Numbered footnote '
|
||||
|
|
|
|||
|
|
@ -353,12 +353,13 @@ class TestDateFormatter(unittest.TestCase):
|
|||
'French locale needed')
|
||||
def test_french_locale(self):
|
||||
settings = read_settings(
|
||||
override = {'LOCALE': locale.normalize('fr_FR.UTF-8'),
|
||||
'TEMPLATE_PAGES': {'template/source.html':
|
||||
'generated/file.html'}})
|
||||
override={'LOCALE': locale.normalize('fr_FR.UTF-8'),
|
||||
'TEMPLATE_PAGES': {'template/source.html':
|
||||
'generated/file.html'}})
|
||||
|
||||
generator = TemplatePagesGenerator({'date': self.date}, settings,
|
||||
self.temp_content, '', self.temp_output, None)
|
||||
generator = TemplatePagesGenerator(
|
||||
{'date': self.date}, settings,
|
||||
self.temp_content, '', self.temp_output)
|
||||
generator.env.filters.update({'strftime': utils.DateFormatter()})
|
||||
|
||||
writer = Writer(self.temp_output, settings=settings)
|
||||
|
|
@ -385,8 +386,9 @@ class TestDateFormatter(unittest.TestCase):
|
|||
'TEMPLATE_PAGES': {'template/source.html':
|
||||
'generated/file.html'}})
|
||||
|
||||
generator = TemplatePagesGenerator({'date': self.date}, settings,
|
||||
self.temp_content, '', self.temp_output, None)
|
||||
generator = TemplatePagesGenerator(
|
||||
{'date': self.date}, settings,
|
||||
self.temp_content, '', self.temp_output)
|
||||
generator.env.filters.update({'strftime': utils.DateFormatter()})
|
||||
|
||||
writer = Writer(self.temp_output, settings=settings)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - Authors{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section id="content" class="body">
|
||||
<h1>Authors on {{ SITENAME }}</h1>
|
||||
|
||||
{%- for author, articles in authors|sort %}
|
||||
<li><a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a> ({{ articles|count }})</li>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
15
pelican/themes/notmyidea/templates/tags.html
Normal file
15
pelican/themes/notmyidea/templates/tags.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - Tags{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section id="content" class="body">
|
||||
<h1>Tags for {{ SITENAME }}</h1>
|
||||
|
||||
{%- for tag, articles in tags|sort %}
|
||||
<li><a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }}</a> ({{ articles|count }})</li>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
10
pelican/themes/simple/templates/authors.html
Normal file
10
pelican/themes/simple/templates/authors.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - Authors{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Authors on {{ SITENAME }}</h1>
|
||||
{%- for author, articles in authors|sort %}
|
||||
<li><a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a> ({{ articles|count }})</li>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ SITENAME }} - Tags{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Tags for {{ SITENAME }}</h1>
|
||||
{%- for tag, articles in tags|sort %}
|
||||
<li><a href="{{ SITEURL }}/{{ tag.url }}">{{ tag }}</a> ({{ articles|count }})</li>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
|
@ -18,3 +18,56 @@ Testing sourcecode directive
|
|||
|
||||
|
||||
Lovely.
|
||||
|
||||
Testing more sourcecode directives
|
||||
----------------------------------
|
||||
|
||||
.. sourcecode:: python
|
||||
:anchorlinenos:
|
||||
:classprefix: testing
|
||||
:hl_lines: 10,11,12
|
||||
:lineanchors: foo
|
||||
:linenos: inline
|
||||
:linenospecial: 2
|
||||
:linenostart: 8
|
||||
:linenostep: 2
|
||||
:lineseparator: <br>
|
||||
:linespans: foo
|
||||
:nobackground:
|
||||
|
||||
def run(self):
|
||||
self.assert_has_content()
|
||||
try:
|
||||
lexer = get_lexer_by_name(self.arguments[0])
|
||||
except ValueError:
|
||||
# no lexer found - use the text one instead of an exception
|
||||
lexer = TextLexer()
|
||||
|
||||
if ('linenos' in self.options and
|
||||
self.options['linenos'] not in ('table', 'inline')):
|
||||
self.options['linenos'] = 'table'
|
||||
|
||||
for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
|
||||
if flag in self.options:
|
||||
self.options[flag] = True
|
||||
|
||||
# noclasses should already default to False, but just in case...
|
||||
formatter = HtmlFormatter(noclasses=False, **self.options)
|
||||
parsed = highlight('\n'.join(self.content), lexer, formatter)
|
||||
return [nodes.raw('', parsed, format='html')]
|
||||
|
||||
|
||||
Lovely.
|
||||
|
||||
Testing even more sourcecode directives
|
||||
---------------------------------------
|
||||
|
||||
.. sourcecode:: python
|
||||
:linenos: table
|
||||
:nowrap:
|
||||
|
||||
|
||||
formatter = self.options and VARIANTS[self.options.keys()[0]]
|
||||
|
||||
|
||||
Lovely.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue