15
15
import re
16
16
import shutil
17
17
import sys
18
+ from tempfile import TemporaryFile
18
19
19
20
import numpy as np
20
21
@@ -132,8 +133,8 @@ def convert(old, new):
132
133
return convert
133
134
134
135
135
- # Copied from https://bugs.python.org/issue25567
136
- _find_unsafe_bytes = re .compile (rb '[^\w @%+=:,./-]', re . ASCII ).search
136
+ # Modified from https://bugs.python.org/issue25567.
137
+ _find_unsafe_bytes = re .compile (br '[^a-zA-Z0-9_ @%+=:,./-]' ).search
137
138
138
139
139
140
def _shlex_quote_bytes (b ):
@@ -185,10 +186,15 @@ def __call__(self, orig, dest):
185
186
env ["DISPLAY" ] = ""
186
187
# Do not load any user options.
187
188
env ["INKSCAPE_PROFILE_DIR" ] = os .devnull
189
+ # Old versions of Inkscape (0.48.3.1, used on Travis as of now)
190
+ # seem to sometimes deadlock when stderr is redirected to a pipe,
191
+ # so we redirect it to a temporary file instead. This is not
192
+ # necessary anymore as of Inkscape 0.92.1.
193
+ self ._stderr = TemporaryFile ()
188
194
self ._proc = subprocess .Popen (
189
195
[str ("inkscape" ), "--without-gui" , "--shell" ],
190
- env = env , stdin = subprocess .PIPE ,
191
- stdout = subprocess . PIPE , stderr = subprocess . PIPE )
196
+ stdin = subprocess . PIPE , stdout = subprocess .PIPE ,
197
+ stderr = self . _stderr , env = env )
192
198
if not self ._read_to_prompt ():
193
199
raise OSError ("Failed to start Inkscape" )
194
200
@@ -200,16 +206,23 @@ def __call__(self, orig, dest):
200
206
def fsencode (s ):
201
207
return s .encode (sys .getfilesystemencoding ())
202
208
203
- orig , dest = map (_shlex_quote_bytes , map (fsencode , [orig , dest ]))
204
- self ._proc .stdin .write (orig + b" --export-png=" + dest + b"\n " )
209
+ orig_b , dest_b = map (_shlex_quote_bytes , map (fsencode , [orig , dest ]))
210
+ if b"\n " in orig_b or b"\n " in dest_b :
211
+ # Who knows whether the current folder name has a newline, or if
212
+ # our encoding is even ASCII compatible... Just fall back on the
213
+ # slow solution.
214
+ return make_external_conversion_command (lambda old , new : [
215
+ str ('inkscape' ), '-z' , old , '--export-png' , new ])(orig , dest )
216
+ self ._proc .stdin .write (orig_b + b" --export-png=" + dest_b + b"\n " )
205
217
self ._proc .stdin .flush ()
206
218
if not self ._read_to_prompt ():
207
- # I *guess* we should technically decode the stream using
208
- # `getdefaultencoding` *except* for filenames which should be
209
- # decoded using `getfilesystemencoding` but that would be a bit
210
- # overkill.
219
+ # Inkscape's output is not localized but gtk's is, so the
220
+ # output stream probably has a mixed encoding. Using
221
+ # `getfilesystemencoding` should at least get the filenames
222
+ # right...
223
+ self ._stderr .seek (0 )
211
224
raise ImageComparisonFailure (
212
- self ._proc . stderr .read ().decode (
225
+ self ._stderr .read ().decode (
213
226
sys .getfilesystemencoding (), "replace" ))
214
227
215
228
def __del__ (self ):
@@ -219,7 +232,7 @@ def __del__(self):
219
232
self ._proc .wait ()
220
233
self ._proc .stdin .close ()
221
234
self ._proc .stdout .close ()
222
- self ._proc . stderr .close ()
235
+ self ._stderr .close ()
223
236
224
237
225
238
def _update_converter ():
0 commit comments