1
0
Fork 0
forked from github/pelican

Add THEME_TEMPLATE_OVERRIDES. Refs 2021

Allow for overriding individual templates from the theme by configuring
the Jinja2 `Environment` loader to search for templates in the
`THEME_TEMPLATES_OVERRIDES` path before the theme's `templates/`
directory.
This commit is contained in:
Pedro H 2016-10-16 15:47:22 +08:00
commit 50af2ed45d
8 changed files with 134 additions and 17 deletions

View file

@ -706,16 +706,13 @@ Template pages
tags and category index pages). If the tag and category collections are not
needed, set ``DIRECT_TEMPLATES = ['index', 'archives']``
``DIRECT_TEMPLATES`` are searched for over paths maintained in
``THEME_TEMPLATES_OVERRIDES``.
.. data:: PAGINATED_DIRECT_TEMPLATES = ['index']
Provides the direct templates that should be paginated.
.. data:: EXTRA_TEMPLATES_PATHS = []
A list of paths you want Jinja2 to search for templates. Can be used to
separate templates from the theme. Example: projects, resume, profile ...
These templates need to use ``DIRECT_TEMPLATES`` setting.
Metadata
========
@ -1011,6 +1008,21 @@ However, here are the settings that are related to themes.
with the same names are included in the paths defined in this settings, they
will be progressively overwritten.
.. data:: THEME_TEMPLATES_OVERRIDES = []
A list of paths you want Jinja2 to search for templates before searching the
theme's ``templates/`` directory. Allows for overriding individual theme
template files without having to fork an existing theme. Jinja2 searches in
the following order: files in ``THEME_TEMPLATES_OVERRIDES`` first, then the
theme's ``templates/``.
You can also extend templates from the theme using the ``{% extends %}``
directive utilizing the ``!theme`` prefix as shown in the following example:
.. parsed-literal::
{% extends '!theme/article.html' %}
.. data:: CSS_FILE = 'main.css'
Specify the CSS file you want to load.

View file

@ -51,20 +51,25 @@ class Generator(object):
# templates cache
self._templates = {}
self._templates_path = []
self._templates_path.append(os.path.expanduser(
os.path.join(self.theme, 'templates')))
self._templates_path += self.settings['EXTRA_TEMPLATES_PATHS']
self._templates_path = list(self.settings['THEME_TEMPLATES_OVERRIDES'])
theme_path = os.path.dirname(os.path.abspath(__file__))
theme_templates_path = os.path.expanduser(
os.path.join(self.theme, 'templates'))
self._templates_path.append(theme_templates_path)
theme_loader = FileSystemLoader(theme_templates_path)
simple_theme_path = os.path.dirname(os.path.abspath(__file__))
simple_loader = FileSystemLoader(
os.path.join(simple_theme_path, "themes", "simple", "templates"))
simple_loader = FileSystemLoader(os.path.join(theme_path,
"themes", "simple", "templates"))
self.env = Environment(
loader=ChoiceLoader([
FileSystemLoader(self._templates_path),
simple_loader, # implicit inheritance
PrefixLoader({'!simple': simple_loader}) # explicit one
PrefixLoader({
'!simple': simple_loader,
'!theme': theme_loader
}) # explicit ones
]),
**self.settings['JINJA_ENVIRONMENT']
)

View file

