ReStructured Text (Sphinx): замена в имени файла?

Я хочу создать несколько файлов из одного шаблона, которые отличаются только именем переменной. Например:

(file1.rst):

.. |variable| replace:: 1
.. include template.rst

(template.rst):

Variable |variable|
=====================

Image
-------

.. image:: ./images/|variable|-image.png

где, конечно, у меня есть изображение под названием "./images/1-image.png". Подстановка "| variable |" по "1" хорошо работает в названии, но не в имени файла изображения, а при компиляции я получаю:

WARNING: image file not readable: ./images/|variable|-image.png

Как я могу получить reST, чтобы сделать замену в имени переменной? (если это что-то меняет, я использую Sphinx).

Ответ 1

Здесь есть две проблемы: проблема замещения и проблема с порядком разбора.

Для первой проблемы ссылка на замену |variable| не может содержать соседние символы (кроме пробелов или, возможно, _ для гиперссылки), иначе она не будет анализироваться как ссылка на замену, поэтому вам нужно ее избежать:

./images/\ |variable|\ -image.png

Тем не менее, вторая проблема ждет за углом. Хотя я не уверен в деталях, кажется, что reST не может разобрать замены внутри других директив. Я думаю, что сначала он анализирует директиву изображения, которая помещает ее в дерево документа и, таким образом, выходит за пределы механизма замены. Точно так же я не думаю, что возможно использовать замену для вставки содержимого, предназначенного для анализа (например, .. |img1| replace::'.. image:: images/1-image.png'). Это все предположения, основанные на некоторых тестах и моем неполном понимании официальной документации, так что кто-то более знающий может исправить то, что я сказал здесь.

Я думаю, что вы знаете о действительной директиве замены изображения (в отличие от замены текста), но я не думаю, что она достигает общности, к которой вы стремитесь (вам все равно понадобится отдельная директива для изображения, как от | variable |), но в любом случае это выглядит так:

.. |img1| image:: images/1-image.png

Поскольку вы используете Sphinx, вы можете попробовать создать собственное расширение директивы (см. этот ответ для получения информации), но это не решит проблему подстановок внутри разметки.

Ответ 2

В этом случае вы должны создать пользовательскую директиву, так как Sphinx не позволяет вам заменять пути к изображениям. Вы можете изменить директиву Sphinx figure следующим образом и использовать ее вместо директивы image.

from typing import Any, Dict, List, Tuple
from typing import cast

from docutils import nodes
from docutils.nodes import Node, make_id, system_message
from docutils.parsers.rst import directives
from docutils.parsers.rst.directives import images, html, tables

from sphinx import addnodes
from sphinx.directives import optional_int
from sphinx.domains.math import MathDomain
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import set_source_info

if False:
    # For type annotation
    from sphinx.application import Sphinx


class CustomFigure(images.Figure):
    """The figure directive which applies ':name:' option to the figure node
    instead of the image node.
    """

    def run(self) -> List[Node]:
        name = self.options.pop('name', None)
        path = self.arguments[0]  #path = ./images/variable-image.png
        #replace 'variable' from th.e given value 
        self.argument[0] = path.replace("variable", "string substitution")
        result = super().run()
        if len(result) == 2 or isinstance(result[0], nodes.system_message):
            return result

        assert len(result) == 1
        figure_node = cast(nodes.figure, result[0])
        if name:
            # set ''name'' to figure_node if given
            self.options['name'] = name
            self.add_name(figure_node)

        # copy lineno from image node
        if figure_node.line is None and len(figure_node) == 2:
            caption = cast(nodes.caption, figure_node[1])
            figure_node.line = caption.line

        return [figure_node]


def setup(app: "Sphinx") -> Dict[str, Any]:
    directives.register_directive('figure', Figure)

    return {
        'version': 'builtin',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }

Вы можете добавить эту директиву CustomFigure.py в conf.py проекта и использовать директиву customfigure в проекте Sphinx вместо директивы Image. Обратитесь http://www.sphinx-doc.org/en/master/usage/extensions/index.html, чтобы добавить пользовательскую директиву в ваш проект Sphinx.