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:
parent
db027929b5
commit
50af2ed45d
8 changed files with 134 additions and 17 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
4
pelican/tests/theme_overrides/level1/article.html
Normal file
4
pelican/tests/theme_overrides/level1/article.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<!--
|
||||
This file is only here to test the `THEME_TEMPLATES_OVERRIDES` configuration
|
||||
setting.
|
||||
-->
|
||||
4
pelican/tests/theme_overrides/level2/article.html
Normal file
4
pelican/tests/theme_overrides/level2/article.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<!--
|
||||
This file is only here to test the `THEME_TEMPLATES_OVERRIDES` configuration
|
||||
setting.
|
||||
-->
|
||||
4
pelican/tests/theme_overrides/level2/authors.html
Normal file
4
pelican/tests/theme_overrides/level2/authors.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<!--
|
||||
This file is only here to test the `THEME_TEMPLATES_OVERRIDES` configuration
|
||||
setting.
|
||||
-->
|
||||
Loading…
Add table
Add a link
Reference in a new issue