##// END OF EJS Templates
add PDFExporter...
MinRK -
Show More
@@ -0,0 +1,141 b''
1 """Export to PDF via latex"""
2
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
5
6 import subprocess
7 import os
8 import sys
9
10 from IPython.utils.traitlets import Integer, List, Bool, Instance
11 from IPython.utils.tempdir import TemporaryWorkingDirectory
12 from .latex import LatexExporter
13
14
15 class PDFExporter(LatexExporter):
16 """Writer designed to write to PDF files"""
17
18 latex_count = Integer(3, config=True,
19 help="How many times latex will be called."
20 )
21
22 latex_command = List([u"pdflatex", u"{filename}"], config=True,
23 help="Shell command used to compile latex."
24 )
25
26 bib_command = List([u"bibtex", u"{filename}"], config=True,
27 help="Shell command used to run bibtex."
28 )
29
30 verbose = Bool(False, config=True,
31 help="Whether to display the output of latex commands."
32 )
33
34 temp_file_exts = List(['.aux', '.bbl', '.blg', '.idx', '.log', '.out'], config=True,
35 help="File extensions of temp files to remove after running."
36 )
37
38 writer = Instance("IPython.nbconvert.writers.FilesWriter", args=())
39
40 def run_command(self, command_list, filename, count, log_function):
41 """Run command_list count times.
42
43 Parameters
44 ----------
45 command_list : list
46 A list of args to provide to Popen. Each element of this
47 list will be interpolated with the filename to convert.
48 filename : unicode
49 The name of the file to convert.
50 count : int
51 How many times to run the command.
52
53 Returns
54 -------
55 success : bool
56 A boolean indicating if the command was successful (True)
57 or failed (False).
58 """
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
61 # unicode commands are not supported
62 if sys.platform == 'win32' and sys.version_info < (3,0):
63 #We must use cp1252 encoding for calling subprocess.Popen
64 #Note that sys.stdin.encoding and encoding.DEFAULT_ENCODING
65 # could be different (cp437 in case of dos console)
66 command = [c.encode('cp1252') for c in command]
67 times = 'time' if count == 1 else 'times'
68 self.log.info("Running %s %i %s: %s", command_list[0], count, times, command)
69 with open(os.devnull, 'rb') as null:
70 stdout = subprocess.PIPE if not self.verbose else None
71 for index in range(count):
72 p = subprocess.Popen(command, stdout=stdout, stdin=null)
73 out, err = p.communicate()
74 if p.returncode:
75 if self.verbose:
76 # verbose means I didn't capture stdout with PIPE,
77 # so it's already been displayed and `out` is None.
78 out = u''
79 else:
80 out = out.decode('utf-8', 'replace')
81 log_function(command, out)
82 return False # failure
83 return True # success
84
85 def run_latex(self, filename):
86 """Run pdflatex self.latex_count times."""
87
88 def log_error(command, out):
89 self.log.critical(u"%s failed: %s\n%s", command[0], command, out)
90
91 return self.run_command(self.latex_command, filename,
92 self.latex_count, log_error)
93
94 def run_bib(self, filename):
95 """Run bibtex self.latex_count times."""
96 filename = os.path.splitext(filename)[0]
97
98 def log_error(command, out):
99 self.log.warn('%s had problems, most likely because there were no citations',
100 command[0])
101 self.log.debug(u"%s output: %s\n%s", command[0], command, out)
102
103 return self.run_command(self.bib_command, filename, 1, log_error)
104
105 def clean_temp_files(self, filename):
106 """Remove temporary files created by pdflatex/bibtex."""
107 self.log.info("Removing temporary LaTeX files")
108 filename = os.path.splitext(filename)[0]
109 for ext in self.temp_file_exts:
110 try:
111 os.remove(filename+ext)
112 except OSError:
113 pass
114
115 def from_notebook_node(self, nb, resources=None, **kw):
116 latex, resources = super(PDFExporter, self).from_notebook_node(
117 nb, resources=resources, **kw
118 )
119 with TemporaryWorkingDirectory() as td:
120 notebook_name = "notebook"
121 tex_file = self.writer.write(latex, resources, notebook_name=notebook_name)
122 self.log.info("Building PDF")
123 rc = self.run_latex(tex_file)
124 if not rc:
125 rc = self.run_bib(tex_file)
126 if not rc:
127 rc = self.run_latex(tex_file)
128
129 pdf_file = notebook_name + '.pdf'
130 if not os.path.isfile(pdf_file):
131 raise RuntimeError("PDF creating failed")
132 self.log.info('PDF successfully created')
133 with open(pdf_file, 'rb') as f:
134 pdf_data = f.read()
135
136 # convert output extension to pdf
137 # the writer above required it to be tex
138 resources['output_extension'] = 'pdf'
139
140 return pdf_data, resources
141
@@ -1,9 +1,10 b''
1 1 from .export import *
2 2 from .html import HTMLExporter
3 3 from .slides import SlidesExporter
4 4 from .templateexporter import TemplateExporter
5 5 from .latex import LatexExporter
6 6 from .markdown import MarkdownExporter
7 from .pdf import PDFExporter
7 8 from .python import PythonExporter
8 9 from .rst import RSTExporter
9 10 from .exporter import Exporter
@@ -1,179 +1,172 b''
1 """
2 Module containing single call export functions.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
1 """Module containing single call export functions."""
11 2
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
15 5
16 6 from functools import wraps
17 7
18 8 from IPython.nbformat.v3.nbbase import NotebookNode
19 9 from IPython.utils.decorators import undoc
20 10 from IPython.utils.py3compat import string_types
21 11
22 12 from .exporter import Exporter
23 13 from .templateexporter import TemplateExporter
24 14 from .html import HTMLExporter
25 15 from .slides import SlidesExporter
26 16 from .latex import LatexExporter
17 from .pdf import PDFExporter
27 18 from .markdown import MarkdownExporter
28 19 from .python import PythonExporter
29 20 from .rst import RSTExporter
30 21
31 22 #-----------------------------------------------------------------------------
32 23 # Classes
33 24 #-----------------------------------------------------------------------------
34 25
35 26 @undoc
36 27 def DocDecorator(f):
37 28
38 29 #Set docstring of function
39 30 f.__doc__ = f.__doc__ + """
40 31 nb : :class:`~{nbnode_mod}.NotebookNode`
41 32 The notebook to export.
42 33 config : config (optional, keyword arg)
43 34 User configuration instance.
44 35 resources : dict (optional, keyword arg)
45 36 Resources used in the conversion process.
46 37
47 38 Returns
48 39 -------
49 40 tuple- output, resources, exporter_instance
50 41 output : str
51 42 Jinja 2 output. This is the resulting converted notebook.
52 43 resources : dictionary
53 44 Dictionary of resources used prior to and during the conversion
54 45 process.
55 46 exporter_instance : Exporter
56 47 Instance of the Exporter class used to export the document. Useful
57 48 to caller because it provides a 'file_extension' property which
58 49 specifies what extension the output should be saved as.
59 50
60 51 Notes
61 52 -----
62 53 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT
63 54 """.format(nbnode_mod=NotebookNode.__module__)
64 55
65 56 @wraps(f)
66 57 def decorator(*args, **kwargs):
67 58 return f(*args, **kwargs)
68 59
69 60 return decorator
70 61
71 62
72 63 #-----------------------------------------------------------------------------
73 64 # Functions
74 65 #-----------------------------------------------------------------------------
75 66
76 67 __all__ = [
77 68 'export',
78 69 'export_html',
79 70 'export_custom',
80 71 'export_slides',
81 72 'export_latex',
73 'export_pdf',
82 74 'export_markdown',
83 75 'export_python',
84 76 'export_rst',
85 77 'export_by_name',
86 78 'get_export_names',
87 79 'ExporterNameError'
88 80 ]
89 81
90 82
91 83 class ExporterNameError(NameError):
92 84 pass
93 85
94 86 @DocDecorator
95 87 def export(exporter, nb, **kw):
96 88 """
97 89 Export a notebook object using specific exporter class.
98 90
99 91 Parameters
100 92 ----------
101 93 exporter : class:`~IPython.nbconvert.exporters.exporter.Exporter` class or instance
102 94 Class type or instance of the exporter that should be used. If the
103 95 method initializes it's own instance of the class, it is ASSUMED that
104 96 the class type provided exposes a constructor (``__init__``) with the same
105 97 signature as the base Exporter class.
106 98 """
107 99
108 100 #Check arguments
109 101 if exporter is None:
110 102 raise TypeError("Exporter is None")
111 103 elif not isinstance(exporter, Exporter) and not issubclass(exporter, Exporter):
112 104 raise TypeError("exporter does not inherit from Exporter (base)")
113 105 if nb is None:
114 106 raise TypeError("nb is None")
115 107
116 108 #Create the exporter
117 109 resources = kw.pop('resources', None)
118 110 if isinstance(exporter, Exporter):
119 111 exporter_instance = exporter
120 112 else:
121 113 exporter_instance = exporter(**kw)
122 114
123 115 #Try to convert the notebook using the appropriate conversion function.
124 116 if isinstance(nb, NotebookNode):
125 117 output, resources = exporter_instance.from_notebook_node(nb, resources)
126 118 elif isinstance(nb, string_types):
127 119 output, resources = exporter_instance.from_filename(nb, resources)
128 120 else:
129 121 output, resources = exporter_instance.from_file(nb, resources)
130 122 return output, resources
131 123
132 124 exporter_map = dict(
133 125 custom=TemplateExporter,
134 126 html=HTMLExporter,
135 127 slides=SlidesExporter,
136 128 latex=LatexExporter,
129 pdf=PDFExporter,
137 130 markdown=MarkdownExporter,
138 131 python=PythonExporter,
139 132 rst=RSTExporter,
140 133 )
141 134
142 135 def _make_exporter(name, E):
143 136 """make an export_foo function from a short key and Exporter class E"""
144 137 def _export(nb, **kw):
145 138 return export(E, nb, **kw)
146 139 _export.__doc__ = """Export a notebook object to {0} format""".format(name)
147 140 return _export
148 141
149 142 g = globals()
150 143
151 144 for name, E in exporter_map.items():
152 145 g['export_%s' % name] = DocDecorator(_make_exporter(name, E))
153 146
154 147 @DocDecorator
155 148 def export_by_name(format_name, nb, **kw):
156 149 """
157 150 Export a notebook object to a template type by its name. Reflection
158 151 (Inspect) is used to find the template's corresponding explicit export
159 152 method defined in this module. That method is then called directly.
160 153
161 154 Parameters
162 155 ----------
163 156 format_name : str
164 157 Name of the template style to export to.
165 158 """
166 159
167 160 function_name = "export_" + format_name.lower()
168 161
169 162 if function_name in globals():
170 163 return globals()[function_name](nb, **kw)
171 164 else:
172 165 raise ExporterNameError("template for `%s` not found" % function_name)
173 166
174 167
175 168 def get_export_names():
176 169 """Return a list of the currently supported export targets
177 170
178 171 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT"""
179 172 return sorted(exporter_map.keys())
@@ -1,323 +1,313 b''
1 1 #!/usr/bin/env python
2 """NBConvert is a utility for conversion of .ipynb files.
2 """NbConvert is a utility for conversion of .ipynb files.
3 3
4 4 Command-line interface for the NbConvert conversion utility.
5 5 """
6 #-----------------------------------------------------------------------------
7 #Copyright (c) 2013, the IPython Development Team.
8 #
9 #Distributed under the terms of the Modified BSD License.
10 #
11 #The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
13 6
14 #-----------------------------------------------------------------------------
15 #Imports
16 #-----------------------------------------------------------------------------
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
17 9
18 # Stdlib imports
19 10 from __future__ import print_function
20 11
21 12 import logging
22 13 import sys
23 14 import os
24 15 import glob
25 16
26 # From IPython
27 17 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
28 18 from IPython.core.profiledir import ProfileDir
29 19 from IPython.config import catch_config_error, Configurable
30 20 from IPython.utils.traitlets import (
31 21 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
32 22 )
33 23 from IPython.utils.importstring import import_item
34 24 from IPython.utils.text import dedent
35 25
36 26 from .exporters.export import get_export_names, exporter_map
37 27 from IPython.nbconvert import exporters, preprocessors, writers, postprocessors
38 28 from .utils.base import NbConvertBase
39 29 from .utils.exceptions import ConversionException
40 30
41 31 #-----------------------------------------------------------------------------
42 32 #Classes and functions
43 33 #-----------------------------------------------------------------------------
44 34
45 35 class DottedOrNone(DottedObjectName):
46 36 """
47 37 A string holding a valid dotted object name in Python, such as A.b3._c
48 38 Also allows for None type."""
49 39
50 40 default_value = u''
51 41
52 42 def validate(self, obj, value):
53 43 if value is not None and len(value) > 0:
54 44 return super(DottedOrNone, self).validate(obj, value)
55 45 else:
56 46 return value
57 47
58 48 nbconvert_aliases = {}
59 49 nbconvert_aliases.update(base_aliases)
60 50 nbconvert_aliases.update({
61 51 'to' : 'NbConvertApp.export_format',
62 52 'template' : 'TemplateExporter.template_file',
63 53 'writer' : 'NbConvertApp.writer_class',
64 54 'post': 'NbConvertApp.postprocessor_class',
65 55 'output': 'NbConvertApp.output_base',
66 56 'reveal-prefix': 'RevealHelpPreprocessor.url_prefix',
67 57 })
68 58
69 59 nbconvert_flags = {}
70 60 nbconvert_flags.update(base_flags)
71 61 nbconvert_flags.update({
72 62 'stdout' : (
73 63 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
74 64 "Write notebook output to stdout instead of files."
75 65 )
76 66 })
77 67
78 68
79 69 class NbConvertApp(BaseIPythonApplication):
80 70 """Application used to convert from notebook file type (``*.ipynb``)"""
81 71
82 72 name = 'ipython-nbconvert'
83 73 aliases = nbconvert_aliases
84 74 flags = nbconvert_flags
85 75
86 76 def _log_level_default(self):
87 77 return logging.INFO
88 78
89 79 def _classes_default(self):
90 80 classes = [NbConvertBase, ProfileDir]
91 81 for pkg in (exporters, preprocessors, writers, postprocessors):
92 82 for name in dir(pkg):
93 83 cls = getattr(pkg, name)
94 84 if isinstance(cls, type) and issubclass(cls, Configurable):
95 85 classes.append(cls)
96 86
97 87 return classes
98 88
99 89 description = Unicode(
100 90 u"""This application is used to convert notebook files (*.ipynb)
101 91 to various other formats.
102 92
103 93 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
104 94
105 95 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
106 96 can only be use when converting one notebook at a time.
107 97 ''')
108 98
109 99 examples = Unicode(u"""
110 100 The simplest way to use nbconvert is
111 101
112 102 > ipython nbconvert mynotebook.ipynb
113 103
114 104 which will convert mynotebook.ipynb to the default format (probably HTML).
115 105
116 106 You can specify the export format with `--to`.
117 107 Options include {0}
118 108
119 109 > ipython nbconvert --to latex mynotebook.ipnynb
120 110
121 111 Both HTML and LaTeX support multiple output templates. LaTeX includes
122 112 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
123 113 can specify the flavor of the format used.
124 114
125 115 > ipython nbconvert --to html --template basic mynotebook.ipynb
126 116
127 117 You can also pipe the output to stdout, rather than a file
128 118
129 119 > ipython nbconvert mynotebook.ipynb --stdout
130 120
131 A post-processor can be used to compile a PDF
121 PDF is generated via latex
132 122
133 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
123 > ipython nbconvert mynotebook.ipynb --to pdf
134 124
135 125 You can get (and serve) a Reveal.js-powered slideshow
136 126
137 127 > ipython nbconvert myslides.ipynb --to slides --post serve
138 128
139 129 Multiple notebooks can be given at the command line in a couple of
140 130 different ways:
141 131
142 132 > ipython nbconvert notebook*.ipynb
143 133 > ipython nbconvert notebook1.ipynb notebook2.ipynb
144 134
145 135 or you can specify the notebooks list in a config file, containing::
146 136
147 137 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
148 138
149 139 > ipython nbconvert --config mycfg.py
150 140 """.format(get_export_names()))
151 141
152 142 # Writer specific variables
153 143 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
154 144 help="""Instance of the writer class used to write the
155 145 results of the conversion.""")
156 146 writer_class = DottedObjectName('FilesWriter', config=True,
157 147 help="""Writer class used to write the
158 148 results of the conversion""")
159 149 writer_aliases = {'fileswriter': 'IPython.nbconvert.writers.files.FilesWriter',
160 150 'debugwriter': 'IPython.nbconvert.writers.debug.DebugWriter',
161 151 'stdoutwriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
162 152 writer_factory = Type()
163 153
164 154 def _writer_class_changed(self, name, old, new):
165 155 if new.lower() in self.writer_aliases:
166 156 new = self.writer_aliases[new.lower()]
167 157 self.writer_factory = import_item(new)
168 158
169 159 # Post-processor specific variables
170 160 postprocessor = Instance('IPython.nbconvert.postprocessors.base.PostProcessorBase',
171 161 help="""Instance of the PostProcessor class used to write the
172 162 results of the conversion.""")
173 163
174 164 postprocessor_class = DottedOrNone(config=True,
175 165 help="""PostProcessor class used to write the
176 166 results of the conversion""")
177 167 postprocessor_aliases = {'pdf': 'IPython.nbconvert.postprocessors.pdf.PDFPostProcessor',
178 168 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
179 169 postprocessor_factory = Type()
180 170
181 171 def _postprocessor_class_changed(self, name, old, new):
182 172 if new.lower() in self.postprocessor_aliases:
183 173 new = self.postprocessor_aliases[new.lower()]
184 174 if new:
185 175 self.postprocessor_factory = import_item(new)
186 176
187 177
188 178 # Other configurable variables
189 179 export_format = CaselessStrEnum(get_export_names(),
190 180 default_value="html",
191 181 config=True,
192 182 help="""The export format to be used."""
193 183 )
194 184
195 185 notebooks = List([], config=True, help="""List of notebooks to convert.
196 186 Wildcards are supported.
197 187 Filenames passed positionally will be added to the list.
198 188 """)
199 189
200 190 @catch_config_error
201 191 def initialize(self, argv=None):
202 192 super(NbConvertApp, self).initialize(argv)
203 193 self.init_syspath()
204 194 self.init_notebooks()
205 195 self.init_writer()
206 196 self.init_postprocessor()
207 197
208 198
209 199
210 200 def init_syspath(self):
211 201 """
212 202 Add the cwd to the sys.path ($PYTHONPATH)
213 203 """
214 204 sys.path.insert(0, os.getcwd())
215 205
216 206
217 207 def init_notebooks(self):
218 208 """Construct the list of notebooks.
219 209 If notebooks are passed on the command-line,
220 210 they override notebooks specified in config files.
221 211 Glob each notebook to replace notebook patterns with filenames.
222 212 """
223 213
224 214 # Specifying notebooks on the command-line overrides (rather than adds)
225 215 # the notebook list
226 216 if self.extra_args:
227 217 patterns = self.extra_args
228 218 else:
229 219 patterns = self.notebooks
230 220
231 221 # Use glob to replace all the notebook patterns with filenames.
232 222 filenames = []
233 223 for pattern in patterns:
234 224
235 225 # Use glob to find matching filenames. Allow the user to convert
236 226 # notebooks without having to type the extension.
237 227 globbed_files = glob.glob(pattern)
238 228 globbed_files.extend(glob.glob(pattern + '.ipynb'))
239 229 if not globbed_files:
240 230 self.log.warn("pattern %r matched no files", pattern)
241 231
242 232 for filename in globbed_files:
243 233 if not filename in filenames:
244 234 filenames.append(filename)
245 235 self.notebooks = filenames
246 236
247 237 def init_writer(self):
248 238 """
249 239 Initialize the writer (which is stateless)
250 240 """
251 241 self._writer_class_changed(None, self.writer_class, self.writer_class)
252 242 self.writer = self.writer_factory(parent=self)
253 243
254 244 def init_postprocessor(self):
255 245 """
256 246 Initialize the postprocessor (which is stateless)
257 247 """
258 248 self._postprocessor_class_changed(None, self.postprocessor_class,
259 249 self.postprocessor_class)
260 250 if self.postprocessor_factory:
261 251 self.postprocessor = self.postprocessor_factory(parent=self)
262 252
263 253 def start(self):
264 254 """
265 255 Ran after initialization completed
266 256 """
267 257 super(NbConvertApp, self).start()
268 258 self.convert_notebooks()
269 259
270 260 def convert_notebooks(self):
271 261 """
272 262 Convert the notebooks in the self.notebook traitlet
273 263 """
274 264 # Export each notebook
275 265 conversion_success = 0
276 266
277 267 if self.output_base != '' and len(self.notebooks) > 1:
278 268 self.log.error(
279 269 """UsageError: --output flag or `NbConvertApp.output_base` config option
280 270 cannot be used when converting multiple notebooks.
281 271 """)
282 272 self.exit(1)
283 273
284 274 exporter = exporter_map[self.export_format](config=self.config)
285 275
286 276 for notebook_filename in self.notebooks:
287 277 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
288 278
289 279 # Get a unique key for the notebook and set it in the resources object.
290 280 basename = os.path.basename(notebook_filename)
291 281 notebook_name = basename[:basename.rfind('.')]
292 282 if self.output_base:
293 283 notebook_name = self.output_base
294 284 resources = {}
295 285 resources['unique_key'] = notebook_name
296 286 resources['output_files_dir'] = '%s_files' % notebook_name
297 287 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
298 288
299 289 # Try to export
300 290 try:
301 291 output, resources = exporter.from_filename(notebook_filename, resources=resources)
302 292 except ConversionException as e:
303 293 self.log.error("Error while converting '%s'", notebook_filename,
304 294 exc_info=True)
305 295 self.exit(1)
306 296 else:
307 297 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
308 298
309 299 #Post-process if post processor has been defined.
310 300 if hasattr(self, 'postprocessor') and self.postprocessor:
311 301 self.postprocessor(write_resultes)
312 302 conversion_success += 1
313 303
314 304 # If nothing was converted successfully, help the user.
315 305 if conversion_success == 0:
316 306 self.print_help()
317 307 sys.exit(-1)
318 308
319 309 #-----------------------------------------------------------------------------
320 310 # Main entry point
321 311 #-----------------------------------------------------------------------------
322 312
323 313 launch_new_instance = NbConvertApp.launch_instance
General Comments 0
You need to be logged in to leave comments. Login now