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

Appearance settings

Commit a6f82b9

Browse filesBrowse files
authored
Merge pull request #17351 from anntzer/inkscape1
Fix running the test suite with inkscape>=1.
2 parents 7377faf + 9e6b9b4 commit a6f82b9
Copy full SHA for a6f82b9

File tree

Expand file treeCollapse file tree

2 files changed

+51
-45
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+51
-45
lines changed

‎lib/matplotlib/__init__.py

Copy file name to clipboardExpand all lines: lib/matplotlib/__init__.py
+6-10Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -331,18 +331,14 @@ def impl(args, regex, min_ver=None, ignore_exit_code=False):
331331
raise ExecutableNotFoundError(message)
332332
elif name == "inkscape":
333333
try:
334-
# use headless option first (works with inkscape version < 1.0):
335-
info = impl(["inkscape", "--without-gui", "-V"],
334+
# Try headless option first (needed for Inkscape version < 1.0):
335+
return impl(["inkscape", "--without-gui", "-V"],
336336
"Inkscape ([^ ]*)")
337337
except ExecutableNotFoundError:
338-
# if --without-gui is not accepted, we're using Inkscape v > 1.0
339-
# so try without the headless option:
340-
info = impl(["inkscape", "-V"], "Inkscape ([^ ]*)")
341-
if info and info.version >= "1.0":
342-
raise ExecutableNotFoundError(
343-
f"You have Inkscape version {info.version} but Matplotlib "
344-
f"only supports Inkscape<1.0")
345-
return info
338+
pass # Suppress exception chaining.
339+
# If --without-gui is not accepted, we may be using Inkscape >= 1.0 so
340+
# try without it:
341+
return impl(["inkscape", "-V"], "Inkscape ([^ ]*)")
346342
elif name == "magick":
347343
path = None
348344
if sys.platform == "win32":

‎lib/matplotlib/testing/compare.py

Copy file name to clipboardExpand all lines: lib/matplotlib/testing/compare.py
+45-35Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import shutil
1111
import subprocess
1212
import sys
13-
from tempfile import TemporaryFile
13+
from tempfile import TemporaryDirectory, TemporaryFile
1414

1515
import numpy as np
1616
import PIL
@@ -158,53 +158,56 @@ def encode_and_escape(name):
158158

159159
class _SVGConverter(_Converter):
160160
def __call__(self, orig, dest):
161+
old_inkscape = mpl._get_executable_info("inkscape").version < "1"
162+
terminator = b"\n>" if old_inkscape else b"> "
163+
if not hasattr(self, "_tmpdir"):
164+
self._tmpdir = TemporaryDirectory()
161165
if (not self._proc # First run.
162166
or self._proc.poll() is not None): # Inkscape terminated.
163-
env = os.environ.copy()
164-
# If one passes e.g. a png file to Inkscape, it will try to
165-
# query the user for conversion options via a GUI (even with
166-
# `--without-gui`). Unsetting `DISPLAY` prevents this (and causes
167-
# GTK to crash and Inkscape to terminate, but that'll just be
168-
# reported as a regular exception below).
169-
env.pop("DISPLAY", None) # May already be unset.
170-
# Do not load any user options.
171-
env["INKSCAPE_PROFILE_DIR"] = os.devnull
172-
# Old versions of Inkscape (0.48.3.1, used on Travis as of now)
173-
# seem to sometimes deadlock when stderr is redirected to a pipe,
174-
# so we redirect it to a temporary file instead. This is not
175-
# necessary anymore as of Inkscape 0.92.1.
167+
env = {
168+
**os.environ,
169+
# If one passes e.g. a png file to Inkscape, it will try to
170+
# query the user for conversion options via a GUI (even with
171+
# `--without-gui`). Unsetting `DISPLAY` prevents this (and
172+
# causes GTK to crash and Inkscape to terminate, but that'll
173+
# just be reported as a regular exception below).
174+
"DISPLAY": "",
175+
# Do not load any user options.
176+
"INKSCAPE_PROFILE_DIR": os.devnull,
177+
}
178+
# Old versions of Inkscape (e.g. 0.48.3.1) seem to sometimes
179+
# deadlock when stderr is redirected to a pipe, so we redirect it
180+
# to a temporary file instead. This is not necessary anymore as of
181+
# Inkscape 0.92.1.
176182
stderr = TemporaryFile()
177183
self._proc = subprocess.Popen(
178-
["inkscape", "--without-gui", "--shell"],
179-
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
180-
stderr=stderr, env=env)
184+
["inkscape", "--without-gui", "--shell"] if old_inkscape else
185+
["inkscape", "--shell"],
186+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr,
187+
env=env, cwd=self._tmpdir.name)
181188
# Slight abuse, but makes shutdown handling easier.
182189
self._proc.stderr = stderr
183190
try:
184-
self._read_until(b"\n>")
191+
self._read_until(terminator)
185192
except _ConverterError as err:
186193
raise OSError("Failed to start Inkscape in interactive "
187194
"mode") from err
188195

189-
# Inkscape uses glib's `g_shell_parse_argv`, which has a consistent
190-
# behavior across platforms, so we can just use `shlex.quote`.
191-
orig_b, dest_b = map(_shlex_quote_bytes,
192-
map(os.fsencode, [orig, dest]))
193-
if b"\n" in orig_b or b"\n" in dest_b:
194-
# Who knows whether the current folder name has a newline, or if
195-
# our encoding is even ASCII compatible... Just fall back on the
196-
# slow solution (Inkscape uses `fgets` so it will always stop at a
197-
# newline).
198-
cbook.warn_deprecated(
199-
"3.3", message="Support for converting files from paths "
200-
"containing a newline is deprecated since %(since)s and "
201-
"support will be removed %(removal)s")
202-
return make_external_conversion_command(lambda old, new: [
203-
'inkscape', '-z', old, '--export-png', new])(orig, dest)
204-
self._proc.stdin.write(orig_b + b" --export-png=" + dest_b + b"\n")
196+
# Inkscape's shell mode does not support escaping metacharacters in the
197+
# filename ("\n", and ":;" for inkscape>=1). Avoid any problems by
198+
# running from a temporary directory and using fixed filenames.
199+
inkscape_orig = Path(self._tmpdir.name, os.fsdecode(b"f.svg"))
200+
inkscape_dest = Path(self._tmpdir.name, os.fsdecode(b"f.png"))
201+
try:
202+
inkscape_orig.symlink_to(Path(orig).resolve())
203+
except OSError:
204+
shutil.copyfile(orig, inkscape_orig)
205+
self._proc.stdin.write(
206+
b"f.svg --export-png=f.png\n" if old_inkscape else
207+
b"file-open:f.svg;export-filename:f.png;export-do;file-close\n")
205208
self._proc.stdin.flush()
206209
try:
207-
self._read_until(b"\n>")
210+
self._read_until(terminator)
208211
except _ConverterError as err:
209212
# Inkscape's output is not localized but gtk's is, so the output
210213
# stream probably has a mixed encoding. Using the filesystem
@@ -213,6 +216,13 @@ def __call__(self, orig, dest):
213216
raise ImageComparisonFailure(
214217
self._proc.stderr.read().decode(
215218
sys.getfilesystemencoding(), "replace")) from err
219+
os.remove(inkscape_orig)
220+
shutil.move(inkscape_dest, dest)
221+
222+
def __del__(self):
223+
super().__del__()
224+
if hasattr(self, "_tmpdir"):
225+
self._tmpdir.cleanup()
216226

217227

218228
def _update_converter():

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.