in _ext/sphinx_plotly_directive.py [0:0]
def run(arguments, content, options, state_machine, state, lineno):
document = state_machine.document
config = document.settings.env.config
nofigs = "nofigs" in options
formats = get_plot_formats(config)
default_fmt = formats[0][0]
options_copy = copy.deepcopy(options)
options.setdefault("include-source", config.plotly_include_source)
options.setdefault("iframe-width", config.plotly_iframe_width)
options.setdefault("iframe-height", config.plotly_iframe_height)
keep_context = "context" in options
context_opt = None if not keep_context else options["context"]
rst_file = document.attributes["source"]
rst_dir = os.path.dirname(rst_file)
if len(arguments):
if not config.plotly_basedir:
source_file_name = os.path.join(setup.app.builder.srcdir, directives.uri(arguments[0]))
else:
source_file_name = os.path.join(
setup.confdir, config.plotly_basedir, directives.uri(arguments[0])
)
# If there is content, it will be passed as a caption.
caption = "\n".join(content)
# Enforce unambiguous use of captions.
if "caption" in options:
if caption:
raise ValueError(
"Caption specified in both content and options." " Please remove ambiguity."
)
# Use caption option
caption = options["caption"]
# If the optional function name is provided, use it
if len(arguments) == 2:
function_name = arguments[1]
else:
function_name = None
code = Path(source_file_name).read_text(encoding="utf-8")
output_base = os.path.basename(source_file_name)
else:
source_file_name = rst_file
code = textwrap.dedent("\n".join(map(str, content)))
counter = document.attributes.get("_plot_counter", 0) + 1
document.attributes["_plot_counter"] = counter
base, ext = os.path.splitext(os.path.basename(source_file_name))
output_base = "%s-%d.py" % (base, counter)
function_name = None
caption = options.get("caption", "")
base, source_ext = os.path.splitext(output_base)
if source_ext in (".py", ".rst", ".txt"):
output_base = base
else:
source_ext = ""
# ensure that LaTeX includegraphics doesn't choke in foo.bar.pdf filenames
output_base = output_base.replace(".", "-")
# is it in doctest format?
is_doctest = contains_doctest(code)
if "format" in options:
if options["format"] == "python":
is_doctest = False
else:
is_doctest = True
# determine output directory name fragment
source_rel_name = relpath(source_file_name, setup.confdir)
source_rel_dir = os.path.dirname(source_rel_name)
while source_rel_dir.startswith(os.path.sep):
source_rel_dir = source_rel_dir[1:]
# build_dir: where to place output files (temporarily)
build_dir = os.path.join(
os.path.dirname(setup.app.doctreedir), "plot_directive", source_rel_dir
)
# get rid of .. in paths, also changes pathsep
# see note in Python docs for warning about symbolic links on Windows.
# need to compare source and dest paths at end
build_dir = os.path.normpath(build_dir)
if not os.path.exists(build_dir):
os.makedirs(build_dir)
# output_dir: final location in the builder's directory
dest_dir = os.path.abspath(os.path.join(setup.app.builder.outdir, source_rel_dir))
if not os.path.exists(dest_dir):
os.makedirs(dest_dir) # no problem here for me, but just use built-ins
# how to link to files from the RST file
dest_dir_link = os.path.join(relpath(setup.confdir, rst_dir), source_rel_dir).replace(
os.path.sep, "/"
)
try:
build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, "/")
except ValueError:
# on Windows, relpath raises ValueError when path and start are on
# different mounts/drives
build_dir_link = build_dir
source_link = dest_dir_link + "/" + output_base + source_ext
# make figures
try:
results = render_figures(
code,
source_file_name,
build_dir,
output_base,
keep_context,
function_name,
config,
context_reset=context_opt == "reset",
close_figs=context_opt == "close-figs",
fig_vars=options.get("fig-vars"),
)
errors = []
except PlotError as err:
reporter = state.memo.reporter
sm = reporter.system_message(
2,
"Exception occurred in plotting {}\n from {}:\n{}".format(
output_base, source_file_name, err
),
line=lineno,
)
results = [(code, [])]
errors = [sm]
# Properly indent the caption
caption = "\n".join(" " + line.strip() for line in caption.split("\n"))
# generate output restructuredtext
total_lines = []
for j, (code_piece, figures) in enumerate(results):
if options["include-source"]:
if is_doctest:
lines = ["", *code_piece.splitlines()]
else:
lines = [
".. code-block:: python",
"",
*textwrap.indent(code_piece, " ").splitlines(),
]
source_code = "\n".join(lines)
else:
source_code = ""
if nofigs:
figures = []
opts = [
":%s: %s" % (key, val)
for key, val in options.items()
if key in ("alt", "height", "width", "scale", "align", "class")
]
# Not-None src_link signals the need for a source link in the generated
# html
if j == 0 and config.plotly_html_show_source_link:
src_link = source_link
else:
src_link = None
if config.plotly_include_directive_source:
directive_source = create_directive_block("plotly", arguments, options_copy, content)
directive_source = create_code_block(directive_source, "text")
else:
directive_source = ""
result = jinja2.Template(config.plotly_template or TEMPLATE).render(
directive_source=directive_source,
default_fmt=default_fmt,
dest_dir=dest_dir_link,
build_dir=build_dir_link,
source_link=src_link,
multi_figure=len(figures) > 1,
options=opts,
figures=figures,
iframe_width=options["iframe-width"],
iframe_height=options["iframe-height"],
source_code=source_code,
html_show_formats=config.plotly_html_show_formats and len(figures),
caption=caption,
)
total_lines.extend(result.split("\n"))
total_lines.extend("\n")
if total_lines:
state_machine.insert_input(total_lines, source=source_file_name)
# copy image files to builder's output directory, if necessary
Path(dest_dir).mkdir(parents=True, exist_ok=True)
for code_piece, figures in results:
for fig in figures:
for fn in fig.filenames():
destfig = os.path.join(dest_dir, os.path.basename(fn))
if fn != destfig:
shutil.copyfile(fn, destfig)
# copy script (if necessary)
Path(dest_dir, output_base + source_ext).write_text(
unescape_doctest(code) if source_file_name == rst_file else code,
encoding="utf-8",
)
return errors