Support and prefer `.jinja to _t` for static templates (#11165)

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
James Addison 2023-04-07 18:07:15 +01:00 committed by GitHub
parent f82c3c9912
commit 5d13215b58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 298 additions and 59 deletions

View File

@ -23,6 +23,11 @@ Deprecated
----------
* #11247: Deprecate the legacy ``intersphinx_mapping`` format
* #11165: Warn when the ``_t`` suffix is used for template files. The formal
deprecation process will begin no earlier than 31 December 2024.
Templates should change to use the ``.jinja`` filename suffix instead.
For more information, see :ref:`theming-static-templates`.
Patch by James Addison and Adam Turner
Features added
--------------
@ -60,6 +65,10 @@ Features added
``= 'xelatex'``. Patch by Dimitar Dimitrov
* #11109, #9643: Add :confval:`python_display_short_literal_types` option for
condensed rendering of ``Literal`` types.
* #11165: Support the `officially recommended`_ ``.jinja`` suffix for template
files. Patch by James Addison
.. _officially recommended: https://jinja.palletsprojects.com/en/latest/templates/#template-file-extension
Bugs fixed
----------

View File

@ -156,13 +156,51 @@ template static files as well as HTML files. Therefore, Sphinx supports
so-called "static templates", like this:
If the name of a file in the ``static/`` directory of a theme (or in the user's
static path, for that matter) ends with ``_t``, it will be processed by the
template engine. The ``_t`` will be left from the final file name. For
example, the *classic* theme has a file ``static/classic.css_t`` which uses
templating to put the color options into the stylesheet. When a documentation
static path, for that matter) ends with ``.jinja``, it will be processed by the
template engine. The ``.jinja`` will be removed from the final file name. For
example, the *classic* theme has a file ``static/classic.css.jinja`` which uses
templating to put the colour options into the stylesheet. When a documentation
is built with the classic theme, the output directory will contain a
``_static/classic.css`` file where all template tags have been processed.
.. versionchanged:: 6.2
The preferred suffix for static templates is now ``.jinja``, in line with
the Jinja project's `recommended file extension`_.
The ``_t`` file suffix for static templates is now considered 'legacy', and
support will eventually be removed. The standard deprecation process will
begin no earlier than 31 December 2024, at which point using ``_t`` suffixes
will emit ``RemovedInSphinx__Warning`` warnings.
If a static template with a ``_t`` suffix is detected, it will be processed
by the template engine, with the ``_t`` suffix removed from the final file
name.
To silence the warning for ``_t`` suffixes, the new
``sphinx.deprecation.OldJinjaSuffixWarning`` class has been added for use
with Python's standard `warning control`_ mechanisms. This class will be
removed no earlier than 31 December 2024, so guard any imports with a
try/except block.
For example, in a ``setup()`` function:
.. code:: python
import warnings
def setup(app):
try:
from sphinx.deprecation import OldJinjaSuffixWarning
except ImportError:
pass # Only silence the warning if it exists!
else:
warnings.filterwarnings('ignore', category=OldJinjaSuffixWarning)
...
.. _recommended file extension: https://jinja.palletsprojects.com/en/latest/templates/#template-file-extension
.. _warning control: https://docs.python.org/3/library/warnings.html#the-warnings-filter
Use custom page metadata in HTML templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1811,12 +1811,12 @@ Miscellany
.. hint::
As an experimental feature, Sphinx can use user-defined template file for
LaTeX source if you have a file named ``_templates/latex.tex_t`` in your
LaTeX source if you have a file named ``_templates/latex.tex.jinja`` in your
project.
Additional files ``longtable.tex_t``, ``tabulary.tex_t`` and
``tabular.tex_t`` can be added to ``_templates/`` to configure some aspects
of table rendering (such as the caption position).
Additional files ``longtable.tex.jinja``, ``tabulary.tex.jinja`` and
``tabular.tex.jinja`` can be added to ``_templates/`` to configure some
aspects of table rendering (such as the caption position).
.. versionadded:: 1.6
currently all template variables are unstable and undocumented.

