@@ -220,15 +220,33 @@ def _build_latex_header():
220
220
# Create LaTeX header with some content, else LaTeX will load some
221
221
# math fonts later when we don't expect the additional output on stdout.
222
222
# TODO: is this sufficient?
223
- latex_header = u"""\\ documentclass{minimal}
224
- %s
225
- %s
226
- \\ begin{document}
227
- text $math \mu$ %% force latex to load fonts now
228
- \\ typeout{pgf_backend_query_start}
229
- """ % (latex_preamble , latex_fontspec )
223
+ latex_header = [r"\documentclass{minimal}" ,
224
+ latex_preamble ,
225
+ latex_fontspec ,
226
+ r"\begin{document}" ,
227
+ r"text $math \mu$" , # force latex to load fonts now
228
+ r"\typeout{pgf_backend_query_start}" ]
229
+ return "\n " .join (latex_header )
230
+
231
+ def _stdin_writeln (self , s ):
232
+ self .latex_stdin_utf8 .write (s )
233
+ self .latex_stdin_utf8 .write ("\n " )
234
+ self .latex_stdin_utf8 .flush ()
235
+
236
+ def _expect (self , s ):
237
+ exp = s .encode ("utf8" )
238
+ buf = bytearray ()
239
+ while True :
240
+ b = self .latex .stdout .read (1 )
241
+ buf += b
242
+ if buf [- len (exp ):] == exp :
243
+ break
244
+ if not len (b ):
245
+ raise LatexError ("LaTeX process halted" , buf .decode ("utf8" ))
246
+ return buf .decode ("utf8" )
230
247
231
- return latex_header
248
+ def _expect_prompt (self ):
249
+ return self ._expect ("\n *" )
232
250
233
251
def __init__ (self ):
234
252
self .texcommand = get_texcommand ()
@@ -238,27 +256,23 @@ def __init__(self):
238
256
# test the LaTeX setup to ensure a clean startup of the subprocess
239
257
latex = subprocess .Popen ([self .texcommand , "-halt-on-error" ],
240
258
stdin = subprocess .PIPE ,
241
- stdout = subprocess .PIPE ,
242
- universal_newlines = True )
243
- stdout , stderr = latex .communicate (self . latex_header + latex_end )
259
+ stdout = subprocess .PIPE )
260
+ test_input = self . latex_header + latex_end
261
+ stdout , stderr = latex .communicate (test_input . encode ( "utf-8" ) )
244
262
if latex .returncode != 0 :
245
263
raise LatexError ("LaTeX returned an error, probably missing font or error in preamble:\n %s" % stdout )
246
264
247
- # open LaTeX process
265
+ # open LaTeX process for real work
248
266
latex = subprocess .Popen ([self .texcommand , "-halt-on-error" ],
249
267
stdin = subprocess .PIPE ,
250
- stdout = subprocess .PIPE ,
251
- universal_newlines = True )
252
- latex .stdin .write (self .latex_header )
253
- latex .stdin .flush ()
254
- # read all lines until our 'pgf_backend_query_start' token appears
255
- while not latex .stdout .readline ().startswith ("*pgf_backend_query_start" ):
256
- pass
257
- while latex .stdout .read (1 ) != '*' :
258
- pass
268
+ stdout = subprocess .PIPE )
259
269
self .latex = latex
260
- self .latex_stdin = codecs .getwriter ("utf-8" )(latex .stdin )
261
- self .latex_stdout = codecs .getreader ("utf-8" )(latex .stdout )
270
+ self .latex_stdin_utf8 = codecs .getwriter ("utf8" )(self .latex .stdin )
271
+ # write header with 'pgf_backend_query_start' token
272
+ self ._stdin_writeln (self ._build_latex_header ())
273
+ # read all lines until our 'pgf_backend_query_start' token appears
274
+ self ._expect ("*pgf_backend_query_start" )
275
+ self ._expect_prompt ()
262
276
263
277
# cache for strings already processed
264
278
self .str_cache = {}
@@ -277,19 +291,6 @@ def __del__(self):
277
291
except :
278
292
pass
279
293
280
- def _wait_for_prompt (self ):
281
- """
282
- Read all bytes from LaTeX stdout until a new line starts with a *.
283
- """
284
- buf = ["" ]
285
- while True :
286
- buf .append (self .latex_stdout .read (1 ))
287
- if buf [- 1 ] == "*" and buf [- 2 ] == "\n " :
288
- break
289
- if buf [- 1 ] == "" :
290
- raise LatexError ("LaTeX process halted" , u"" .join (buf ))
291
- return "" .join (buf )
292
-
293
294
def get_width_height_descent (self , text , prop ):
294
295
"""
295
296
Get the width, total height and descent for a text typesetted by the
@@ -298,30 +299,27 @@ def get_width_height_descent(self, text, prop):
298
299
299
300
# apply font properties and define textbox
300
301
prop_cmds = _font_properties_str (prop )
301
- textbox = u "\\ sbox0{%s %s}\n " % (prop_cmds , text )
302
+ textbox = "\\ sbox0{%s %s}" % (prop_cmds , text )
302
303
303
304
# check cache
304
305
if textbox in self .str_cache :
305
306
return self .str_cache [textbox ]
306
307
307
308
# send textbox to LaTeX and wait for prompt
308
- self .latex_stdin .write (unicode (textbox ))
309
- self .latex_stdin .flush ()
309
+ self ._stdin_writeln (textbox )
310
310
try :
311
- self ._wait_for_prompt ()
311
+ self ._expect_prompt ()
312
312
except LatexError as e :
313
- msg = u "Error processing '%s'\n LaTeX Output:\n %s" % (text , e .latex_output )
313
+ msg = "Error processing '%s'\n LaTeX Output:\n %s" % (text , e .latex_output )
314
314
raise ValueError (msg )
315
315
316
316
# typeout width, height and text offset of the last textbox
317
- query = "\\ typeout{\\ the\\ wd0,\\ the\\ ht0,\\ the\\ dp0}\n "
318
- self .latex_stdin .write (query )
319
- self .latex_stdin .flush ()
317
+ self ._stdin_writeln (r"\typeout{\the\wd0,\the\ht0,\the\dp0}" )
320
318
# read answer from latex and advance to the next prompt
321
319
try :
322
- answer = self ._wait_for_prompt ()
320
+ answer = self ._expect_prompt ()
323
321
except LatexError as e :
324
- msg = u "Error processing '%s'\n LaTeX Output:\n %s" % (text , e .latex_output )
322
+ msg = "Error processing '%s'\n LaTeX Output:\n %s" % (text , e .latex_output )
325
323
raise ValueError (msg )
326
324
327
325
# parse metrics from the answer string
@@ -712,7 +710,7 @@ def print_pdf(self, filename, *args, **kwargs):
712
710
texcommand = get_texcommand ()
713
711
cmdargs = [texcommand , "-interaction=nonstopmode" , "-halt-on-error" , "figure.tex" ]
714
712
try :
715
- stdout = subprocess .check_output (cmdargs , universal_newlines = True , stderr = subprocess .STDOUT )
713
+ stdout = subprocess .check_output (cmdargs , stderr = subprocess .STDOUT )
716
714
except :
717
715
raise RuntimeError ("%s was not able to process your file.\n \n Full log:\n %s" % (texcommand , stdout ))
718
716
shutil .copyfile ("figure.pdf" , target )
0 commit comments