##// END OF EJS Templates
Merge pull request #5586 from minrk/pdf-exporter...
Thomas Kluyver -
r16421:fee8aced merge
parent child Browse files
Show More
@@ -0,0 +1,36 b''
1 """Tests for PDF export"""
2
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
5
6 import logging
7 import os
8
9 from IPython.testing import decorators as dec
10
11 from .base import ExportersTestsBase
12 from ..pdf import PDFExporter
13
14
15 #-----------------------------------------------------------------------------
16 # Class
17 #-----------------------------------------------------------------------------
18
19 class TestPDF(ExportersTestsBase):
20 """Test PDF export"""
21
22 exporter_class = PDFExporter
23
24 def test_constructor(self):
25 """Can a PDFExporter be constructed?"""
26 self.exporter_class()
27
28
29 @dec.onlyif_cmds_exist('pdflatex')
30 @dec.onlyif_cmds_exist('pandoc')
31 def test_export(self):
32 """Smoke test PDFExporter"""
33 (output, resources) = self.exporter_class(latex_count=1).from_filename(self._get_notebook())
34 self.assertIsInstance(output, bytes)
35 assert len(output) > 0
36
@@ -0,0 +1,2 b''
1 Creating PDFs with LaTeX no longer uses a post processor.
2 Use `nbconvert --to pdf` instead of `nbconvert --to latex --post pdf`.
@@ -73,7 +73,7 b' class NbconvertFileHandler(IPythonHandler):'
73 @web.authenticated
73 @web.authenticated
74 def get(self, format, path='', name=None):
74 def get(self, format, path='', name=None):
75
75
76 exporter = get_exporter(format, config=self.config)
76 exporter = get_exporter(format, config=self.config, log=self.log)
77
77
78 path = path.strip('/')
78 path = path.strip('/')
79 model = self.notebook_manager.get_notebook(name=name, path=path)
79 model = self.notebook_manager.get_notebook(name=name, path=path)
@@ -1,9 +1,5 b''
1 //----------------------------------------------------------------------------
1 // Copyright (c) IPython Development Team.
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Distributed under the terms of the Modified BSD License.
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
3
8 //============================================================================
4 //============================================================================
9 // MenuBar
5 // MenuBar
@@ -125,6 +121,10 b' var IPython = (function (IPython) {'
125 that._nbconvert('rst', true);
121 that._nbconvert('rst', true);
126 });
122 });
127
123
124 this.element.find('#download_pdf').click(function () {
125 that._nbconvert('pdf', true);
126 });
127
128 this.element.find('#rename_notebook').click(function () {
128 this.element.find('#rename_notebook').click(function () {
129 IPython.save_widget.rename_notebook();
129 IPython.save_widget.rename_notebook();
130 });
130 });
@@ -84,6 +84,7 b' class="notebook_app"'
84 <li id="download_py"><a href="#">Python (.py)</a></li>
84 <li id="download_py"><a href="#">Python (.py)</a></li>
85 <li id="download_html"><a href="#">HTML (.html)</a></li>
85 <li id="download_html"><a href="#">HTML (.html)</a></li>
86 <li id="download_rst"><a href="#">reST (.rst)</a></li>
86 <li id="download_rst"><a href="#">reST (.rst)</a></li>
87 <li id="download_pdf"><a href="#">PDF (.pdf)</a></li>
87 </ul>
88 </ul>
88 </li>
89 </li>
89 <li class="divider"></li>
90 <li class="divider"></li>
@@ -4,6 +4,7 b' from .slides import SlidesExporter'
4 from .templateexporter import TemplateExporter
4 from .templateexporter import TemplateExporter
5 from .latex import LatexExporter
5 from .latex import LatexExporter
6 from .markdown import MarkdownExporter
6 from .markdown import MarkdownExporter
7 from .pdf import PDFExporter
7 from .python import PythonExporter
8 from .python import PythonExporter
8 from .rst import RSTExporter
9 from .rst import RSTExporter
9 from .exporter import Exporter
10 from .exporter import Exporter
@@ -1,17 +1,7 b''
1 """
1 """Module containing single call export functions."""
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 #-----------------------------------------------------------------------------
11
2
12 #-----------------------------------------------------------------------------
3 # Copyright (c) IPython Development Team.
13 # Imports
4 # Distributed under the terms of the Modified BSD License.
14 #-----------------------------------------------------------------------------
15
5
16 from functools import wraps
6 from functools import wraps
17
7
@@ -24,6 +14,7 b' from .templateexporter import TemplateExporter'
24 from .html import HTMLExporter
14 from .html import HTMLExporter
25 from .slides import SlidesExporter
15 from .slides import SlidesExporter
26 from .latex import LatexExporter
16 from .latex import LatexExporter
17 from .pdf import PDFExporter
27 from .markdown import MarkdownExporter
18 from .markdown import MarkdownExporter
28 from .python import PythonExporter
19 from .python import PythonExporter
29 from .rst import RSTExporter
20 from .rst import RSTExporter
@@ -79,6 +70,7 b' __all__ = ['
79 'export_custom',
70 'export_custom',
80 'export_slides',
71 'export_slides',
81 'export_latex',
72 'export_latex',
73 'export_pdf',
82 'export_markdown',
74 'export_markdown',
83 'export_python',
75 'export_python',
84 'export_rst',
76 'export_rst',
@@ -134,6 +126,7 b' exporter_map = dict('
134 html=HTMLExporter,
126 html=HTMLExporter,
135 slides=SlidesExporter,
127 slides=SlidesExporter,
136 latex=LatexExporter,
128 latex=LatexExporter,
129 pdf=PDFExporter,
137 markdown=MarkdownExporter,
130 markdown=MarkdownExporter,
138 python=PythonExporter,
131 python=PythonExporter,
139 rst=RSTExporter,
132 rst=RSTExporter,
@@ -1,53 +1,41 b''
1 """
1 """Export to PDF via latex"""
2 Contains writer for writing nbconvert output to PDF.
2
3 """
3 # Copyright (c) IPython Development Team.
4 #-----------------------------------------------------------------------------
4 # Distributed under the terms of the Modified BSD License.
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 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
5
16 import subprocess
6 import subprocess
17 import os
7 import os
18 import sys
8 import sys
19
9
20 from IPython.utils.traitlets import Integer, List, Bool
10 from IPython.utils.traitlets import Integer, List, Bool, Instance
11 from IPython.utils.tempdir import TemporaryWorkingDirectory
12 from .latex import LatexExporter
21
13
22 from .base import PostProcessorBase
23
14
24 #-----------------------------------------------------------------------------
15 class PDFExporter(LatexExporter):
25 # Classes
26 #-----------------------------------------------------------------------------
27 class PDFPostProcessor(PostProcessorBase):
28 """Writer designed to write to PDF files"""
16 """Writer designed to write to PDF files"""
29
17
30 latex_count = Integer(3, config=True, help="""
18 latex_count = Integer(3, config=True,
31 How many times pdflatex will be called.
19 help="How many times latex will be called."
32 """)
20 )
33
21
34 latex_command = List([u"pdflatex", u"{filename}"], config=True, help="""
22 latex_command = List([u"pdflatex", u"{filename}"], config=True,
35 Shell command used to compile PDF.""")
23 help="Shell command used to compile latex."
24 )
36
25
37 bib_command = List([u"bibtex", u"{filename}"], config=True, help="""
26 bib_command = List([u"bibtex", u"{filename}"], config=True,
38 Shell command used to run bibtex.""")
27 help="Shell command used to run bibtex."
28 )
39
29
40 verbose = Bool(False, config=True, help="""
30 verbose = Bool(False, config=True,
41 Whether or not to display the output of the compile call.
31 help="Whether to display the output of latex commands."
42 """)
32 )
43
33
44 temp_file_exts = List(['.aux', '.bbl', '.blg', '.idx', '.log', '.out'],
34 temp_file_exts = List(['.aux', '.bbl', '.blg', '.idx', '.log', '.out'], config=True,
45 config=True, help="""
35 help="File extensions of temp files to remove after running."
46 Filename extensions of temp files to remove after running.
36 )
47 """)
37
48 pdf_open = Bool(False, config=True, help="""
38 writer = Instance("IPython.nbconvert.writers.FilesWriter", args=())
49 Whether or not to open the pdf after the compile call.
50 """)
51
39
52 def run_command(self, command_list, filename, count, log_function):
40 def run_command(self, command_list, filename, count, log_function):
53 """Run command_list count times.
41 """Run command_list count times.
@@ -64,7 +52,7 b' class PDFPostProcessor(PostProcessorBase):'
64
52
65 Returns
53 Returns
66 -------
54 -------
67 continue : bool
55 success : bool
68 A boolean indicating if the command was successful (True)
56 A boolean indicating if the command was successful (True)
69 or failed (False).
57 or failed (False).
70 """
58 """
@@ -124,33 +112,30 b' class PDFPostProcessor(PostProcessorBase):'
124 except OSError:
112 except OSError:
125 pass
113 pass
126
114
127 def open_pdf(self, filename):
115 def from_notebook_node(self, nb, resources=None, **kw):
128 """Open the pdf in the default viewer."""
116 latex, resources = super(PDFExporter, self).from_notebook_node(
129 if sys.platform.startswith('darwin'):
117 nb, resources=resources, **kw
130 subprocess.call(('open', filename))
118 )
131 elif os.name == 'nt':
119 with TemporaryWorkingDirectory() as td:
132 os.startfile(filename)
120 notebook_name = "notebook"
133 elif os.name == 'posix':
121 tex_file = self.writer.write(latex, resources, notebook_name=notebook_name)
134 subprocess.call(('xdg-open', filename))
122 self.log.info("Building PDF")
135 return
123 rc = self.run_latex(tex_file)
136
124 if not rc:
137 def postprocess(self, filename):
125 rc = self.run_bib(tex_file)
138 """Build a PDF by running pdflatex and bibtex"""
126 if not rc:
139 self.log.info("Building PDF")
127 rc = self.run_latex(tex_file)
140 cont = self.run_latex(filename)
128
141 if cont:
129 pdf_file = notebook_name + '.pdf'
142 cont = self.run_bib(filename)
130 if not os.path.isfile(pdf_file):
143 else:
131 raise RuntimeError("PDF creating failed")
144 self.clean_temp_files(filename)
145 return
146 if cont:
147 cont = self.run_latex(filename)
148 self.clean_temp_files(filename)
149 filename = os.path.splitext(filename)[0]
150 if os.path.isfile(filename+'.pdf'):
151 self.log.info('PDF successfully created')
132 self.log.info('PDF successfully created')
152 if self.pdf_open:
133 with open(pdf_file, 'rb') as f:
153 self.log.info('Viewer called')
134 pdf_data = f.read()
154 self.open_pdf(filename+'.pdf')
135
155 return
136 # convert output extension to pdf
156
137 # the writer above required it to be tex
138 resources['output_extension'] = 'pdf'
139
140 return pdf_data, resources
141
@@ -1,21 +1,12 b''
1 #!/usr/bin/env python
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 Command-line interface for the NbConvert conversion utility.
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 #-----------------------------------------------------------------------------
7 # Copyright (c) IPython Development Team.
15 #Imports
8 # Distributed under the terms of the Modified BSD License.
16 #-----------------------------------------------------------------------------
17
9
18 # Stdlib imports
19 from __future__ import print_function
10 from __future__ import print_function
20
11
21 import logging
12 import logging
@@ -23,7 +14,6 b' import sys'
23 import os
14 import os
24 import glob
15 import glob
25
16
26 # From IPython
27 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
17 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
28 from IPython.core.profiledir import ProfileDir
18 from IPython.core.profiledir import ProfileDir
29 from IPython.config import catch_config_error, Configurable
19 from IPython.config import catch_config_error, Configurable
@@ -128,9 +118,9 b' class NbConvertApp(BaseIPythonApplication):'
128
118
129 > ipython nbconvert mynotebook.ipynb --stdout
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 You can get (and serve) a Reveal.js-powered slideshow
125 You can get (and serve) a Reveal.js-powered slideshow
136
126
@@ -174,8 +164,7 b' class NbConvertApp(BaseIPythonApplication):'
174 postprocessor_class = DottedOrNone(config=True,
164 postprocessor_class = DottedOrNone(config=True,
175 help="""PostProcessor class used to write the
165 help="""PostProcessor class used to write the
176 results of the conversion""")
166 results of the conversion""")
177 postprocessor_aliases = {'pdf': 'IPython.nbconvert.postprocessors.pdf.PDFPostProcessor',
167 postprocessor_aliases = {'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
178 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
179 postprocessor_factory = Type()
168 postprocessor_factory = Type()
180
169
181 def _postprocessor_class_changed(self, name, old, new):
170 def _postprocessor_class_changed(self, name, old, new):
@@ -1,5 +1,4 b''
1 from .base import PostProcessorBase
1 from .base import PostProcessorBase
2 from .pdf import PDFPostProcessor
3
2
4 # protect against unavailable tornado
3 # protect against unavailable tornado
5 try:
4 try:
@@ -1,22 +1,15 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Test NbConvertApp"""
2 """Test NbConvertApp"""
3
3
4 #-----------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Copyright (C) 2013 The IPython Development Team
5 # Distributed under the terms of the Modified BSD License.
6 #
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
6
15 import os
7 import os
16 import glob
8 import glob
17 import sys
9 import sys
18
10
19 from .base import TestsBase
11 from .base import TestsBase
12 from ..postprocessors import PostProcessorBase
20
13
21 import IPython.testing.tools as tt
14 import IPython.testing.tools as tt
22 from IPython.testing import decorators as dec
15 from IPython.testing import decorators as dec
@@ -25,6 +18,10 b' from IPython.testing import decorators as dec'
25 # Classes and functions
18 # Classes and functions
26 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
27
20
21 class DummyPost(PostProcessorBase):
22 def postprocess(self, filename):
23 print("Dummy:%s" % filename)
24
28 class TestNbConvertApp(TestsBase):
25 class TestNbConvertApp(TestsBase):
29 """Collection of NbConvertApp tests"""
26 """Collection of NbConvertApp tests"""
30
27
@@ -79,24 +76,19 b' class TestNbConvertApp(TestsBase):'
79 """
76 """
80 with self.create_temp_cwd(['notebook2.ipynb']):
77 with self.create_temp_cwd(['notebook2.ipynb']):
81 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
78 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
82 self.call('nbconvert --log-level 0 --to latex '
79 self.call('nbconvert --log-level 0 --to pdf'
83 '"notebook with spaces" --post PDF '
80 ' "notebook with spaces"'
84 '--PDFPostProcessor.verbose=True')
81 ' --PDFExporter.latex_count=1'
85 assert os.path.isfile('notebook with spaces.tex')
82 ' --PDFExporter.verbose=True'
86 assert os.path.isdir('notebook with spaces_files')
83 )
87 assert os.path.isfile('notebook with spaces.pdf')
84 assert os.path.isfile('notebook with spaces.pdf')
88
85
89 @dec.onlyif_cmds_exist('pdflatex')
90 @dec.onlyif_cmds_exist('pandoc')
91 def test_post_processor(self):
86 def test_post_processor(self):
92 """
87 """Do post processors work?"""
93 Do post processors work?
94 """
95 with self.create_temp_cwd(['notebook1.ipynb']):
88 with self.create_temp_cwd(['notebook1.ipynb']):
96 self.call('nbconvert --log-level 0 --to latex notebook1 '
89 out, err = self.call('nbconvert --log-level 0 --to python notebook1 '
97 '--post PDF --PDFPostProcessor.verbose=True')
90 '--post IPython.nbconvert.tests.test_nbconvertapp.DummyPost')
98 assert os.path.isfile('notebook1.tex')
91 self.assertIn('Dummy:notebook1.py', out)
99 assert os.path.isfile('notebook1.pdf')
100
92
101 @dec.onlyif_cmds_exist('pandoc')
93 @dec.onlyif_cmds_exist('pandoc')
102 def test_spurious_cr(self):
94 def test_spurious_cr(self):
@@ -195,10 +187,9 b' class TestNbConvertApp(TestsBase):'
195 """
187 """
196 with self.create_temp_cwd():
188 with self.create_temp_cwd():
197 self.create_empty_notebook(u'nb1_análisis.ipynb')
189 self.create_empty_notebook(u'nb1_análisis.ipynb')
198 self.call('nbconvert --log-level 0 --to latex '
190 self.call('nbconvert --log-level 0 --to pdf "nb1_*"'
199 '"nb1_*" --post PDF '
191 ' --PDFExporter.latex_count=1'
200 '--PDFPostProcessor.verbose=True')
192 ' --PDFExporter.verbose=True')
201 assert os.path.isfile(u'nb1_análisis.tex')
202 assert os.path.isfile(u'nb1_análisis.pdf')
193 assert os.path.isfile(u'nb1_análisis.pdf')
203
194
204 def test_cwd_plugin(self):
195 def test_cwd_plugin(self):
@@ -1,17 +1,7 b''
1 """
1 """Contains writer for writing nbconvert output to filesystem."""
2 Contains writer for writing nbconvert output to filesystem.
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 #-----------------------------------------------------------------------------
11
2
12 #-----------------------------------------------------------------------------
3 # Copyright (c) IPython Development Team.
13 # Imports
4 # Distributed under the terms of the Modified BSD License.
14 #-----------------------------------------------------------------------------
15
5
16 import io
6 import io
17 import os
7 import os
@@ -19,6 +9,7 b' import glob'
19
9
20 from IPython.utils.traitlets import Unicode
10 from IPython.utils.traitlets import Unicode
21 from IPython.utils.path import link_or_copy
11 from IPython.utils.path import link_or_copy
12 from IPython.utils.py3compat import unicode_type
22
13
23 from .base import WriterBase
14 from .base import WriterBase
24
15
@@ -110,6 +101,11 b' class FilesWriter(WriterBase):'
110
101
111 # Write conversion results.
102 # Write conversion results.
112 self.log.info("Writing %i bytes to %s", len(output), dest)
103 self.log.info("Writing %i bytes to %s", len(output), dest)
113 with io.open(dest, 'w', encoding='utf-8') as f:
104 if isinstance(output, unicode_type):
114 f.write(output)
105 with io.open(dest, 'w', encoding='utf-8') as f:
106 f.write(output)
107 else:
108 with io.open(dest, 'wb') as f:
109 f.write(output)
110
115 return dest
111 return dest
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now