python - 如何让我的 sphinx 指令将资产添加到 _static 文件夹?
问题描述
我正在构建一个自定义 sphinx 扩展和指令,以在 sphinx 和 ReadTheDocs 上呈现交互式图表。图表的实际数据位于.json
文件中。
在.rst
文档中,包括图表如下所示:
.. chart:: charts/test.json
:width: 400px
:height: 250px
This is the caption of the chart, yay...
我采取的步骤是:
使用与图表相同大小的占位符渲染文档(加载微调器)
使用 jQuery(在添加的 javascript 文件中)获取 json 文件(在本例中)的 URI(我将其作为属性添加到我的指令中的 dom 节点
charts/test.json
)使用 jQuery 获取文件并解析 JSON
成功获取数据后,使用 plotly 库将其呈现为图表并使用 jQuery 删除占位符
该指令如下所示:
class PlotlyChartDirective(Directive):
""" Top-level plotly chart directive """
has_content = True
def px_value(argument):
# This is not callable as self.align. We cannot make it a
# staticmethod because we're saving an unbound method in
# option_spec below.
return directives.length_or_percentage_or_unitless(argument, 'px')
required_arguments = 1
optional_arguments = 0
option_spec = {
# TODO allow static images for PDF renders 'altimage': directives.unchanged,
'height': px_value,
'width': px_value,
}
def run(self):
""" Parse a plotly chart directive """
self.assert_has_content()
env = self.state.document.settings.env
# Ensure the current chart ID is initialised in the environment
if 'next_plotly_chart_id' not in env.temp_data:
env.temp_data['next_plotly_chart_id'] = 0
id = env.temp_data['next_plotly_chart_id']
# Handle the URI of the *.json asset
uri = directives.uri(self.arguments[0])
# Create the main node container and store the URI of the file which will be collected later
node = nodes.container()
node['classes'] = ['sphinx-plotly']
# Increment the ID counter ready for the next chart
env.temp_data['next_plotly_chart_id'] += 1
# Only if its a supported builder do we proceed (otherwise return an empty node)
if env.app.builder.name in get_compatible_builders(env.app):
chart_node = nodes.container()
chart_node['classes'] = ['sphinx-plotly-chart', f"sphinx-plotly-chart-id-{id}", f"sphinx-plotly-chart-uri-{uri}"]
placeholder_node = nodes.container()
placeholder_node['classes'] = ['sphinx-plotly-placeholder', f"sphinx-plotly-placeholder-{id}"]
placeholder_node += nodes.caption('', 'Loading...')
node += chart_node
node += placeholder_node
# Add optional chart caption and legend (inspired by Figure directive)
if self.content:
caption_node = nodes.Element() # Anonymous container for parsing
self.state.nested_parse(self.content, self.content_offset, caption_node)
first_node = caption_node[0]
if isinstance(first_node, nodes.paragraph):
caption = nodes.caption(first_node.rawsource, '', *first_node.children)
caption.source = first_node.source
caption.line = first_node.line
node += caption
elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0):
error = self.state_machine.reporter.error(
'Chart caption must be a paragraph or empty comment.',
nodes.literal_block(self.block_text, self.block_text),
line=self.lineno)
return [node, error]
if len(caption_node) > 1:
node += nodes.legend('', *caption_node[1:])
return [node]
无论我在哪里查看Figure
andImage
指令的源代码(我以此为基础),我都无法弄清楚如何将实际图像从其输入位置复制到构建目录中的静态文件夹中。
如果不将参数中指定的文件复制*.json
到我的指令中,我总是找不到文件!
我努力寻找支持方法(我假设Sphinx
app
实例有一个add_static_file()
方法,就像它有一个add_css_file()
方法一样)。
我还尝试添加要复制到app
实例的文件列表,然后在构建结束时复制资产(但由于无法向Sphinx
类添加属性而受到阻碍)
简而言之的问题
在自定义指令中,如何将资产(其路径由指令的参数指定)复制到构建_static
目录?
解决方案
我意识到在指令的方法中直接使用 sphinx 的copyfile
实用程序(仅在文件更改时复制,所以很快) 。run()
看看我是如何在这个更新后直接获取src_uri
和build_uri
复制文件的Directive
:
class PlotlyChartDirective(Directive):
""" Top-level plotly chart directive """
has_content = True
def px_value(argument):
# This is not callable as self.align. We cannot make it a
# staticmethod because we're saving an unbound method in
# option_spec below.
return directives.length_or_percentage_or_unitless(argument, 'px')
required_arguments = 1
optional_arguments = 0
option_spec = {
# TODO allow static images for PDF renders 'altimage': directives.unchanged,
'height': px_value,
'width': px_value,
}
def run(self):
""" Parse a plotly chart directive """
self.assert_has_content()
env = self.state.document.settings.env
# Ensure the current chart ID is initialised in the environment
if 'next_plotly_chart_id' not in env.temp_data:
env.temp_data['next_plotly_chart_id'] = 0
# Get the ID of this chart
id = env.temp_data['next_plotly_chart_id']
# Handle the src and destination URI of the *.json asset
uri = directives.uri(self.arguments[0])
src_uri = os.path.join(env.app.builder.srcdir, uri)
build_uri = os.path.join(env.app.builder.outdir, '_static', uri)
# Create the main node container and store the URI of the file which will be collected later
node = nodes.container()
node['classes'] = ['sphinx-plotly']
# Increment the ID counter ready for the next chart
env.temp_data['next_plotly_chart_id'] += 1
# Only if its a supported builder do we proceed (otherwise return an empty node)
if env.app.builder.name in get_compatible_builders(env.app):
# Make the directories and copy file (if file has changed)
destdir = os.path.dirname(build_uri)
if not os.path.exists(destdir):
os.makedirs(destdir)
copyfile(src_uri, build_uri)
width = self.options.pop('width', DEFAULT_WIDTH)
height = self.options.pop('height', DEFAULT_HEIGHT)
chart_node = nodes.container()
chart_node['classes'] = ['sphinx-plotly-chart', f"sphinx-plotly-chart-id-{id}", f"sphinx-plotly-chart-uri-{uri}"]
placeholder_node = nodes.container()
placeholder_node['classes'] = ['sphinx-plotly-placeholder', f"sphinx-plotly-placeholder-{id}"]
placeholder_node += nodes.caption('', 'Loading...')
node += chart_node
node += placeholder_node
# Add optional chart caption and legend (as per figure directive)
if self.content:
caption_node = nodes.Element() # Anonymous container for parsing
self.state.nested_parse(self.content, self.content_offset, caption_node)
first_node = caption_node[0]
if isinstance(first_node, nodes.paragraph):
caption = nodes.caption(first_node.rawsource, '', *first_node.children)
caption.source = first_node.source
caption.line = first_node.line
node += caption
elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0):
error = self.state_machine.reporter.error(
'Chart caption must be a paragraph or empty comment.',
nodes.literal_block(self.block_text, self.block_text),
line=self.lineno)
return [node, error]
if len(caption_node) > 1:
node += nodes.legend('', *caption_node[1:])
return [node]
推荐阅读
- c++ - 常量表达式的计算结果为 -1,不能缩小为类型 'char' [-Wc++11-narrowing] 错误
- jquery - 当克隆元素出现时向下滑动
- dataframe - Julia DataFrames.jl 双组按
- highcharts - 如何按照以下屏幕截图在高图的下方和上方添加标签
- collections - 转换列表
- > 到地图
- flutter - 用于从 Navigator 推送或弹出路由的上下文必须是作为 Navigator 小部件后代的小部件的上下文
- druid - 在 Apache Druid 中,是否可以获取前一行的值?
- javascript - 从 Cloud Storage 加载 BigQuery 表在打字稿中不起作用
- javascript - JavaScript 切换按钮不适用于 HTML 表格中的按钮
- snowflake-cloud-data-platform - 雪花中的查询结果大小