mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Refactor readers and remove MARKUP
Add a `Readers` class which contains a dict of file extensions / `Reader`
instances. This dict can be overwritten with a `READERS` settings, for instance
to avoid processing *.html files:
READERS = {'html': None}
Or to add a custom reader for the `foo` extension:
READERS = {'foo': FooReader}
This dict is no storing the Reader classes as it was done before with
`EXTENSIONS`. It stores the instances of the Reader classes to avoid instancing
for each file reading.
This commit is contained in:
parent
c3aa85831f
commit
4bc4b1500c
7 changed files with 201 additions and 203 deletions
|
|
@ -17,6 +17,7 @@ from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
||||||
StaticGenerator, SourceFileGenerator,
|
StaticGenerator, SourceFileGenerator,
|
||||||
TemplatePagesGenerator)
|
TemplatePagesGenerator)
|
||||||
from pelican.log import init
|
from pelican.log import init
|
||||||
|
from pelican.readers import Readers
|
||||||
from pelican.settings import read_settings
|
from pelican.settings import read_settings
|
||||||
from pelican.utils import clean_output_dir, folder_watcher, file_watcher
|
from pelican.utils import clean_output_dir, folder_watcher, file_watcher
|
||||||
from pelican.writers import Writer
|
from pelican.writers import Writer
|
||||||
|
|
@ -46,7 +47,6 @@ class Pelican(object):
|
||||||
self.path = settings['PATH']
|
self.path = settings['PATH']
|
||||||
self.theme = settings['THEME']
|
self.theme = settings['THEME']
|
||||||
self.output_path = settings['OUTPUT_PATH']
|
self.output_path = settings['OUTPUT_PATH']
|
||||||
self.markup = settings['MARKUP']
|
|
||||||
self.ignore_files = settings['IGNORE_FILES']
|
self.ignore_files = settings['IGNORE_FILES']
|
||||||
self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY']
|
self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY']
|
||||||
self.output_retention = settings['OUTPUT_RETENTION']
|
self.output_retention = settings['OUTPUT_RETENTION']
|
||||||
|
|
@ -164,7 +164,6 @@ class Pelican(object):
|
||||||
path=self.path,
|
path=self.path,
|
||||||
theme=self.theme,
|
theme=self.theme,
|
||||||
output_path=self.output_path,
|
output_path=self.output_path,
|
||||||
markup=self.markup,
|
|
||||||
) for cls in self.get_generator_classes()
|
) 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 '
|
help='Where to output the generated files. If not specified, a '
|
||||||
'directory will be created, named "output" in the current path.')
|
'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',
|
parser.add_argument('-s', '--settings', dest='settings',
|
||||||
help='The settings of the application, this is automatically set to '
|
help='The settings of the application, this is automatically set to '
|
||||||
'{0} if a file exists with this name.'.format(DEFAULT_CONFIG_NAME))
|
'{0} if a file exists with this name.'.format(DEFAULT_CONFIG_NAME))
|
||||||
|
|
@ -279,8 +274,6 @@ def get_config(args):
|
||||||
if args.output:
|
if args.output:
|
||||||
config['OUTPUT_PATH'] = \
|
config['OUTPUT_PATH'] = \
|
||||||
os.path.abspath(os.path.expanduser(args.output))
|
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:
|
if args.theme:
|
||||||
abstheme = os.path.abspath(os.path.expanduser(args.theme))
|
abstheme = os.path.abspath(os.path.expanduser(args.theme))
|
||||||
config['THEME'] = abstheme if os.path.exists(abstheme) else 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:
|
for key in config:
|
||||||
if key in ('PATH', 'OUTPUT_PATH', 'THEME'):
|
if key in ('PATH', 'OUTPUT_PATH', 'THEME'):
|
||||||
config[key] = config[key].decode(enc)
|
config[key] = config[key].decode(enc)
|
||||||
if key == "MARKUP":
|
|
||||||
config[key] = [a.decode(enc) for a in config[key]]
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -315,16 +306,17 @@ def get_instance(args):
|
||||||
module = __import__(module)
|
module = __import__(module)
|
||||||
cls = getattr(module, cls_name)
|
cls = getattr(module, cls_name)
|
||||||
|
|
||||||
return cls(settings)
|
return cls(settings), settings
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = parse_arguments()
|
args = parse_arguments()
|
||||||
init(args.verbosity)
|
init(args.verbosity)
|
||||||
pelican = get_instance(args)
|
pelican, settings = get_instance(args)
|
||||||
|
readers = Readers(settings)
|
||||||
|
|
||||||
watchers = {'content': folder_watcher(pelican.path,
|
watchers = {'content': folder_watcher(pelican.path,
|
||||||
pelican.markup,
|
readers.extensions,
|
||||||
pelican.ignore_files),
|
pelican.ignore_files),
|
||||||
'theme': folder_watcher(pelican.theme,
|
'theme': folder_watcher(pelican.theme,
|
||||||
[''],
|
[''],
|
||||||
|
|
@ -333,8 +325,8 @@ def main():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if args.autoreload:
|
if args.autoreload:
|
||||||
print(' --- AutoReload Mode: Monitoring `content`, `theme` and `settings`'
|
print(' --- AutoReload Mode: Monitoring `content`, `theme` and'
|
||||||
' for changes. ---')
|
' `settings` for changes. ---')
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,13 @@ from functools import partial
|
||||||
from itertools import chain, groupby
|
from itertools import chain, groupby
|
||||||
from operator import attrgetter, itemgetter
|
from operator import attrgetter, itemgetter
|
||||||
|
|
||||||
from jinja2 import (
|
from jinja2 import (Environment, FileSystemLoader, PrefixLoader, ChoiceLoader,
|
||||||
Environment, FileSystemLoader, PrefixLoader, ChoiceLoader, BaseLoader,
|
BaseLoader, TemplateNotFound)
|
||||||
TemplateNotFound
|
|
||||||
)
|
|
||||||
|
|
||||||
from pelican.contents import Article, Page, Static, is_valid_content
|
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.utils import copy, process_translations, mkdir_p, DateFormatter
|
||||||
from pelican import signals
|
from pelican import signals
|
||||||
import pelican.utils
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -31,23 +28,23 @@ logger = logging.getLogger(__name__)
|
||||||
class Generator(object):
|
class Generator(object):
|
||||||
"""Baseclass generator"""
|
"""Baseclass generator"""
|
||||||
|
|
||||||
def __init__(self, context, settings, path, theme, output_path, markup,
|
def __init__(self, context, settings, path, theme, output_path, **kwargs):
|
||||||
**kwargs):
|
|
||||||
self.context = context
|
self.context = context
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.path = path
|
self.path = path
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.output_path = output_path
|
self.output_path = output_path
|
||||||
self.markup = markup
|
|
||||||
|
|
||||||
for arg, value in kwargs.items():
|
for arg, value in kwargs.items():
|
||||||
setattr(self, arg, value)
|
setattr(self, arg, value)
|
||||||
|
|
||||||
|
self.readers = Readers(self.settings)
|
||||||
|
|
||||||
# templates cache
|
# templates cache
|
||||||
self._templates = {}
|
self._templates = {}
|
||||||
self._templates_path = []
|
self._templates_path = []
|
||||||
self._templates_path.append(os.path.expanduser(
|
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']
|
self._templates_path += self.settings['EXTRA_TEMPLATES_PATHS']
|
||||||
|
|
||||||
theme_path = os.path.dirname(os.path.abspath(__file__))
|
theme_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
@ -85,9 +82,8 @@ class Generator(object):
|
||||||
try:
|
try:
|
||||||
self._templates[name] = self.env.get_template(name + '.html')
|
self._templates[name] = self.env.get_template(name + '.html')
|
||||||
except TemplateNotFound:
|
except TemplateNotFound:
|
||||||
raise Exception(
|
raise Exception('[templates] unable to load %s.html from %s'
|
||||||
('[templates] unable to load %s.html from %s'
|
% (name, self._templates_path))
|
||||||
% (name, self._templates_path)))
|
|
||||||
return self._templates[name]
|
return self._templates[name]
|
||||||
|
|
||||||
def _include_path(self, path, extensions=None):
|
def _include_path(self, path, extensions=None):
|
||||||
|
|
@ -98,7 +94,7 @@ class Generator(object):
|
||||||
extensions are allowed)
|
extensions are allowed)
|
||||||
"""
|
"""
|
||||||
if extensions is None:
|
if extensions is None:
|
||||||
extensions = tuple(self.markup)
|
extensions = tuple(self.readers.extensions)
|
||||||
basename = os.path.basename(path)
|
basename = os.path.basename(path)
|
||||||
if extensions is False or basename.endswith(extensions):
|
if extensions is False or basename.endswith(extensions):
|
||||||
return True
|
return True
|
||||||
|
|
@ -388,9 +384,9 @@ class ArticlesGenerator(Generator):
|
||||||
self.settings['ARTICLE_DIR'],
|
self.settings['ARTICLE_DIR'],
|
||||||
exclude=self.settings['ARTICLE_EXCLUDES']):
|
exclude=self.settings['ARTICLE_EXCLUDES']):
|
||||||
try:
|
try:
|
||||||
article = read_file(
|
article = self.readers.read_file(
|
||||||
base_path=self.path, path=f, content_class=Article,
|
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_signal=signals.article_generator_preread,
|
||||||
preread_sender=self,
|
preread_sender=self,
|
||||||
context_signal=signals.article_generator_context,
|
context_signal=signals.article_generator_context,
|
||||||
|
|
@ -496,9 +492,9 @@ class PagesGenerator(Generator):
|
||||||
self.settings['PAGE_DIR'],
|
self.settings['PAGE_DIR'],
|
||||||
exclude=self.settings['PAGE_EXCLUDES']):
|
exclude=self.settings['PAGE_EXCLUDES']):
|
||||||
try:
|
try:
|
||||||
page = read_file(
|
page = self.readers.read_file(
|
||||||
base_path=self.path, path=f, content_class=Page,
|
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_signal=signals.page_generator_preread,
|
||||||
preread_sender=self,
|
preread_sender=self,
|
||||||
context_signal=signals.page_generator_context,
|
context_signal=signals.page_generator_context,
|
||||||
|
|
@ -557,10 +553,9 @@ class StaticGenerator(Generator):
|
||||||
for static_path in self.settings['STATIC_PATHS']:
|
for static_path in self.settings['STATIC_PATHS']:
|
||||||
for f in self.get_files(
|
for f in self.get_files(
|
||||||
static_path, extensions=False):
|
static_path, extensions=False):
|
||||||
static = read_file(
|
static = self.readers.read_file(
|
||||||
base_path=self.path, path=f, content_class=Static,
|
base_path=self.path, path=f, content_class=Static,
|
||||||
fmt='static',
|
fmt='static', context=self.context,
|
||||||
settings=self.settings, context=self.context,
|
|
||||||
preread_signal=signals.static_generator_preread,
|
preread_signal=signals.static_generator_preread,
|
||||||
preread_sender=self,
|
preread_sender=self,
|
||||||
context_signal=signals.static_generator_context,
|
context_signal=signals.static_generator_context,
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ except ImportError:
|
||||||
from pelican.contents import Page, Category, Tag, Author
|
from pelican.contents import Page, Category, Tag, Author
|
||||||
from pelican.utils import get_date, pelican_open
|
from pelican.utils import get_date, pelican_open
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
METADATA_PROCESSORS = {
|
METADATA_PROCESSORS = {
|
||||||
'tags': lambda x, y: [Tag(tag, y) for tag in x.split(',')],
|
'tags': lambda x, y: [Tag(tag, y) for tag in x.split(',')],
|
||||||
|
|
@ -50,7 +49,7 @@ METADATA_PROCESSORS = {
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Reader(object):
|
class BaseReader(object):
|
||||||
enabled = True
|
enabled = True
|
||||||
file_extensions = ['static']
|
file_extensions = ['static']
|
||||||
extensions = None
|
extensions = None
|
||||||
|
|
@ -110,7 +109,7 @@ class PelicanHTMLTranslator(HTMLTranslator):
|
||||||
return HTMLTranslator.visit_image(self, node)
|
return HTMLTranslator.visit_image(self, node)
|
||||||
|
|
||||||
|
|
||||||
class RstReader(Reader):
|
class RstReader(BaseReader):
|
||||||
enabled = bool(docutils)
|
enabled = bool(docutils)
|
||||||
file_extensions = ['rst']
|
file_extensions = ['rst']
|
||||||
|
|
||||||
|
|
@ -166,7 +165,7 @@ class RstReader(Reader):
|
||||||
return content, metadata
|
return content, metadata
|
||||||
|
|
||||||
|
|
||||||
class MarkdownReader(Reader):
|
class MarkdownReader(BaseReader):
|
||||||
enabled = bool(Markdown)
|
enabled = bool(Markdown)
|
||||||
file_extensions = ['md', 'markdown', 'mkd', 'mdown']
|
file_extensions = ['md', 'markdown', 'mkd', 'mdown']
|
||||||
|
|
||||||
|
|
@ -174,7 +173,6 @@ class MarkdownReader(Reader):
|
||||||
super(MarkdownReader, self).__init__(*args, **kwargs)
|
super(MarkdownReader, self).__init__(*args, **kwargs)
|
||||||
self.extensions = self.settings['MD_EXTENSIONS']
|
self.extensions = self.settings['MD_EXTENSIONS']
|
||||||
self.extensions.append('meta')
|
self.extensions.append('meta')
|
||||||
self._md = Markdown(extensions=self.extensions)
|
|
||||||
|
|
||||||
def _parse_metadata(self, meta):
|
def _parse_metadata(self, meta):
|
||||||
"""Return the dict containing document metadata"""
|
"""Return the dict containing document metadata"""
|
||||||
|
|
@ -194,6 +192,7 @@ class MarkdownReader(Reader):
|
||||||
def read(self, source_path):
|
def read(self, source_path):
|
||||||
"""Parse content and metadata of markdown files"""
|
"""Parse content and metadata of markdown files"""
|
||||||
|
|
||||||
|
self._md = Markdown(extensions=self.extensions)
|
||||||
with pelican_open(source_path) as text:
|
with pelican_open(source_path) as text:
|
||||||
content = self._md.convert(text)
|
content = self._md.convert(text)
|
||||||
|
|
||||||
|
|
@ -201,7 +200,7 @@ class MarkdownReader(Reader):
|
||||||
return content, metadata
|
return content, metadata
|
||||||
|
|
||||||
|
|
||||||
class HTMLReader(Reader):
|
class HTMLReader(BaseReader):
|
||||||
"""Parses HTML files as input, looking for meta, title, and body tags"""
|
"""Parses HTML files as input, looking for meta, title, and body tags"""
|
||||||
file_extensions = ['htm', 'html']
|
file_extensions = ['htm', 'html']
|
||||||
enabled = True
|
enabled = True
|
||||||
|
|
@ -312,7 +311,7 @@ class HTMLReader(Reader):
|
||||||
return parser.body, metadata
|
return parser.body, metadata
|
||||||
|
|
||||||
|
|
||||||
class AsciiDocReader(Reader):
|
class AsciiDocReader(BaseReader):
|
||||||
enabled = bool(asciidoc)
|
enabled = bool(asciidoc)
|
||||||
file_extensions = ['asc']
|
file_extensions = ['asc']
|
||||||
default_options = ["--no-header-footer", "-a newline=\\n"]
|
default_options = ["--no-header-footer", "-a newline=\\n"]
|
||||||
|
|
@ -344,109 +343,125 @@ class AsciiDocReader(Reader):
|
||||||
return content, metadata
|
return content, metadata
|
||||||
|
|
||||||
|
|
||||||
EXTENSIONS = {}
|
class Readers(object):
|
||||||
|
|
||||||
for cls in [Reader] + Reader.__subclasses__():
|
def __init__(self, settings=None):
|
||||||
for ext in cls.file_extensions:
|
self.settings = settings or {}
|
||||||
EXTENSIONS[ext] = cls
|
self.readers = {}
|
||||||
|
|
||||||
|
extensions = {}
|
||||||
|
for cls in [BaseReader] + BaseReader.__subclasses__():
|
||||||
|
for ext in cls.file_extensions:
|
||||||
|
extensions[ext] = cls
|
||||||
|
|
||||||
def read_file(base_path, path, content_class=Page, fmt=None,
|
if self.settings['READERS']:
|
||||||
settings=None, context=None,
|
extensions.update(self.settings['READERS'])
|
||||||
preread_signal=None, preread_sender=None,
|
|
||||||
context_signal=None, context_sender=None):
|
for fmt, reader_class in extensions.items():
|
||||||
"""Return a content object parsed with the given format."""
|
if not reader_class:
|
||||||
path = os.path.abspath(os.path.join(base_path, path))
|
continue
|
||||||
source_path = os.path.relpath(path, base_path)
|
|
||||||
base, ext = os.path.splitext(os.path.basename(path))
|
if not reader_class.enabled:
|
||||||
logger.debug('read file {} -> {}'.format(
|
logger.warning('Missing dependencies for {}'.format(fmt))
|
||||||
|
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__))
|
source_path, content_class.__name__))
|
||||||
if not fmt:
|
|
||||||
fmt = ext[1:]
|
|
||||||
|
|
||||||
if fmt not in EXTENSIONS:
|
if not fmt:
|
||||||
raise TypeError('Pelican does not know how to parse {}'.format(path))
|
_, ext = os.path.splitext(os.path.basename(path))
|
||||||
|
fmt = ext[1:]
|
||||||
|
|
||||||
if preread_signal:
|
if fmt not in self.readers:
|
||||||
logger.debug('signal {}.send({})'.format(
|
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, preread_sender))
|
||||||
preread_signal.send(preread_sender)
|
preread_signal.send(preread_sender)
|
||||||
|
|
||||||
if settings is None:
|
reader = self.readers[fmt]
|
||||||
settings = {}
|
|
||||||
|
|
||||||
reader_class = EXTENSIONS[fmt]
|
metadata = default_metadata(
|
||||||
if not reader_class.enabled:
|
settings=self.settings, process=reader.process_metadata)
|
||||||
raise ValueError('Missing dependencies for {}'.format(fmt))
|
metadata.update(path_metadata(
|
||||||
|
full_path=path, source_path=source_path,
|
||||||
reader = reader_class(settings)
|
settings=self.settings))
|
||||||
|
metadata.update(parse_path_metadata(
|
||||||
settings_key = '%s_EXTENSIONS' % fmt.upper()
|
source_path=source_path, settings=self.settings,
|
||||||
|
|
||||||
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,
|
|
||||||
process=reader.process_metadata))
|
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)
|
content, reader_metadata = reader.read(path)
|
||||||
# as they are really likely to be accessibility flaws
|
metadata.update(reader_metadata)
|
||||||
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))
|
|
||||||
|
|
||||||
# eventually filter the content with typogrify if asked so
|
# create warnings for all images with empty alt (up to a certain
|
||||||
if content and settings and settings['TYPOGRIFY']:
|
# number) # as they are really likely to be accessibility flaws
|
||||||
from typogrify.filters import typogrify
|
if content:
|
||||||
content = typogrify(content)
|
# find images with empty alt
|
||||||
metadata['title'] = typogrify(metadata['title'])
|
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))
|
||||||
|
|
||||||
if context_signal:
|
# eventually filter the content with typogrify if asked so
|
||||||
logger.debug('signal {}.send({}, <metadata>)'.format(
|
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, context_sender))
|
||||||
context_signal.send(context_sender, metadata=metadata)
|
context_signal.send(context_sender, metadata=metadata)
|
||||||
return content_class(
|
|
||||||
content=content,
|
return content_class(content=content, metadata=metadata,
|
||||||
metadata=metadata,
|
settings=self.settings, source_path=path,
|
||||||
settings=settings,
|
context=context)
|
||||||
source_path=path,
|
|
||||||
context=context)
|
|
||||||
|
|
||||||
|
|
||||||
def default_metadata(settings=None, process=None):
|
def default_metadata(settings=None, process=None):
|
||||||
|
|
@ -482,7 +497,7 @@ def parse_path_metadata(source_path, settings=None, process=None):
|
||||||
... 'PATH_METADATA':
|
... 'PATH_METADATA':
|
||||||
... '(?P<category>[^/]*)/(?P<date>\d{4}-\d{2}-\d{2})/.*',
|
... '(?P<category>[^/]*)/(?P<date>\d{4}-\d{2}-\d{2})/.*',
|
||||||
... }
|
... }
|
||||||
>>> reader = Reader(settings=settings)
|
>>> reader = BaseReader(settings=settings)
|
||||||
>>> metadata = parse_path_metadata(
|
>>> metadata = parse_path_metadata(
|
||||||
... source_path='my-cat/2013-01-01/my-slug.html',
|
... source_path='my-cat/2013-01-01/my-slug.html',
|
||||||
... settings=settings,
|
... settings=settings,
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ DEFAULT_CONFIG = {
|
||||||
'PAGE_EXCLUDES': (),
|
'PAGE_EXCLUDES': (),
|
||||||
'THEME': DEFAULT_THEME,
|
'THEME': DEFAULT_THEME,
|
||||||
'OUTPUT_PATH': 'output',
|
'OUTPUT_PATH': 'output',
|
||||||
'MARKUP': ('rst', 'md'),
|
'READERS': {},
|
||||||
'STATIC_PATHS': ['images', ],
|
'STATIC_PATHS': ['images', ],
|
||||||
'THEME_STATIC_DIR': 'theme',
|
'THEME_STATIC_DIR': 'theme',
|
||||||
'THEME_STATIC_PATHS': ['static', ],
|
'THEME_STATIC_PATHS': ['static', ],
|
||||||
|
|
@ -112,6 +112,7 @@ DEFAULT_CONFIG = {
|
||||||
'SLUG_SUBSTITUTIONS': (),
|
'SLUG_SUBSTITUTIONS': (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def read_settings(path=None, override=None):
|
def read_settings(path=None, override=None):
|
||||||
if path:
|
if path:
|
||||||
local_settings = get_settings_from_file(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 \
|
if p in local_settings and local_settings[p] is not None \
|
||||||
and not isabs(local_settings[p]):
|
and not isabs(local_settings[p]):
|
||||||
absp = os.path.abspath(os.path.normpath(os.path.join(
|
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):
|
if p not in ('THEME', 'PLUGIN_PATH') or os.path.exists(absp):
|
||||||
local_settings[p] = absp
|
local_settings[p] = absp
|
||||||
else:
|
else:
|
||||||
|
|
@ -138,7 +139,7 @@ def get_settings_from_module(module=None, default_settings=DEFAULT_CONFIG):
|
||||||
context = copy.deepcopy(default_settings)
|
context = copy.deepcopy(default_settings)
|
||||||
if module is not None:
|
if module is not None:
|
||||||
context.update(
|
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
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -221,17 +222,18 @@ def configure_settings(settings):
|
||||||
settings['FEED_DOMAIN'] = settings['SITEURL']
|
settings['FEED_DOMAIN'] = settings['SITEURL']
|
||||||
|
|
||||||
# Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined
|
# Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined
|
||||||
feed_keys = ['FEED_ATOM', 'FEED_RSS',
|
feed_keys = [
|
||||||
'FEED_ALL_ATOM', 'FEED_ALL_RSS',
|
'FEED_ATOM', 'FEED_RSS',
|
||||||
'CATEGORY_FEED_ATOM', 'CATEGORY_FEED_RSS',
|
'FEED_ALL_ATOM', 'FEED_ALL_RSS',
|
||||||
'TAG_FEED_ATOM', 'TAG_FEED_RSS',
|
'CATEGORY_FEED_ATOM', 'CATEGORY_FEED_RSS',
|
||||||
'TRANSLATION_FEED_ATOM', 'TRANSLATION_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 any(settings.get(k) for k in feed_keys):
|
||||||
if not settings.get('SITEURL'):
|
if not settings.get('SITEURL'):
|
||||||
logger.warning('Feeds generated without SITEURL set properly may not'
|
logger.warning('Feeds generated without SITEURL set properly may'
|
||||||
' be valid')
|
' not be valid')
|
||||||
|
|
||||||
if not 'TIMEZONE' in settings:
|
if not 'TIMEZONE' in settings:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
|
@ -255,26 +257,26 @@ def configure_settings(settings):
|
||||||
|
|
||||||
# Save people from accidentally setting a string rather than a list
|
# Save people from accidentally setting a string rather than a list
|
||||||
path_keys = (
|
path_keys = (
|
||||||
'ARTICLE_EXCLUDES',
|
'ARTICLE_EXCLUDES',
|
||||||
'DEFAULT_METADATA',
|
'DEFAULT_METADATA',
|
||||||
'DIRECT_TEMPLATES',
|
'DIRECT_TEMPLATES',
|
||||||
'EXTRA_TEMPLATES_PATHS',
|
'EXTRA_TEMPLATES_PATHS',
|
||||||
'FILES_TO_COPY',
|
'FILES_TO_COPY',
|
||||||
'IGNORE_FILES',
|
'IGNORE_FILES',
|
||||||
'JINJA_EXTENSIONS',
|
'JINJA_EXTENSIONS',
|
||||||
'MARKUP',
|
'PAGINATED_DIRECT_TEMPLATES',
|
||||||
'PAGINATED_DIRECT_TEMPLATES',
|
'PLUGINS',
|
||||||
'PLUGINS',
|
'STATIC_PATHS',
|
||||||
'STATIC_PATHS',
|
'THEME_STATIC_PATHS',
|
||||||
'THEME_STATIC_PATHS',)
|
)
|
||||||
for PATH_KEY in filter(lambda k: k in settings, path_keys):
|
for PATH_KEY in filter(lambda k: k in settings, path_keys):
|
||||||
if isinstance(settings[PATH_KEY], six.string_types):
|
if isinstance(settings[PATH_KEY], six.string_types):
|
||||||
logger.warning("Detected misconfiguration with %s setting (must "
|
logger.warning("Detected misconfiguration with %s setting "
|
||||||
"be a list), falling back to the default"
|
"(must be a list), falling back to the default"
|
||||||
% PATH_KEY)
|
% PATH_KEY)
|
||||||
settings[PATH_KEY] = DEFAULT_CONFIG[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),
|
('LESS_GENERATOR', 'the Webassets plugin', None),
|
||||||
('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA',
|
('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA',
|
||||||
'https://github.com/getpelican/pelican/blob/master/docs/settings.rst#path-metadata'),
|
'https://github.com/getpelican/pelican/blob/master/docs/settings.rst#path-metadata'),
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ class TestGenerator(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.settings = get_settings()
|
self.settings = get_settings()
|
||||||
self.generator = Generator(self.settings.copy(), self.settings,
|
self.generator = Generator(self.settings.copy(), self.settings,
|
||||||
CUR_DIR, self.settings['THEME'], None,
|
CUR_DIR, self.settings['THEME'], None)
|
||||||
self.settings['MARKUP'])
|
|
||||||
|
|
||||||
def test_include_path(self):
|
def test_include_path(self):
|
||||||
filename = os.path.join(CUR_DIR, 'content', 'article.rst')
|
filename = os.path.join(CUR_DIR, 'content', 'article.rst')
|
||||||
|
|
@ -30,10 +29,6 @@ class TestGenerator(unittest.TestCase):
|
||||||
self.assertTrue(include_path(filename, extensions=('rst',)))
|
self.assertTrue(include_path(filename, extensions=('rst',)))
|
||||||
self.assertFalse(include_path(filename, extensions=('md',)))
|
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):
|
class TestArticlesGenerator(unittest.TestCase):
|
||||||
|
|
||||||
|
|
@ -45,8 +40,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
|
|
||||||
cls.generator = ArticlesGenerator(
|
cls.generator = ArticlesGenerator(
|
||||||
context=settings.copy(), settings=settings,
|
context=settings.copy(), settings=settings,
|
||||||
path=CONTENT_DIR, theme=settings['THEME'],
|
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=settings['MARKUP'])
|
|
||||||
cls.generator.generate_context()
|
cls.generator.generate_context()
|
||||||
cls.articles = [[page.title, page.status, page.category.name,
|
cls.articles = [[page.title, page.status, page.category.name,
|
||||||
page.template] for page in cls.generator.articles]
|
page.template] for page in cls.generator.articles]
|
||||||
|
|
@ -55,8 +49,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
generator = ArticlesGenerator(
|
generator = ArticlesGenerator(
|
||||||
context=settings, settings=settings,
|
context=settings, settings=settings,
|
||||||
path=None, theme=settings['THEME'],
|
path=None, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=settings['MARKUP'])
|
|
||||||
writer = MagicMock()
|
writer = MagicMock()
|
||||||
generator.generate_feeds(writer)
|
generator.generate_feeds(writer)
|
||||||
writer.write_feed.assert_called_with([], settings,
|
writer.write_feed.assert_called_with([], settings,
|
||||||
|
|
@ -64,8 +57,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
|
|
||||||
generator = ArticlesGenerator(
|
generator = ArticlesGenerator(
|
||||||
context=settings, settings=get_settings(FEED_ALL_ATOM=None),
|
context=settings, settings=get_settings(FEED_ALL_ATOM=None),
|
||||||
path=None, theme=settings['THEME'],
|
path=None, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=None)
|
|
||||||
writer = MagicMock()
|
writer = MagicMock()
|
||||||
generator.generate_feeds(writer)
|
generator.generate_feeds(writer)
|
||||||
self.assertFalse(writer.write_feed.called)
|
self.assertFalse(writer.write_feed.called)
|
||||||
|
|
@ -74,26 +66,33 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
|
|
||||||
articles_expected = [
|
articles_expected = [
|
||||||
['Article title', 'published', 'Default', 'article'],
|
['Article title', 'published', 'Default', 'article'],
|
||||||
['Article with markdown and summary metadata single', 'published',
|
|
||||||
'Default', 'article'],
|
|
||||||
['Article with markdown and summary metadata multi', 'published',
|
['Article with markdown and summary metadata multi', 'published',
|
||||||
'Default', 'article'],
|
'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'],
|
['Article with template', 'published', 'Default', 'custom'],
|
||||||
['Test md File', 'published', 'test', 'article'],
|
|
||||||
['Rst with filename metadata', 'published', 'yeah', 'article'],
|
['Rst with filename metadata', 'published', 'yeah', 'article'],
|
||||||
['Test Markdown extensions', 'published', 'Default', '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', 'yeah', 'article'],
|
||||||
|
['This is a super article !', 'published', 'Default', 'article'],
|
||||||
['This is an article with category !', 'published', 'yeah',
|
['This is an article with category !', 'published', 'yeah',
|
||||||
'article'],
|
'article'],
|
||||||
['This is an article without category !', 'published', 'Default',
|
['This is an article without category !', 'published', 'Default',
|
||||||
'article'],
|
'article'],
|
||||||
['This is an article without category !', 'published',
|
['This is an article without category !', 'published',
|
||||||
'TestCategory', 'article'],
|
'TestCategory', 'article'],
|
||||||
['This is a super article !', 'published', 'yeah', 'article'],
|
['マックOS X 10.8でパイソンとVirtualenvをインストールと設定', 'published',
|
||||||
['マックOS X 10.8でパイソンとVirtualenvをインストールと設定',
|
'指導書', 'article'],
|
||||||
'published', '指導書', 'article'],
|
|
||||||
['Article with markdown containing footnotes', 'published',
|
|
||||||
'Default', 'article']
|
|
||||||
]
|
]
|
||||||
self.assertEqual(sorted(articles_expected), sorted(self.articles))
|
self.assertEqual(sorted(articles_expected), sorted(self.articles))
|
||||||
|
|
||||||
|
|
@ -124,8 +123,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
settings['filenames'] = {}
|
settings['filenames'] = {}
|
||||||
generator = ArticlesGenerator(
|
generator = ArticlesGenerator(
|
||||||
context=settings.copy(), settings=settings,
|
context=settings.copy(), settings=settings,
|
||||||
path=CONTENT_DIR, theme=settings['THEME'],
|
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=settings['MARKUP'])
|
|
||||||
generator.generate_context()
|
generator.generate_context()
|
||||||
# test for name
|
# test for name
|
||||||
# categories are grouped by slug; if two categories have the same slug
|
# categories are grouped by slug; if two categories have the same slug
|
||||||
|
|
@ -147,8 +145,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
settings = get_settings(filenames={})
|
settings = get_settings(filenames={})
|
||||||
generator = ArticlesGenerator(
|
generator = ArticlesGenerator(
|
||||||
context=settings, settings=settings,
|
context=settings, settings=settings,
|
||||||
path=None, theme=settings['THEME'],
|
path=None, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=settings['MARKUP'])
|
|
||||||
write = MagicMock()
|
write = MagicMock()
|
||||||
generator.generate_direct_templates(write)
|
generator.generate_direct_templates(write)
|
||||||
write.assert_called_with("archives.html",
|
write.assert_called_with("archives.html",
|
||||||
|
|
@ -162,8 +159,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
|
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
|
||||||
generator = ArticlesGenerator(
|
generator = ArticlesGenerator(
|
||||||
context=settings, settings=settings,
|
context=settings, settings=settings,
|
||||||
path=None, theme=settings['THEME'],
|
path=None, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=settings['MARKUP'])
|
|
||||||
write = MagicMock()
|
write = MagicMock()
|
||||||
generator.generate_direct_templates(write)
|
generator.generate_direct_templates(write)
|
||||||
write.assert_called_with("archives/index.html",
|
write.assert_called_with("archives/index.html",
|
||||||
|
|
@ -178,8 +174,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
|
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
|
||||||
generator = ArticlesGenerator(
|
generator = ArticlesGenerator(
|
||||||
context=settings, settings=settings,
|
context=settings, settings=settings,
|
||||||
path=None, theme=settings['THEME'],
|
path=None, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=settings['MARKUP'])
|
|
||||||
write = MagicMock()
|
write = MagicMock()
|
||||||
generator.generate_direct_templates(write)
|
generator.generate_direct_templates(write)
|
||||||
write.assert_called_count == 0
|
write.assert_called_count == 0
|
||||||
|
|
@ -212,8 +207,7 @@ class TestPageGenerator(unittest.TestCase):
|
||||||
|
|
||||||
generator = PagesGenerator(
|
generator = PagesGenerator(
|
||||||
context=settings.copy(), settings=settings,
|
context=settings.copy(), settings=settings,
|
||||||
path=CUR_DIR, theme=settings['THEME'],
|
path=CUR_DIR, theme=settings['THEME'], output_path=None)
|
||||||
output_path=None, markup=settings['MARKUP'])
|
|
||||||
generator.generate_context()
|
generator.generate_context()
|
||||||
pages = self.distill_pages(generator.pages)
|
pages = self.distill_pages(generator.pages)
|
||||||
hidden_pages = self.distill_pages(generator.hidden_pages)
|
hidden_pages = self.distill_pages(generator.hidden_pages)
|
||||||
|
|
@ -252,13 +246,12 @@ class TestTemplatePagesGenerator(unittest.TestCase):
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
settings['STATIC_PATHS'] = ['static']
|
settings['STATIC_PATHS'] = ['static']
|
||||||
settings['TEMPLATE_PAGES'] = {
|
settings['TEMPLATE_PAGES'] = {
|
||||||
'template/source.html': 'generated/file.html'
|
'template/source.html': 'generated/file.html'
|
||||||
}
|
}
|
||||||
|
|
||||||
generator = TemplatePagesGenerator(
|
generator = TemplatePagesGenerator(
|
||||||
context={'foo': 'bar'}, settings=settings,
|
context={'foo': 'bar'}, settings=settings,
|
||||||
path=self.temp_content, theme='',
|
path=self.temp_content, theme='', output_path=self.temp_output)
|
||||||
output_path=self.temp_output, markup=None)
|
|
||||||
|
|
||||||
# create a dummy template file
|
# create a dummy template file
|
||||||
template_dir = os.path.join(self.temp_content, 'template')
|
template_dir = os.path.join(self.temp_content, 'template')
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ class ReaderTest(unittest.TestCase):
|
||||||
|
|
||||||
def read_file(self, path, **kwargs):
|
def read_file(self, path, **kwargs):
|
||||||
# Isolate from future API changes to readers.read_file
|
# Isolate from future API changes to readers.read_file
|
||||||
return readers.read_file(
|
r = readers.Readers(settings=get_settings(**kwargs))
|
||||||
base_path=CONTENT_PATH, path=path, settings=get_settings(**kwargs))
|
return r.read_file(base_path=CONTENT_PATH, path=path)
|
||||||
|
|
||||||
|
|
||||||
class RstReaderTest(ReaderTest):
|
class RstReaderTest(ReaderTest):
|
||||||
|
|
@ -160,7 +160,7 @@ class MdReaderTest(ReaderTest):
|
||||||
' with some footnotes'
|
' with some footnotes'
|
||||||
'<sup id="fnref:footnote"><a class="footnote-ref" '
|
'<sup id="fnref:footnote"><a class="footnote-ref" '
|
||||||
'href="#fn:footnote" rel="footnote">2</a></sup></p>\n'
|
'href="#fn:footnote" rel="footnote">2</a></sup></p>\n'
|
||||||
|
|
||||||
'<div class="footnote">\n'
|
'<div class="footnote">\n'
|
||||||
'<hr />\n<ol>\n<li id="fn:1">\n'
|
'<hr />\n<ol>\n<li id="fn:1">\n'
|
||||||
'<p>Numbered footnote '
|
'<p>Numbered footnote '
|
||||||
|
|
|
||||||
|
|
@ -353,12 +353,13 @@ class TestDateFormatter(unittest.TestCase):
|
||||||
'French locale needed')
|
'French locale needed')
|
||||||
def test_french_locale(self):
|
def test_french_locale(self):
|
||||||
settings = read_settings(
|
settings = read_settings(
|
||||||
override = {'LOCALE': locale.normalize('fr_FR.UTF-8'),
|
override={'LOCALE': locale.normalize('fr_FR.UTF-8'),
|
||||||
'TEMPLATE_PAGES': {'template/source.html':
|
'TEMPLATE_PAGES': {'template/source.html':
|
||||||
'generated/file.html'}})
|
'generated/file.html'}})
|
||||||
|
|
||||||
generator = TemplatePagesGenerator({'date': self.date}, settings,
|
generator = TemplatePagesGenerator(
|
||||||
self.temp_content, '', self.temp_output, None)
|
{'date': self.date}, settings,
|
||||||
|
self.temp_content, '', self.temp_output)
|
||||||
generator.env.filters.update({'strftime': utils.DateFormatter()})
|
generator.env.filters.update({'strftime': utils.DateFormatter()})
|
||||||
|
|
||||||
writer = Writer(self.temp_output, settings=settings)
|
writer = Writer(self.temp_output, settings=settings)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue