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