@ -99,7 +99,7 @@ DEFAULT_CONFIG = {
'RELATIVE_URLS': False,
'DEFAULT_LANG': 'en',
'DIRECT_TEMPLATES': ['index', 'tags', 'categories', 'authors', 'archives'],
'EXTRA_TEMPLATES_PATHS': [],
'THEME_TEMPLATES_OVERRIDES': [],
'PAGINATED_DIRECT_TEMPLATES': ['index'],
'PELICAN_CLASS': 'pelican.Pelican',
'DEFAULT_DATE_FORMAT': '%a %d %B %Y',
@ -376,12 +376,26 @@ def configure_settings(settings):
settings[new_key] = [settings[old_key]] # also make a list
del settings[old_key]
# Deprecated warning of EXTRA_TEMPLATES_PATHS
if 'EXTRA_TEMPLATES_PATHS' in settings:
logger.warning('EXTRA_TEMPLATES_PATHS is deprecated use '
'THEME_TEMPLATES_OVERRIDES instead.')
if ('THEME_TEMPLATES_OVERRIDES' in settings and
settings['THEME_TEMPLATES_OVERRIDES']):
raise Exception(
'Setting both EXTRA_TEMPLATES_PATHS and '
'THEME_TEMPLATES_OVERRIDES is not permitted. Please move to '
'only setting THEME_TEMPLATES_OVERRIDES.')
settings['THEME_TEMPLATES_OVERRIDES'] = \
settings['EXTRA_TEMPLATES_PATHS']
del settings['EXTRA_TEMPLATES_PATHS']
# Save people from accidentally setting a string rather than a list
path_keys = (
'ARTICLE_EXCLUDES',
'DEFAULT_METADATA',
'DIRECT_TEMPLATES',
'EXTRA_TEMPLATES_PATHS',
'THEME_TEMPLATES_OVERRIDES',
'FILES_TO_COPY',
'IGNORE_FILES',
'PAGINATED_DIRECT_TEMPLATES',

View file

@ -9,7 +9,8 @@ from shutil import copy, rmtree
from tempfile import mkdtemp
from pelican.generators import (ArticlesGenerator, Generator, PagesGenerator,
StaticGenerator, TemplatePagesGenerator)
PelicanTemplateNotFound, StaticGenerator,
TemplatePagesGenerator)
from pelican.tests.support import get_settings, unittest
from pelican.writers import Writer
@ -117,6 +118,62 @@ class TestGenerator(unittest.TestCase):
self.assertEqual(comment_end_string,
generator.env.comment_end_string)
def test_theme_overrides(self):
"""
Test that the THEME_TEMPLATES_OVERRIDES configuration setting is
utilized correctly in the Generator.
"""
override_dirs = (os.path.join(CUR_DIR, 'theme_overrides', 'level1'),
os.path.join(CUR_DIR, 'theme_overrides', 'level2'))
self.settings['THEME_TEMPLATES_OVERRIDES'] = override_dirs
generator = Generator(
context=self.settings.copy(),
settings=self.settings,
path=CUR_DIR,
theme=self.settings['THEME'],
output_path=None)
filename = generator.get_template('article').filename
self.assertEqual(override_dirs[0], os.path.dirname(filename))
self.assertEqual('article.html', os.path.basename(filename))
filename = generator.get_template('authors').filename
self.assertEqual(override_dirs[1], os.path.dirname(filename))
self.assertEqual('authors.html', os.path.basename(filename))
filename = generator.get_template('taglist').filename
self.assertEqual(os.path.join(self.settings['THEME'], 'templates'),
os.path.dirname(filename))
self.assertNotIn(os.path.dirname(filename), override_dirs)
self.assertEqual('taglist.html', os.path.basename(filename))
def test_simple_prefix(self):
"""
Test `!simple` theme prefix.
"""
filename = self.generator.get_template('!simple/authors').filename
expected_path = os.path.join(
os.path.dirname(CUR_DIR), 'themes', 'simple', 'templates')
self.assertEqual(expected_path, os.path.dirname(filename))
self.assertEqual('authors.html', os.path.basename(filename))
def test_theme_prefix(self):
"""
Test `!theme` theme prefix.
"""
filename = self.generator.get_template('!theme/authors').filename
expected_path = os.path.join(
os.path.dirname(CUR_DIR), 'themes', 'notmyidea', 'templates')
self.assertEqual(expected_path, os.path.dirname(filename))
self.assertEqual('authors.html', os.path.basename(filename))
def test_bad_prefix(self):
"""
Test unknown/bad theme prefix throws exception.
"""
self.assertRaises(PelicanTemplateNotFound, self.generator.get_template,
'!UNKNOWN/authors')
class TestArticlesGenerator(unittest.TestCase):

View file

@ -166,3 +166,20 @@ class TestSettingsConfiguration(unittest.TestCase):
settings['THEME'] = 'foo'
self.assertRaises(Exception, configure_settings, settings)
def test_deprecated_extra_templates_paths(self):
settings = self.settings
settings['EXTRA_TEMPLATES_PATHS'] = ['/foo/bar', '/ha']
configure_settings(settings)
self.assertEqual(settings['THEME_TEMPLATES_OVERRIDES'],
['/foo/bar', '/ha'])
self.assertNotIn('EXTRA_TEMPLATES_PATHS', settings)
def test_theme_and_extra_templates_exception(self):
settings = self.settings
settings['EXTRA_TEMPLATES_PATHS'] = ['/ha']
settings['THEME_TEMPLATES_OVERRIDES'] = ['/foo/bar']
self.assertRaises(Exception, configure_settings, settings)

View file

@ -0,0 +1,4 @@
<!--
This file is only here to test the `THEME_TEMPLATES_OVERRIDES` configuration
setting.
-->

View file

@ -0,0 +1,4 @@
<!--
This file is only here to test the `THEME_TEMPLATES_OVERRIDES` configuration
setting.
-->

View file

@ -0,0 +1,4 @@
<!--
This file is only here to test the `THEME_TEMPLATES_OVERRIDES` configuration
setting.
-->