Skip to content

Commit a1cd19e

Browse files
authored
Fix copying images under parallel execution (#11100)
1 parent 5008291 commit a1cd19e

File tree

8 files changed

+110
-16
lines changed

8 files changed

+110
-16
lines changed

sphinx/builders/_epub_base.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,12 @@ def copy_image_files_pil(self) -> None:
401401
the format and resizing the image if necessary/possible.
402402
"""
403403
ensuredir(path.join(self.outdir, self.imagedir))
404-
for src in status_iterator(self.images, __('copying images... '), "brown",
405-
len(self.images), self.app.verbosity):
406-
dest = self.images[src]
404+
converted_images = {*self.env.original_image_uri.values()}
405+
for src in status_iterator(self.env.images, __('copying images... '), "brown",
406+
len(self.env.images), self.app.verbosity):
407+
if src in converted_images:
408+
continue
409+
_docnames, dest = self.env.images[src]
407410
try:
408411
img = Image.open(path.join(self.srcdir, src))
409412
except OSError:
@@ -438,7 +441,7 @@ def copy_image_files(self) -> None:
438441
"""Copy image files to destination directory.
439442
This overwritten method can use Pillow to convert image files.
440443
"""
441-
if self.images:
444+
if self.env.images:
442445
if self.config.epub_fix_images or self.config.epub_max_image_width:
443446
if not Image:
444447
logger.warning(__('Pillow not found - copying image files'))

sphinx/builders/html/__init__.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -764,13 +764,16 @@ def write_domain_indices(self) -> None:
764764
self.handle_page(indexname, indexcontext, 'domainindex.html')
765765

766766
def copy_image_files(self) -> None:
767-
if self.images:
767+
if self.env.images:
768+
converted_images = {*self.env.original_image_uri.values()}
768769
stringify_func = ImageAdapter(self.app.env).get_original_image_uri
769770
ensuredir(path.join(self.outdir, self.imagedir))
770-
for src in status_iterator(self.images, __('copying images... '), "brown",
771-
len(self.images), self.app.verbosity,
771+
for src in status_iterator(self.env.images, __('copying images... '), "brown",
772+
len(self.env.images), self.app.verbosity,
772773
stringify_func=stringify_func):
773-
dest = self.images[src]
774+
if src in converted_images:
775+
continue
776+
_docnames, dest = self.env.images[src]
774777
try:
775778
copyfile(path.join(self.srcdir, src),
776779
path.join(self.outdir, self.imagedir, dest))

sphinx/builders/latex/__init__.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,12 +413,15 @@ def copy_latex_additional_files(self) -> None:
413413
copy_asset_file(path.join(self.confdir, filename), self.outdir)
414414

415415
def copy_image_files(self) -> None:
416-
if self.images:
416+
if self.env.images:
417+
converted_images = {*self.env.original_image_uri.values()}
417418
stringify_func = ImageAdapter(self.app.env).get_original_image_uri
418-
for src in status_iterator(self.images, __('copying images... '), "brown",
419-
len(self.images), self.app.verbosity,
419+
for src in status_iterator(self.env.images, __('copying images... '), "brown",
420+
len(self.env.images), self.app.verbosity,
420421
stringify_func=stringify_func):
421-
dest = self.images[src]
422+
if src in converted_images:
423+
continue
424+
_docnames, dest = self.env.images[src]
422425
try:
423426
copy_asset_file(path.join(self.srcdir, src),
424427
path.join(self.outdir, dest))

sphinx/builders/texinfo.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,15 @@ def finish(self) -> None:
173173
self.copy_support_files()
174174

175175
def copy_image_files(self, targetname: str) -> None:
176-
if self.images:
176+
if self.env.images:
177+
converted_images = {*self.env.original_image_uri.values()}
177178
stringify_func = ImageAdapter(self.app.env).get_original_image_uri
178-
for src in status_iterator(self.images, __('copying images... '), "brown",
179-
len(self.images), self.app.verbosity,
179+
for src in status_iterator(self.env.images, __('copying images... '), "brown",
180+
len(self.env.images), self.app.verbosity,
180181
stringify_func=stringify_func):
181-
dest = self.images[src]
182+
if src in converted_images:
183+
continue
184+
_docnames, dest = self.env.images[src]
182185
try:
183186
imagedir = path.join(self.outdir, targetname + '-figures')
184187
ensuredir(imagedir)

tests/test_build_epub.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
import subprocess
5+
from pathlib import Path
56
from subprocess import CalledProcessError
67
from xml.etree import ElementTree
78

@@ -390,3 +391,22 @@ def test_xml_name_pattern_check():
390391
assert _XML_NAME_PATTERN.match('id-pub')
391392
assert _XML_NAME_PATTERN.match('webpage')
392393
assert not _XML_NAME_PATTERN.match('1bfda21')
394+
395+
396+
@pytest.mark.sphinx('epub', testroot='images')
397+
def test_copy_images(app, status, warning):
398+
app.build()
399+
400+
images_dir = Path(app.outdir) / '_images'
401+
images = {image.name for image in images_dir.rglob('*')}
402+
assert images == {
403+
'img.gif',
404+
'img.pdf',
405+
'img.png',
406+
'python-logo.png',
407+
'rimg.png',
408+
'rimg1.png',
409+
'svgimg.pdf',
410+
'svgimg.svg',
411+
'testimäge.png',
412+
}

tests/test_build_html.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import re
55
from itertools import chain, cycle
6+
from pathlib import Path
67
from unittest.mock import ANY, call, patch
78

89
import pytest
@@ -1770,3 +1771,21 @@ def test_theme_having_multiple_stylesheets(app):
17701771

17711772
assert '<link rel="stylesheet" type="text/css" href="_static/mytheme.css" />' in content
17721773
assert '<link rel="stylesheet" type="text/css" href="_static/extra.css" />' in content
1774+
1775+
1776+
@pytest.mark.sphinx('html', testroot='images')
1777+
def test_copy_images(app, status, warning):
1778+
app.build()
1779+
1780+
images_dir = Path(app.outdir) / '_images'
1781+
images = {image.name for image in images_dir.rglob('*')}
1782+
assert images == {
1783+
'img.gif',
1784+
'img.pdf',
1785+
'img.png',
1786+
'rimg.png',
1787+
'rimg1.png',
1788+
'svgimg.pdf',
1789+
'svgimg.svg',
1790+
'testimäge.png',
1791+
}

tests/test_build_latex.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import subprocess
66
from itertools import product
7+
from pathlib import Path
78
from shutil import copyfile
89
from subprocess import CalledProcessError
910

@@ -1670,3 +1671,25 @@ def test_latex_code_role(app):
16701671
common_content + '%\n}} code block') in content
16711672
assert (r'\begin{sphinxVerbatim}[commandchars=\\\{\}]' +
16721673
'\n' + common_content + '\n' + r'\end{sphinxVerbatim}') in content
1674+
1675+
1676+
@pytest.mark.sphinx('latex', testroot='images')
1677+
def test_copy_images(app, status, warning):
1678+
app.build()
1679+
1680+
test_dir = Path(app.outdir)
1681+
images = {
1682+
image.name for image in test_dir.rglob('*')
1683+
if image.suffix in {'.gif', '.pdf', '.png', '.svg'}
1684+
}
1685+
assert images == {
1686+
'img.gif',
1687+
'img.pdf',
1688+
'img.png',
1689+
'python-logo.png',
1690+
'rimg.png',
1691+
'rimg1.png',
1692+
'svgimg.pdf',
1693+
'svgimg.svg',
1694+
'testimäge.png',
1695+
}

tests/test_build_texinfo.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import re
55
import subprocess
6+
from pathlib import Path
67
from subprocess import CalledProcessError
78
from unittest.mock import Mock
89

@@ -137,3 +138,22 @@ def test_texinfo_samp_with_variable(app, status, warning):
137138
assert '@code{@var{variable_only}}' in output
138139
assert '@code{@var{variable} and text}' in output
139140
assert '@code{Show @var{variable} in the middle}' in output
141+
142+
143+
@pytest.mark.sphinx('texinfo', testroot='images')
144+
def test_copy_images(app, status, warning):
145+
app.build()
146+
147+
images_dir = Path(app.outdir) / 'python-figures'
148+
images = {image.name for image in images_dir.rglob('*')}
149+
assert images == {
150+
'img.gif',
151+
'img.pdf',
152+
'img.png',
153+
'python-logo.png',
154+
'rimg.png',
155+
'rimg1.png',
156+
'svgimg.pdf',
157+
'svgimg.svg',
158+
'testimäge.png',
159+
}

0 commit comments

Comments
 (0)