View File

@ -603,7 +603,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
html.escape(self.refnodes[0]['refuri'])))
# write the project file
copy_asset_file(path.join(self.template_dir, 'content.opf_t'), self.outdir, metadata)
content_t = path.join(self.template_dir, 'content.opf.jinja')
copy_asset_file(content_t, self.outdir, metadata)
def new_navpoint(self, node: dict[str, Any], level: int, incr: bool = True) -> NavPoint:
"""Create a new entry in the toc from the node at given level."""
@ -686,7 +687,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
navpoints = self.build_navpoints(refnodes)
level = max(item['level'] for item in self.refnodes)
level = min(level, self.config.epub_tocdepth)
copy_asset_file(path.join(self.template_dir, 'toc.ncx_t'), self.outdir,
copy_asset_file(path.join(self.template_dir, 'toc.ncx.jinja'), self.outdir,
self.toc_metadata(level, navpoints))
def build_epub(self) -> None:

View File

@ -133,10 +133,10 @@ class ChangesBuilder(Builder):
f.write(self.templates.render('changes/rstsource.html', ctx))
themectx = {'theme_' + key: val for (key, val) in
self.theme.get_options({}).items()}
copy_asset_file(path.join(package_dir, 'themes', 'default', 'static', 'default.css_t'),
self.outdir, context=themectx, renderer=self.templates)
copy_asset_file(path.join(package_dir, 'themes', 'basic', 'static', 'basic.css'),
self.outdir)
default_t = path.join(package_dir, 'themes', 'default', 'static', 'default.css.jinja')
copy_asset_file(default_t, self.outdir, context=themectx, renderer=self.templates)
basic = path.join(package_dir, 'themes', 'basic', 'static', 'basic.css')
copy_asset_file(basic, self.outdir)
def hl(self, text: str, version: str) -> str:
text = html.escape(text)

View File

@ -184,7 +184,7 @@ class Epub3Builder(_epub_base.EpubBuilder):
# 'includehidden'
refnodes = self.refnodes
navlist = self.build_navlist(refnodes)
copy_asset_file(path.join(self.template_dir, 'nav.xhtml_t'), self.outdir,
copy_asset_file(path.join(self.template_dir, 'nav.xhtml.jinja'), self.outdir,
self.navigation_doc_metadata(navlist))
# Add nav.xhtml to epub file

View File

@ -283,7 +283,7 @@ class MessageCatalogBuilder(I18nBuilder):
ensuredir(path.join(self.outdir, path.dirname(textdomain)))
context['messages'] = list(catalog)
content = GettextRenderer(outdir=self.outdir).render('message.pot_t', context)
content = GettextRenderer(outdir=self.outdir).render('message.pot.jinja', context)
pofn = path.join(self.outdir, textdomain + '.pot')
if should_write(pofn, content):

View File

@ -402,7 +402,7 @@ class LaTeXBuilder(Builder):
# use pre-1.6.x Makefile for make latexpdf on Windows
if os.name == 'nt':
staticdirname = path.join(package_dir, 'texinputs_win')
copy_asset_file(path.join(staticdirname, 'Makefile_t'),
copy_asset_file(path.join(staticdirname, 'Makefile.jinja'),
self.outdir, context=context)
@progress_message(__('copying additional files'))
@ -441,7 +441,7 @@ class LaTeXBuilder(Builder):
if self.context['babel'] or self.context['polyglossia']:
context['addtocaptions'] = r'\addto\captions%s' % self.babel.get_language()
filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty_t')
filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty.jinja')
copy_asset_file(filename, self.outdir, context=context, renderer=LaTeXRenderer())

View File

@ -370,29 +370,29 @@ def generate(
if 'quiet' not in d:
print(__('File %s already exists, skipping.') % fpath)
conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None
conf_path = os.path.join(templatedir, 'conf.py.jinja') if templatedir else None
if not conf_path or not path.isfile(conf_path):
conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t')
conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py.jinja')
with open(conf_path, encoding="utf-8") as f:
conf_text = f.read()
write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d))
masterfile = path.join(srcdir, d['master'] + d['suffix'])
if template._has_custom_template('quickstart/master_doc.rst_t'):
if template._has_custom_template('quickstart/master_doc.rst.jinja'):
msg = ('A custom template `master_doc.rst_t` found. It has been renamed to '
'`root_doc.rst_t`. Please rename it on your project too.')
print(colorize('red', msg))
write_file(masterfile, template.render('quickstart/master_doc.rst_t', d))
write_file(masterfile, template.render('quickstart/master_doc.rst.jinja', d))
else:
write_file(masterfile, template.render('quickstart/root_doc.rst_t', d))
write_file(masterfile, template.render('quickstart/root_doc.rst.jinja', d))
if d.get('make_mode') is True:
makefile_template = 'quickstart/Makefile.new_t'
batchfile_template = 'quickstart/make.bat.new_t'
makefile_template = 'quickstart/Makefile.new.jinja'
batchfile_template = 'quickstart/make.bat.new.jinja'
else:
makefile_template = 'quickstart/Makefile_t'
batchfile_template = 'quickstart/make.bat_t'
makefile_template = 'quickstart/Makefile.jinja'
batchfile_template = 'quickstart/make.bat.jinja'
if d['makefile'] is True:
d['rsrcdir'] = 'source' if d['sep'] else '.'

View File

@ -62,3 +62,31 @@ def _deprecation_warning(
warnings.warn(message + " Check CHANGES for Sphinx API modifications.",
warning_class, stacklevel=3)
class OldJinjaSuffixWarning(PendingDeprecationWarning):
"""Warning class for ``_old_jinja_template_suffix_warning``.
This class exists only so that extensions and themes can silence the legacy
filename warning via Python's `warning control`_ mechanisms. See
:ref:`theming-static-templates` for an example.
This warning class will be removed, and the warning class changed to the
appropriate RemovedInSphinx_0Warning no earlier than 31 December 2024, at
which point the standard deprecation process for ``_t`` template suffixes
will start.
.. _warning control: https://docs.python.org/3/library/warnings.html#the-warnings-filter
"""
def _old_jinja_template_suffix_warning(filename: str) -> None:
if filename.endswith('_t'):
warnings.warn(
f"{filename!r}: the '_t' suffix for Jinja templates is deprecated. "
"If the file is a template, use the suffix '.jinja' instead. "
'For more information, see '
'https://www.sphinx-doc.org/en/master/development/theming.html#static-templates',
OldJinjaSuffixWarning,
stacklevel=3,
)

View File

@ -102,7 +102,7 @@ def create_module_file(package: str, basename: str, opts: Any,
'qualname': qualname,
'automodule_options': options,
}
text = ReSTRenderer([user_template_dir, template_dir]).render('module.rst_t', context)
text = ReSTRenderer([user_template_dir, template_dir]).render('module.rst.jinja', context)
write_file(qualname, text, opts)
@ -138,7 +138,8 @@ def create_package_file(root: str, master_package: str, subroot: str, py_files:
'show_headings': not opts.noheadings,
'maxdepth': opts.maxdepth,
}
text = ReSTRenderer([user_template_dir, template_dir]).render('package.rst_t', context)
engine = ReSTRenderer([user_template_dir, template_dir])
text = engine.render('package.rst.jinja', context)
write_file(pkgname, text, opts)
if submodules and opts.separatemodules:
@ -163,7 +164,7 @@ def create_modules_toc_file(modules: list[str], opts: Any, name: str = 'modules'
'maxdepth': opts.maxdepth,
'docnames': modules,
}
text = ReSTRenderer([user_template_dir, template_dir]).render('toc.rst_t', context)
text = ReSTRenderer([user_template_dir, template_dir]).render('toc.rst.jinja', context)
write_file(name, text, opts)

View File

@ -19,6 +19,7 @@ from sphinx import package_dir
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.config import Config
from sphinx.deprecation import _old_jinja_template_suffix_warning
from sphinx.errors import SphinxError
from sphinx.locale import _, __
from sphinx.util import logging, sha1
@ -95,16 +96,20 @@ def generate_latex_macro(image_format: str,
}
if config.imgmath_use_preview:
template_name = 'preview.tex_t'
template_name = 'preview.tex'
else:
template_name = 'template.tex_t'
template_name = 'template.tex'
for template_dir in config.templates_path:
template = path.join(confdir, template_dir, template_name)
if path.exists(template):
return LaTeXRenderer().render(template, variables)
# TODO: deprecate '_t' template suffix support after 2024-12-31
for template_suffix in ('_t', '.jinja'):
template = path.join(confdir, template_dir, template_name + template_suffix)
if path.exists(template):
_old_jinja_template_suffix_warning(template)
return LaTeXRenderer().render(template, variables)
return LaTeXRenderer(templates_path).render(template_name, variables)
# Default: fallback to a pathless in-library jinja template
return LaTeXRenderer(templates_path).render(f"{template_name}.jinja", variables)
def ensure_tempdir(builder: Builder) -> str:

View File

@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Callable
from docutils.utils import relative_path
from sphinx.deprecation import _old_jinja_template_suffix_warning
from sphinx.util.osutil import copyfile, ensuredir
from sphinx.util.typing import PathMatcher
@ -15,6 +16,19 @@ if TYPE_CHECKING:
from sphinx.util.template import BaseRenderer
def _template_basename(filename: str) -> str | None:
"""Given an input filename:
If the input looks like a template, then return the filename output should
be written to. Otherwise, return no result (None)."""
# TODO: deprecate '_t' template suffix support after 2024-12-31
if filename.lower().endswith('_t'):
_old_jinja_template_suffix_warning(filename)
return filename[:-2]
elif filename.lower().endswith(".jinja"):
return filename[:-6]
return None
def copy_asset_file(source: str, destination: str,
context: dict | None = None,
renderer: BaseRenderer | None = None) -> None:
@ -35,14 +49,13 @@ def copy_asset_file(source: str, destination: str,
# Use source filename if destination points a directory
destination = os.path.join(destination, os.path.basename(source))
if source.lower().endswith('_t') and context is not None:
if _template_basename(source) and context is not None:
if renderer is None:
from sphinx.util.template import SphinxRenderer
renderer = SphinxRenderer()
with open(source, encoding='utf-8') as fsrc:
if destination.lower().endswith('_t'):
destination = destination[:-2]
destination = _template_basename(destination) or destination
with open(destination, 'w', encoding='utf-8') as fdst:
fdst.write(renderer.render_string(fsrc.read(), context))
else:

View File

@ -16,7 +16,7 @@ from docutils import nodes, writers
from docutils.nodes import Element, Node, Text
from sphinx import addnodes, highlighting
from sphinx.deprecation import RemovedInSphinx70Warning
from sphinx.deprecation import RemovedInSphinx70Warning, _old_jinja_template_suffix_warning
from sphinx.domains import IndexEntry
from sphinx.domains.std import StandardDomain
from sphinx.errors import SphinxError
@ -435,7 +435,8 @@ class LaTeXTranslator(SphinxTranslator):
'body': ''.join(self.body),
'indices': self.generate_indices(),
})
return self.render('latex.tex_t', self.elements)
template = self._find_template('latex.tex')
return self.render(template, self.elements)
def hypertarget(self, id: str, withdoc: bool = True, anchor: bool = True) -> str:
if withdoc:
@ -512,14 +513,21 @@ class LaTeXTranslator(SphinxTranslator):
return ''.join(ret)
def _find_template(self, template_name: str) -> str:
for template_dir in self.config.templates_path:
# TODO: deprecate '_t' template suffix support after 2024-12-31
for template_suffix in ('_t', '.jinja'):
template = path.join(self.builder.confdir, template_dir,
template_name + template_suffix)
if path.exists(template):
_old_jinja_template_suffix_warning(template)
return template
# Default: fallback to a pathless in-library jinja template
return f"{template_name}.jinja"
def render(self, template_name: str, variables: dict[str, Any]) -> str:
renderer = LaTeXRenderer(latex_engine=self.config.latex_engine)
for template_dir in self.config.templates_path:
template = path.join(self.builder.confdir, template_dir,
template_name)
if path.exists(template):
return renderer.render(template, variables)
return renderer.render(template_name, variables)
@property
@ -902,8 +910,8 @@ class LaTeXTranslator(SphinxTranslator):
def depart_table(self, node: Element) -> None:
labels = self.hypertarget_to(node)
table_type = self.table.get_table_type()
table = self.render(table_type + '.tex_t',
{'table': self.table, 'labels': labels})
template = self._find_template(f"{table_type}.tex")
table = self.render(template, {'table': self.table, 'labels': labels})
self.body.append(BLANKLINE)
self.body.append(table)
self.body.append(CR)

View File

@ -0,0 +1,2 @@
<# TODO: deprecate '_t' template suffix support after 2024-12-31 #>
AU REVOIR, KANIGGETS

View File

@ -1153,7 +1153,7 @@ def test_html_assets(app):
# html_extra_path
assert (app.outdir / '.htaccess').exists()
assert not (app.outdir / '.htpasswd').exists()
assert (app.outdir / 'API.html_t').exists()
assert (app.outdir / 'API.html.jinja').exists()
assert (app.outdir / 'css/style.css').exists()
assert (app.outdir / 'rimg.png').exists()
assert not (app.outdir / '_build' / 'index.html').exists()

View File

@ -1379,6 +1379,10 @@ def test_latex_table_custom_template_caseA(app, status, warning):
result = (app.outdir / 'python.tex').read_text(encoding='utf8')
assert 'SALUT LES COPAINS' in result
# # TODO: deprecate '_t' template suffix support after 2024-12-31
assert 'TODO' not in result
assert 'AU REVOIR, KANIGGETS' in result
@pytest.mark.sphinx('latex', testroot='latex-table',
confoverrides={'templates_path': ['_mytemplates']})

114
tests/test_deprecation.py Normal file
View File

@ -0,0 +1,114 @@
import warnings
from pathlib import Path
import pytest
from sphinx import deprecation
def test_old_jinja_suffix_warning_is_warning():
assert isinstance(deprecation.OldJinjaSuffixWarning, type)
assert issubclass(deprecation.OldJinjaSuffixWarning, Warning)
assert issubclass(deprecation.OldJinjaSuffixWarning, PendingDeprecationWarning)
with pytest.warns(deprecation.OldJinjaSuffixWarning):
warnings.warn('test_1', category=deprecation.OldJinjaSuffixWarning)
with pytest.warns(PendingDeprecationWarning):
warnings.warn('test_2', category=deprecation.OldJinjaSuffixWarning)
with pytest.warns(Warning):
warnings.warn('test_3', category=deprecation.OldJinjaSuffixWarning)
def test_old_jinja_suffix_warning_simplefilter_always(recwarn):
assert len(recwarn) == 0
warnings.resetwarnings()
warnings.simplefilter('always', category=deprecation.OldJinjaSuffixWarning)
warnings.warn('test_simplefilter_always', category=deprecation.OldJinjaSuffixWarning)
assert len(recwarn) == 1
caught_warning = recwarn[0]
assert caught_warning.category is deprecation.OldJinjaSuffixWarning
assert str(caught_warning.message) == 'test_simplefilter_always'
def test_old_jinja_suffix_warning_filterwarnings_always(recwarn):
assert len(recwarn) == 0
warnings.resetwarnings()
warnings.filterwarnings('always', category=deprecation.OldJinjaSuffixWarning)
warnings.warn('test_filterwarnings_always', category=deprecation.OldJinjaSuffixWarning)
assert len(recwarn) == 1
caught_warning = recwarn[0]
assert caught_warning.category is deprecation.OldJinjaSuffixWarning
assert str(caught_warning.message) == 'test_filterwarnings_always'
def test_old_jinja_suffix_warning_simplefilter_ignore(recwarn):
assert len(recwarn) == 0
warnings.resetwarnings()
warnings.simplefilter('ignore', deprecation.OldJinjaSuffixWarning)
warnings.warn('test_simplefilter_ignore', category=deprecation.OldJinjaSuffixWarning)
assert len(recwarn) == 0
def test_old_jinja_suffix_warning_filterwarnings_ignore(recwarn):
assert len(recwarn) == 0
warnings.resetwarnings()
warnings.filterwarnings('ignore', category=deprecation.OldJinjaSuffixWarning)
warnings.warn('test_filterwarnings_ignore', category=deprecation.OldJinjaSuffixWarning)
assert len(recwarn) == 0
def test__old_jinja_template_suffix_no_warning_css(recwarn):
assert len(recwarn) == 0
warnings.resetwarnings()
warnings.simplefilter('always', category=deprecation.OldJinjaSuffixWarning)
deprecation._old_jinja_template_suffix_warning('template.css')
assert len(recwarn) == 0
def test__old_jinja_template_suffix_no_warning_jinja(recwarn):
assert len(recwarn) == 0
warnings.resetwarnings()
warnings.simplefilter('always', category=deprecation.OldJinjaSuffixWarning)
deprecation._old_jinja_template_suffix_warning('template.css.jinja')
assert len(recwarn) == 0
def test__old_jinja_template_suffix_warning__t():
with pytest.warns(deprecation.OldJinjaSuffixWarning,
match=r"the '_t' suffix for Jinja templates is deprecated"):
deprecation._old_jinja_template_suffix_warning('template.css_t')
def test__old_jinja_template_suffix_warning_stacklevel():
# _old_jinja_template_suffix_warning is only called within functions that
# use template files.
def do_something_with_templates(filename):
deprecation._old_jinja_template_suffix_warning(filename)
# TOJTSWS line number marker
with pytest.warns(deprecation.OldJinjaSuffixWarning) as caught:
do_something_with_templates('template.css_t')
lines = [b''] + Path(__file__).read_bytes().splitlines()
line_number = lines.index(b' # TOJTSWS line number marker') + 2
assert len(caught) == 1
caught_warning = caught[0]
assert caught_warning.category is deprecation.OldJinjaSuffixWarning
assert "the '_t' suffix for Jinja templates is deprecated" in str(caught_warning.message)
assert caught_warning.filename == __file__
assert caught_warning.lineno == line_number

View File

@ -3,7 +3,7 @@
from unittest import mock
from sphinx.jinja2glue import BuiltinTemplateLoader
from sphinx.util.fileutil import copy_asset, copy_asset_file
from sphinx.util.fileutil import _template_basename, copy_asset, copy_asset_file
class DummyTemplateLoader(BuiltinTemplateLoader):
@ -28,9 +28,9 @@ def test_copy_asset_file(tempdir):
assert src.read_text(encoding='utf8') == dest.read_text(encoding='utf8')
# copy template file
src = (tempdir / 'asset.txt_t')
src = (tempdir / 'asset.txt.jinja')
src.write_text('# {{var1}} data')
dest = (tempdir / 'output.txt_t')
dest = (tempdir / 'output.txt.jinja')
copy_asset_file(src, dest, {'var1': 'template'}, renderer)
assert not dest.exists()
@ -38,7 +38,7 @@ def test_copy_asset_file(tempdir):
assert (tempdir / 'output.txt').read_text(encoding='utf8') == '# template data'
# copy template file to subdir
src = (tempdir / 'asset.txt_t')
src = (tempdir / 'asset.txt.jinja')
src.write_text('# {{var1}} data')
subdir1 = (tempdir / 'subdir')
subdir1.makedirs()
@ -48,14 +48,14 @@ def test_copy_asset_file(tempdir):
assert (subdir1 / 'asset.txt').read_text(encoding='utf8') == '# template data'
# copy template file without context
src = (tempdir / 'asset.txt_t')
src = (tempdir / 'asset.txt.jinja')
subdir2 = (tempdir / 'subdir2')
subdir2.makedirs()
copy_asset_file(src, subdir2)
assert not (subdir2 / 'asset.txt').exists()
assert (subdir2 / 'asset.txt_t').exists()
assert (subdir2 / 'asset.txt_t').read_text(encoding='utf8') == '# {{var1}} data'
assert (subdir2 / 'asset.txt.jinja').exists()
assert (subdir2 / 'asset.txt.jinja').read_text(encoding='utf8') == '# {{var1}} data'
def test_copy_asset(tempdir):
@ -65,12 +65,12 @@ def test_copy_asset(tempdir):
source = (tempdir / 'source')
source.makedirs()
(source / 'index.rst').write_text('index.rst', encoding='utf8')
(source / 'foo.rst_t').write_text('{{var1}}.rst', encoding='utf8')
(source / 'foo.rst.jinja').write_text('{{var1}}.rst', encoding='utf8')
(source / '_static').makedirs()
(source / '_static' / 'basic.css').write_text('basic.css', encoding='utf8')
(source / '_templates').makedirs()
(source / '_templates' / 'layout.html').write_text('layout.html', encoding='utf8')
(source / '_templates' / 'sidebar.html_t').write_text('sidebar: {{var2}}', encoding='utf8')
(source / '_templates' / 'sidebar.html.jinja').write_text('sidebar: {{var2}}', encoding='utf8')
# copy a single file
assert not (tempdir / 'test1').exists()
@ -101,3 +101,14 @@ def test_copy_asset(tempdir):
assert not (destdir / '_static' / 'basic.css').exists()
assert (destdir / '_templates' / 'layout.html').exists()
assert not (destdir / '_templates' / 'sidebar.html').exists()
def test_template_basename():
assert not _template_basename("asset.txt")
assert _template_basename("asset.txt.jinja") == "asset.txt"
assert _template_basename("sidebar.html.jinja") == "sidebar.html"
def test_legacy_template_basename():
# TODO: deprecate '_t' template suffix support after 2024-12-31
assert _template_basename("asset.txt_t") == "asset.txt"

View File

@ -42,7 +42,9 @@ METHOD_MAP = [
# Extraction from Python source files
('**.py', extract_python),
# Extraction from Jinja2 template files
('**/templates/latex/**.tex.jinja', extract_jinja2),
('**/templates/latex/**.tex_t', extract_jinja2),
('**/templates/latex/**.sty.jinja', extract_jinja2),
('**/templates/latex/**.sty_t', extract_jinja2),
# Extraction from Jinja2 HTML templates
('**/themes/**.html', extract_jinja2),
@ -50,6 +52,7 @@ METHOD_MAP = [
('**/themes/**.xml', extract_jinja2),
# Extraction from JavaScript files
('**.js', extract_javascript),
('**.js.jinja', extract_javascript),
('**.js_t', extract_javascript),
]
OPTIONS_MAP = {
@ -58,7 +61,9 @@ OPTIONS_MAP = {
'encoding': 'utf-8',
},
# Extraction from Jinja2 template files
'**/templates/latex/**.tex.jinja': TEX_DELIMITERS.copy(),
'**/templates/latex/**.tex_t': TEX_DELIMITERS.copy(),
'**/templates/latex/**.sty.jinja': TEX_DELIMITERS.copy(),
'**/templates/latex/**.sty_t': TEX_DELIMITERS.copy(),
# Extraction from Jinja2 HTML templates
'**/themes/**.html': {