Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit80486e6

Browse files
authored
Merge pull request#28187 from asmeurer/output-base-name
Add a filename-prefix option to the Sphinx plot directive
2 parentsf6b77d2 +f4f1fbf commit80486e6

File tree

4 files changed

+128
-10
lines changed

4 files changed

+128
-10
lines changed

‎lib/matplotlib/sphinxext/plot_directive.py

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
4848
The ``.. plot::`` directive supports the following options:
4949
50+
``:filename-prefix:`` : str
51+
The base name (without the extension) of the outputted image and script
52+
files. The default is to use the same name as the input script, or the
53+
name of the RST document if no script is provided. The filename-prefix for
54+
each plot directive must be unique.
55+
5056
``:format:`` : {'python', 'doctest'}
5157
The format of the input. If unset, the format is auto-detected.
5258
@@ -163,8 +169,10 @@
163169
be customized by changing the *plot_template*. See the source of
164170
:doc:`/api/sphinxext_plot_directive_api` for the templates defined in *TEMPLATE*
165171
and *TEMPLATE_SRCSET*.
172+
166173
"""
167174

175+
fromcollectionsimportdefaultdict
168176
importcontextlib
169177
importdoctest
170178
fromioimportStringIO
@@ -182,6 +190,7 @@
182190
fromdocutils.parsers.rst.directives.imagesimportImage
183191
importjinja2# Sphinx dependency.
184192

193+
fromsphinx.environment.collectorsimportEnvironmentCollector
185194
fromsphinx.errorsimportExtensionError
186195

187196
importmatplotlib
@@ -265,6 +274,7 @@ class PlotDirective(Directive):
265274
'scale':directives.nonnegative_int,
266275
'align':Image.align,
267276
'class':directives.class_option,
277+
'filename-prefix':directives.unchanged,
268278
'include-source':_option_boolean,
269279
'show-source-link':_option_boolean,
270280
'format':_option_format,
@@ -312,9 +322,35 @@ def setup(app):
312322
app.connect('build-finished',_copy_css_file)
313323
metadata= {'parallel_read_safe':True,'parallel_write_safe':True,
314324
'version':matplotlib.__version__}
325+
app.connect('builder-inited',init_filename_registry)
326+
app.add_env_collector(_FilenameCollector)
315327
returnmetadata
316328

317329

330+
# -----------------------------------------------------------------------------
331+
# Handle Duplicate Filenames
332+
# -----------------------------------------------------------------------------
333+
334+
definit_filename_registry(app):
335+
env=app.builder.env
336+
ifnothasattr(env,'mpl_plot_image_basenames'):
337+
env.mpl_plot_image_basenames=defaultdict(set)
338+
339+
340+
class_FilenameCollector(EnvironmentCollector):
341+
defprocess_doc(self,app,doctree):
342+
pass
343+
344+
defclear_doc(self,app,env,docname):
345+
ifdocnameinenv.mpl_plot_image_basenames:
346+
delenv.mpl_plot_image_basenames[docname]
347+
348+
defmerge_other(self,app,env,docnames,other):
349+
fordocnameinother.mpl_plot_image_basenames:
350+
env.mpl_plot_image_basenames[docname].update(
351+
other.mpl_plot_image_basenames[docname])
352+
353+
318354
# -----------------------------------------------------------------------------
319355
# Doctest handling
320356
# -----------------------------------------------------------------------------
@@ -600,6 +636,25 @@ def _parse_srcset(entries):
600636
returnsrcset
601637

602638

639+
defcheck_output_base_name(env,output_base):
640+
docname=env.docname
641+
642+
if'.'inoutput_baseor'/'inoutput_baseor'\\'inoutput_base:
643+
raisePlotError(
644+
f"The filename-prefix '{output_base}' is invalid. "
645+
f"It must not contain dots or slashes.")
646+
647+
fordinenv.mpl_plot_image_basenames:
648+
ifoutput_baseinenv.mpl_plot_image_basenames[d]:
649+
ifd==docname:
650+
raisePlotError(
651+
f"The filename-prefix{output_base!r} is used multiple times.")
652+
raisePlotError(f"The filename-prefix{output_base!r} is used multiple"
653+
f"times (it is also used in{env.doc2path(d)}).")
654+
655+
env.mpl_plot_image_basenames[docname].add(output_base)
656+
657+
603658
defrender_figures(code,code_path,output_dir,output_base,context,
604659
function_name,config,context_reset=False,
605660
close_figs=False,
@@ -722,7 +777,8 @@ def render_figures(code, code_path, output_dir, output_base, context,
722777

723778
defrun(arguments,content,options,state_machine,state,lineno):
724779
document=state_machine.document
725-
config=document.settings.env.config
780+
env=document.settings.env
781+
config=env.config
726782
nofigs='nofigs'inoptions
727783

728784
ifconfig.plot_srcsetandsetup.app.builder.name=='singlehtml':
@@ -734,6 +790,7 @@ def run(arguments, content, options, state_machine, state, lineno):
734790

735791
options.setdefault('include-source',config.plot_include_source)
736792
options.setdefault('show-source-link',config.plot_html_show_source_link)
793+
options.setdefault('filename-prefix',None)
737794

738795
if'class'inoptions:
739796
# classes are parsed into a list of string, and output by simply
@@ -775,14 +832,22 @@ def run(arguments, content, options, state_machine, state, lineno):
775832
function_name=None
776833

777834
code=Path(source_file_name).read_text(encoding='utf-8')
778-
output_base=os.path.basename(source_file_name)
835+
ifoptions['filename-prefix']:
836+
output_base=options['filename-prefix']
837+
check_output_base_name(env,output_base)
838+
else:
839+
output_base=os.path.basename(source_file_name)
779840
else:
780841
source_file_name=rst_file
781842
code=textwrap.dedent("\n".join(map(str,content)))
782-
counter=document.attributes.get('_plot_counter',0)+1
783-
document.attributes['_plot_counter']=counter
784-
base,ext=os.path.splitext(os.path.basename(source_file_name))
785-
output_base='%s-%d.py'% (base,counter)
843+
ifoptions['filename-prefix']:
844+
output_base=options['filename-prefix']
845+
check_output_base_name(env,output_base)
846+
else:
847+
base,ext=os.path.splitext(os.path.basename(source_file_name))
848+
counter=document.attributes.get('_plot_counter',0)+1
849+
document.attributes['_plot_counter']=counter
850+
output_base='%s-%d.py'% (base,counter)
786851
function_name=None
787852
caption=options.get('caption','')
788853

@@ -846,7 +911,7 @@ def run(arguments, content, options, state_machine, state, lineno):
846911

847912
# save script (if necessary)
848913
ifoptions['show-source-link']:
849-
Path(build_dir,output_base+source_ext).write_text(
914+
Path(build_dir,output_base+(source_extor'.py')).write_text(
850915
doctest.script_from_examples(code)
851916
ifsource_file_name==rst_fileandis_doctest
852917
elsecode,
@@ -906,7 +971,7 @@ def run(arguments, content, options, state_machine, state, lineno):
906971
# Not-None src_name signals the need for a source download in the
907972
# generated html
908973
ifj==0andoptions['show-source-link']:
909-
src_name=output_base+source_ext
974+
src_name=output_base+(source_extor'.py')
910975
else:
911976
src_name=None
912977
ifconfig.plot_srcset:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
_build/
2+
doctrees/
3+
plot_directive/

‎lib/matplotlib/tests/data/tinypages/some_plots.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,22 @@ Plot 21 is generated via an include directive:
179179
Plot 22 uses a different specific function in a file with plot commands:
180180

181181
..plot::range6.py range10
182+
183+
Plots 23--25 use filename-prefix.
184+
185+
..plot::
186+
:filename-prefix: custom-basename-6
187+
188+
plt.plot(range(6))
189+
190+
..plot::range4.py
191+
:filename-prefix: custom-basename-4
192+
193+
..plot::
194+
:filename-prefix: custom-basename-4-6
195+
196+
plt.figure()
197+
plt.plot(range(4))
198+
199+
plt.figure()
200+
plt.plot(range(6))

‎lib/matplotlib/tests/test_sphinxext.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ def build_sphinx_html(source_dir, doctree_dir, html_dir, extra_args=None):
4040

4141

4242
deftest_tinypages(tmp_path):
43-
shutil.copytree(tinypages,tmp_path,dirs_exist_ok=True)
43+
shutil.copytree(tinypages,tmp_path,dirs_exist_ok=True,
44+
ignore=shutil.ignore_patterns('_build','doctrees',
45+
'plot_directive'))
4446
html_dir=tmp_path/'_build'/'html'
4547
img_dir=html_dir/'_images'
4648
doctree_dir=tmp_path/'doctrees'
@@ -92,6 +94,11 @@ def plot_directive_file(num):
9294
assertfilecmp.cmp(range_6,plot_file(17))
9395
# plot 22 is from the range6.py file again, but a different function
9496
assertfilecmp.cmp(range_10,img_dir/'range6_range10.png')
97+
# plots 23--25 use a custom basename
98+
assertfilecmp.cmp(range_6,img_dir/'custom-basename-6.png')
99+
assertfilecmp.cmp(range_4,img_dir/'custom-basename-4.png')
100+
assertfilecmp.cmp(range_4,img_dir/'custom-basename-4-6_00.png')
101+
assertfilecmp.cmp(range_6,img_dir/'custom-basename-4-6_01.png')
95102

96103
# Modify the included plot
97104
contents= (tmp_path/'included_plot_21.rst').read_bytes()
@@ -176,12 +183,37 @@ def test_show_source_link_false(tmp_path, plot_html_show_source_link):
176183
assertlen(list(html_dir.glob("**/index-1.py")))==0
177184

178185

186+
deftest_plot_html_show_source_link_custom_basename(tmp_path):
187+
# Test that source link filename includes .py extension when using custom basename
188+
shutil.copyfile(tinypages/'conf.py',tmp_path/'conf.py')
189+
shutil.copytree(tinypages/'_static',tmp_path/'_static')
190+
doctree_dir=tmp_path/'doctrees'
191+
(tmp_path/'index.rst').write_text("""
192+
.. plot::
193+
:filename-prefix: custom-name
194+
195+
plt.plot(range(2))
196+
""")
197+
html_dir=tmp_path/'_build'/'html'
198+
build_sphinx_html(tmp_path,doctree_dir,html_dir)
199+
200+
# Check that source file with .py extension is generated
201+
assertlen(list(html_dir.glob("**/custom-name.py")))==1
202+
203+
# Check that the HTML contains the correct link with .py extension
204+
html_content= (html_dir/'index.html').read_text()
205+
assert'custom-name.py'inhtml_content
206+
207+
179208
deftest_srcset_version(tmp_path):
209+
shutil.copytree(tinypages,tmp_path,dirs_exist_ok=True,
210+
ignore=shutil.ignore_patterns('_build','doctrees',
211+
'plot_directive'))
180212
html_dir=tmp_path/'_build'/'html'
181213
img_dir=html_dir/'_images'
182214
doctree_dir=tmp_path/'doctrees'
183215

184-
build_sphinx_html(tinypages,doctree_dir,html_dir,
216+
build_sphinx_html(tmp_path,doctree_dir,html_dir,
185217
extra_args=['-D','plot_srcset=2x'])
186218

187219
defplot_file(num,suff=''):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp