diff --git a/IPython/nbconvert/exporters/tests/test_pdf.py b/IPython/nbconvert/exporters/tests/test_pdf.py new file mode 100644 index 0000000..6272605 --- /dev/null +++ b/IPython/nbconvert/exporters/tests/test_pdf.py @@ -0,0 +1,36 @@ +"""Tests for PDF export""" + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + +import logging +import os + +from IPython.testing import decorators as dec + +from .base import ExportersTestsBase +from ..pdf import PDFExporter + + +#----------------------------------------------------------------------------- +# Class +#----------------------------------------------------------------------------- + +class TestPDF(ExportersTestsBase): + """Test PDF export""" + + exporter_class = PDFExporter + + def test_constructor(self): + """Can a PDFExporter be constructed?""" + self.exporter_class() + + + @dec.onlyif_cmds_exist('pdflatex') + @dec.onlyif_cmds_exist('pandoc') + def test_export(self): + """Smoke test PDFExporter""" + (output, resources) = self.exporter_class(latex_count=1).from_filename(self._get_notebook()) + self.assertIsInstance(output, bytes) + assert len(output) > 0 + diff --git a/IPython/nbconvert/nbconvertapp.py b/IPython/nbconvert/nbconvertapp.py index fb31df4..cdb23a0 100755 --- a/IPython/nbconvert/nbconvertapp.py +++ b/IPython/nbconvert/nbconvertapp.py @@ -164,8 +164,7 @@ class NbConvertApp(BaseIPythonApplication): postprocessor_class = DottedOrNone(config=True, help="""PostProcessor class used to write the results of the conversion""") - postprocessor_aliases = {'pdf': 'IPython.nbconvert.postprocessors.pdf.PDFPostProcessor', - 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'} + postprocessor_aliases = {'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'} postprocessor_factory = Type() def _postprocessor_class_changed(self, name, old, new): diff --git a/IPython/nbconvert/postprocessors/__init__.py b/IPython/nbconvert/postprocessors/__init__.py index 9f954f3..75ff947 100644 --- a/IPython/nbconvert/postprocessors/__init__.py +++ b/IPython/nbconvert/postprocessors/__init__.py @@ -1,5 +1,4 @@ from .base import PostProcessorBase -from .pdf import PDFPostProcessor # protect against unavailable tornado try: diff --git a/IPython/nbconvert/postprocessors/pdf.py b/IPython/nbconvert/postprocessors/pdf.py deleted file mode 100644 index cfd85b7..0000000 --- a/IPython/nbconvert/postprocessors/pdf.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -Contains writer for writing nbconvert output to PDF. -""" -#----------------------------------------------------------------------------- -#Copyright (c) 2013, the IPython Development Team. -# -#Distributed under the terms of the Modified BSD License. -# -#The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -import subprocess -import os -import sys - -from IPython.utils.traitlets import Integer, List, Bool - -from .base import PostProcessorBase - -#----------------------------------------------------------------------------- -# Classes -#----------------------------------------------------------------------------- -class PDFPostProcessor(PostProcessorBase): - """Writer designed to write to PDF files""" - - latex_count = Integer(3, config=True, help=""" - How many times pdflatex will be called. - """) - - latex_command = List([u"pdflatex", u"{filename}"], config=True, help=""" - Shell command used to compile PDF.""") - - bib_command = List([u"bibtex", u"{filename}"], config=True, help=""" - Shell command used to run bibtex.""") - - verbose = Bool(False, config=True, help=""" - Whether or not to display the output of the compile call. - """) - - temp_file_exts = List(['.aux', '.bbl', '.blg', '.idx', '.log', '.out'], - config=True, help=""" - Filename extensions of temp files to remove after running. - """) - pdf_open = Bool(False, config=True, help=""" - Whether or not to open the pdf after the compile call. - """) - - def run_command(self, command_list, filename, count, log_function): - """Run command_list count times. - - Parameters - ---------- - command_list : list - A list of args to provide to Popen. Each element of this - list will be interpolated with the filename to convert. - filename : unicode - The name of the file to convert. - count : int - How many times to run the command. - - Returns - ------- - continue : bool - A boolean indicating if the command was successful (True) - or failed (False). - """ - command = [c.format(filename=filename) for c in command_list] - #In windows and python 2.x there is a bug in subprocess.Popen and - # unicode commands are not supported - if sys.platform == 'win32' and sys.version_info < (3,0): - #We must use cp1252 encoding for calling subprocess.Popen - #Note that sys.stdin.encoding and encoding.DEFAULT_ENCODING - # could be different (cp437 in case of dos console) - command = [c.encode('cp1252') for c in command] - times = 'time' if count == 1 else 'times' - self.log.info("Running %s %i %s: %s", command_list[0], count, times, command) - with open(os.devnull, 'rb') as null: - stdout = subprocess.PIPE if not self.verbose else None - for index in range(count): - p = subprocess.Popen(command, stdout=stdout, stdin=null) - out, err = p.communicate() - if p.returncode: - if self.verbose: - # verbose means I didn't capture stdout with PIPE, - # so it's already been displayed and `out` is None. - out = u'' - else: - out = out.decode('utf-8', 'replace') - log_function(command, out) - return False # failure - return True # success - - def run_latex(self, filename): - """Run pdflatex self.latex_count times.""" - - def log_error(command, out): - self.log.critical(u"%s failed: %s\n%s", command[0], command, out) - - return self.run_command(self.latex_command, filename, - self.latex_count, log_error) - - def run_bib(self, filename): - """Run bibtex self.latex_count times.""" - filename = os.path.splitext(filename)[0] - - def log_error(command, out): - self.log.warn('%s had problems, most likely because there were no citations', - command[0]) - self.log.debug(u"%s output: %s\n%s", command[0], command, out) - - return self.run_command(self.bib_command, filename, 1, log_error) - - def clean_temp_files(self, filename): - """Remove temporary files created by pdflatex/bibtex.""" - self.log.info("Removing temporary LaTeX files") - filename = os.path.splitext(filename)[0] - for ext in self.temp_file_exts: - try: - os.remove(filename+ext) - except OSError: - pass - - def open_pdf(self, filename): - """Open the pdf in the default viewer.""" - if sys.platform.startswith('darwin'): - subprocess.call(('open', filename)) - elif os.name == 'nt': - os.startfile(filename) - elif os.name == 'posix': - subprocess.call(('xdg-open', filename)) - return - - def postprocess(self, filename): - """Build a PDF by running pdflatex and bibtex""" - self.log.info("Building PDF") - cont = self.run_latex(filename) - if cont: - cont = self.run_bib(filename) - else: - self.clean_temp_files(filename) - return - if cont: - cont = self.run_latex(filename) - self.clean_temp_files(filename) - filename = os.path.splitext(filename)[0] - if os.path.isfile(filename+'.pdf'): - self.log.info('PDF successfully created') - if self.pdf_open: - self.log.info('Viewer called') - self.open_pdf(filename+'.pdf') - return - diff --git a/IPython/nbconvert/postprocessors/tests/test_pdf.py b/IPython/nbconvert/postprocessors/tests/test_pdf.py deleted file mode 100644 index 11da2cb..0000000 --- a/IPython/nbconvert/postprocessors/tests/test_pdf.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -Module with tests for the PDF post-processor -""" - -#----------------------------------------------------------------------------- -# Copyright (c) 2013, the IPython Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -import logging -import os - -from IPython.testing import decorators as dec - -from ...tests.base import TestsBase -from ..pdf import PDFPostProcessor - - -#----------------------------------------------------------------------------- -# Constants -#----------------------------------------------------------------------------- - -HELLO_WORLD = r"""% hello.tex - Our first LaTeX example! -\documentclass{article} -\begin{document} -Hello World! -\end{document}""" - - -#----------------------------------------------------------------------------- -# Class -#----------------------------------------------------------------------------- - -class TestPDF(TestsBase): - """Contains test functions for pdf.py""" - - - def test_constructor(self): - """Can a PDFPostProcessor be constructed?""" - PDFPostProcessor() - - - @dec.onlyif_cmds_exist('pdflatex') - def test_pdf(self): - """Can a PDF be made using the PDFPostProcessor?""" - - # Work in a temporary directory with hello world latex in it. - with self.create_temp_cwd(): - with open('a.tex', 'w') as f: - f.write(HELLO_WORLD) - - # Construct post-processor - processor = PDFPostProcessor(log=logging.getLogger()) - processor.verbose = False - processor('a.tex') - - # Check that the PDF was created. - assert os.path.isfile('a.pdf') - - # Make sure that temp files are cleaned up - for ext in processor.temp_file_exts: - assert not os.path.isfile('a'+ext) diff --git a/IPython/nbconvert/tests/test_nbconvertapp.py b/IPython/nbconvert/tests/test_nbconvertapp.py index a03c30a..91e7813 100644 --- a/IPython/nbconvert/tests/test_nbconvertapp.py +++ b/IPython/nbconvert/tests/test_nbconvertapp.py @@ -1,22 +1,15 @@ # -*- coding: utf-8 -*- """Test NbConvertApp""" -#----------------------------------------------------------------------------- -# Copyright (C) 2013 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. import os import glob import sys from .base import TestsBase +from ..postprocessors import PostProcessorBase import IPython.testing.tools as tt from IPython.testing import decorators as dec @@ -25,6 +18,10 @@ from IPython.testing import decorators as dec # Classes and functions #----------------------------------------------------------------------------- +class DummyPost(PostProcessorBase): + def postprocess(self, filename): + print("Dummy:%s" % filename) + class TestNbConvertApp(TestsBase): """Collection of NbConvertApp tests""" @@ -79,24 +76,19 @@ class TestNbConvertApp(TestsBase): """ with self.create_temp_cwd(['notebook2.ipynb']): os.rename('notebook2.ipynb', 'notebook with spaces.ipynb') - self.call('nbconvert --log-level 0 --to latex ' - '"notebook with spaces" --post PDF ' - '--PDFPostProcessor.verbose=True') - assert os.path.isfile('notebook with spaces.tex') - assert os.path.isdir('notebook with spaces_files') + self.call('nbconvert --log-level 0 --to pdf' + ' "notebook with spaces"' + ' --PDFExporter.latex_count=1' + ' --PDFExporter.verbose=True' + ) assert os.path.isfile('notebook with spaces.pdf') - @dec.onlyif_cmds_exist('pdflatex') - @dec.onlyif_cmds_exist('pandoc') def test_post_processor(self): - """ - Do post processors work? - """ + """Do post processors work?""" with self.create_temp_cwd(['notebook1.ipynb']): - self.call('nbconvert --log-level 0 --to latex notebook1 ' - '--post PDF --PDFPostProcessor.verbose=True') - assert os.path.isfile('notebook1.tex') - assert os.path.isfile('notebook1.pdf') + out, err = self.call('nbconvert --log-level 0 --to python notebook1 ' + '--post IPython.nbconvert.tests.test_nbconvertapp.DummyPost') + self.assertIn('Dummy:notebook1.py', out) @dec.onlyif_cmds_exist('pandoc') def test_spurious_cr(self): @@ -195,8 +187,7 @@ class TestNbConvertApp(TestsBase): """ with self.create_temp_cwd(): self.create_empty_notebook(u'nb1_análisis.ipynb') - self.call('nbconvert --log-level 0 --to latex ' - '"nb1_*" --post PDF ' - '--PDFPostProcessor.verbose=True') - assert os.path.isfile(u'nb1_análisis.tex') + self.call('nbconvert --log-level 0 --to pdf "nb1_*"' + ' --PDFExporter.latex_count=1' + ' --PDFExporter.verbose=True') assert os.path.isfile(u'nb1_análisis.pdf')