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