##// END OF EJS Templates
Use our own find_cmd instead of shutil.which
Thomas Kluyver -
Show More
@@ -1,151 +1,147 b''
1 1 """Export to PDF via latex"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import subprocess
7 7 import os
8 8 import sys
9 import shutil
10 9
10 from IPython.utils.process import find_cmd
11 11 from IPython.utils.traitlets import Integer, List, Bool, Instance
12 12 from IPython.utils.tempdir import TemporaryWorkingDirectory
13 13 from .latex import LatexExporter
14 14
15 15
16 16 class PDFExporter(LatexExporter):
17 17 """Writer designed to write to PDF files"""
18 18
19 19 latex_count = Integer(3, config=True,
20 20 help="How many times latex will be called."
21 21 )
22 22
23 23 latex_command = List([u"pdflatex", u"{filename}"], config=True,
24 24 help="Shell command used to compile latex."
25 25 )
26 26
27 27 bib_command = List([u"bibtex", u"{filename}"], config=True,
28 28 help="Shell command used to run bibtex."
29 29 )
30 30
31 31 verbose = Bool(False, config=True,
32 32 help="Whether to display the output of latex commands."
33 33 )
34 34
35 35 temp_file_exts = List(['.aux', '.bbl', '.blg', '.idx', '.log', '.out'], config=True,
36 36 help="File extensions of temp files to remove after running."
37 37 )
38 38
39 39 writer = Instance("IPython.nbconvert.writers.FilesWriter", args=())
40 40
41 def valid_on_path(self, command):
42 """Ensure the given command exists in the OS PATH."""
43 if (shutil.which(command)==None) :
44 raise FileNotFoundError("NBConvert requires this command to be on the System PATH: "+str(command))
45
46 41 def run_command(self, command_list, filename, count, log_function):
47 42 """Run command_list count times.
48 43
49 44 Parameters
50 45 ----------
51 46 command_list : list
52 47 A list of args to provide to Popen. Each element of this
53 48 list will be interpolated with the filename to convert.
54 49 filename : unicode
55 50 The name of the file to convert.
56 51 count : int
57 52 How many times to run the command.
58 53
59 54 Returns
60 55 -------
61 56 success : bool
62 57 A boolean indicating if the command was successful (True)
63 58 or failed (False).
64 59 """
65 60 command = [c.format(filename=filename) for c in command_list]
66 61
67 62 # On windows with python 2.x there is a bug in subprocess.Popen and
68 63 # unicode commands are not supported
69 64 if sys.platform == 'win32' and sys.version_info < (3,0):
70 65 #We must use cp1252 encoding for calling subprocess.Popen
71 66 #Note that sys.stdin.encoding and encoding.DEFAULT_ENCODING
72 67 # could be different (cp437 in case of dos console)
73 68 command = [c.encode('cp1252') for c in command]
74 69
75 self.valid_on_path(command_list[0])
70 # This will throw a clearer error if the command is not found
71 find_cmd(command_list[0])
76 72
77 73 times = 'time' if count == 1 else 'times'
78 74 self.log.info("Running %s %i %s: %s", command_list[0], count, times, command)
79 75 with open(os.devnull, 'rb') as null:
80 76 stdout = subprocess.PIPE if not self.verbose else None
81 77 for index in range(count):
82 78 p = subprocess.Popen(command, stdout=stdout, stdin=null)
83 79 out, err = p.communicate()
84 80 if p.returncode:
85 81 if self.verbose:
86 82 # verbose means I didn't capture stdout with PIPE,
87 83 # so it's already been displayed and `out` is None.
88 84 out = u''
89 85 else:
90 86 out = out.decode('utf-8', 'replace')
91 87 log_function(command, out)
92 88 return False # failure
93 89 return True # success
94 90
95 91 def run_latex(self, filename):
96 92 """Run pdflatex self.latex_count times."""
97 93
98 94 def log_error(command, out):
99 95 self.log.critical(u"%s failed: %s\n%s", command[0], command, out)
100 96
101 97 return self.run_command(self.latex_command, filename,
102 98 self.latex_count, log_error)
103 99
104 100 def run_bib(self, filename):
105 101 """Run bibtex self.latex_count times."""
106 102 filename = os.path.splitext(filename)[0]
107 103
108 104 def log_error(command, out):
109 105 self.log.warn('%s had problems, most likely because there were no citations',
110 106 command[0])
111 107 self.log.debug(u"%s output: %s\n%s", command[0], command, out)
112 108
113 109 return self.run_command(self.bib_command, filename, 1, log_error)
114 110
115 111 def clean_temp_files(self, filename):
116 112 """Remove temporary files created by pdflatex/bibtex."""
117 113 self.log.info("Removing temporary LaTeX files")
118 114 filename = os.path.splitext(filename)[0]
119 115 for ext in self.temp_file_exts:
120 116 try:
121 117 os.remove(filename+ext)
122 118 except OSError:
123 119 pass
124 120
125 121 def from_notebook_node(self, nb, resources=None, **kw):
126 122 latex, resources = super(PDFExporter, self).from_notebook_node(
127 123 nb, resources=resources, **kw
128 124 )
129 125 with TemporaryWorkingDirectory() as td:
130 126 notebook_name = "notebook"
131 127 tex_file = self.writer.write(latex, resources, notebook_name=notebook_name)
132 128 self.log.info("Building PDF")
133 129 rc = self.run_latex(tex_file)
134 130 if not rc:
135 131 rc = self.run_bib(tex_file)
136 132 if not rc:
137 133 rc = self.run_latex(tex_file)
138 134
139 135 pdf_file = notebook_name + '.pdf'
140 136 if not os.path.isfile(pdf_file):
141 137 raise RuntimeError("PDF creating failed")
142 138 self.log.info('PDF successfully created')
143 139 with open(pdf_file, 'rb') as f:
144 140 pdf_data = f.read()
145 141
146 142 # convert output extension to pdf
147 143 # the writer above required it to be tex
148 144 resources['output_extension'] = 'pdf'
149 145
150 146 return pdf_data, resources
151 147
General Comments 0
You need to be logged in to leave comments. Login now