##// END OF EJS Templates
Merge pull request #7027 from takluyver/svg2pdf-test-fix...
Thomas Kluyver -
r19075:1da9421a merge
parent child Browse files
Show More
@@ -1,64 +1,58 b''
1 """Module containing a preprocessor that converts outputs in the notebook from
1 """Module containing a preprocessor that converts outputs in the notebook from
2 one format to another.
2 one format to another.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from .base import Preprocessor
16 from .base import Preprocessor
17 from IPython.utils.traitlets import Unicode
17 from IPython.utils.traitlets import Unicode
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 class ConvertFiguresPreprocessor(Preprocessor):
23 class ConvertFiguresPreprocessor(Preprocessor):
24 """
24 """
25 Converts all of the outputs in a notebook from one format to another.
25 Converts all of the outputs in a notebook from one format to another.
26 """
26 """
27
27
28 from_format = Unicode(config=True, help='Format the converter accepts')
28 from_format = Unicode(config=True, help='Format the converter accepts')
29 to_format = Unicode(config=True, help='Format the converter writes')
29 to_format = Unicode(config=True, help='Format the converter writes')
30
30
31 def __init__(self, **kw):
31 def __init__(self, **kw):
32 """
32 """
33 Public constructor
33 Public constructor
34 """
34 """
35 super(ConvertFiguresPreprocessor, self).__init__(**kw)
35 super(ConvertFiguresPreprocessor, self).__init__(**kw)
36
36
37
37
38 def convert_figure(self, data_format, data):
38 def convert_figure(self, data_format, data):
39 raise NotImplementedError()
39 raise NotImplementedError()
40
40
41
41
42 def preprocess_cell(self, cell, resources, cell_index):
42 def preprocess_cell(self, cell, resources, cell_index):
43 """
43 """
44 Apply a transformation on each cell,
44 Apply a transformation on each cell,
45
45
46 See base.py
46 See base.py
47 """
47 """
48
48
49 # Loop through all of the datatypes of the outputs in the cell.
49 # Loop through all of the datatypes of the outputs in the cell.
50 for index, cell_out in enumerate(cell.get('outputs', [])):
50 for output in cell.get('outputs', []):
51 for data_type, data in list(cell_out.items()):
51 if output.output_type in {'execute_result', 'display_data'} \
52 # this must run *before* extract outputs,
52 and self.from_format in output.data \
53 # so figure_name and filename do not exist
53 and self.to_format not in output.data:
54 self._convert_figure(cell_out, resources, data_type, data)
55 return cell, resources
56
54
55 output.data[self.to_format] = self.convert_figure(
56 self.from_format, output.data[self.from_format])
57
57
58 def _convert_figure(self, cell_out, resources, data_type, data):
58 return cell, resources
59 """
60 Convert a figure and output the results to the cell output
61 """
62 if not self.to_format in cell_out and data_type == self.from_format:
63 data = self.convert_figure(data_type, data)
64 cell_out[self.to_format] = data
@@ -1,82 +1,82 b''
1 """Module containing a preprocessor that converts outputs in the notebook from
1 """Module containing a preprocessor that converts outputs in the notebook from
2 one format to another.
2 one format to another.
3 """
3 """
4
4
5 # Copyright (c) IPython Development Team.
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7
7
8 import base64
8 import base64
9 import io
9 import io
10 import os
10 import os
11 import sys
11 import sys
12 import subprocess
12 import subprocess
13
13
14 from IPython.utils.tempdir import TemporaryDirectory
14 from IPython.utils.tempdir import TemporaryDirectory
15 from IPython.utils.traitlets import Unicode
15 from IPython.utils.traitlets import Unicode
16
16
17 from .convertfigures import ConvertFiguresPreprocessor
17 from .convertfigures import ConvertFiguresPreprocessor
18
18
19
19
20 INKSCAPE_APP = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
20 INKSCAPE_APP = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
21
21
22
22
23 class SVG2PDFPreprocessor(ConvertFiguresPreprocessor):
23 class SVG2PDFPreprocessor(ConvertFiguresPreprocessor):
24 """
24 """
25 Converts all of the outputs in a notebook from SVG to PDF.
25 Converts all of the outputs in a notebook from SVG to PDF.
26 """
26 """
27
27
28 def _from_format_default(self):
28 def _from_format_default(self):
29 return 'image/svg+xml'
29 return 'image/svg+xml'
30 def _to_format_default(self):
30 def _to_format_default(self):
31 return 'application/pdf'
31 return 'application/pdf'
32
32
33 command = Unicode(config=True,
33 command = Unicode(config=True,
34 help="""The command to use for converting SVG to PDF
34 help="""The command to use for converting SVG to PDF
35
35
36 This string is a template, which will be formatted with the keys
36 This string is a template, which will be formatted with the keys
37 to_filename and from_filename.
37 to_filename and from_filename.
38
38
39 The conversion call must read the SVG from {from_flename},
39 The conversion call must read the SVG from {from_flename},
40 and write a PDF to {to_filename}.
40 and write a PDF to {to_filename}.
41 """)
41 """)
42
42
43 def _command_default(self):
43 def _command_default(self):
44 return self.inkscape + \
44 return self.inkscape + \
45 ' --without-gui --export-pdf="{to_filename}" "{from_filename}"'
45 ' --without-gui --export-pdf="{to_filename}" "{from_filename}"'
46
46
47 inkscape = Unicode(config=True, help="The path to Inkscape, if necessary")
47 inkscape = Unicode(config=True, help="The path to Inkscape, if necessary")
48 def _inkscape_default(self):
48 def _inkscape_default(self):
49 if sys.platform == "darwin":
49 if sys.platform == "darwin":
50 if os.path.isfile(INKSCAPE_APP):
50 if os.path.isfile(INKSCAPE_APP):
51 return INKSCAPE_APP
51 return INKSCAPE_APP
52 return "inkscape"
52 return "inkscape"
53
53
54
54
55 def convert_figure(self, data_format, data):
55 def convert_figure(self, data_format, data):
56 """
56 """
57 Convert a single SVG figure to PDF. Returns converted data.
57 Convert a single SVG figure to PDF. Returns converted data.
58 """
58 """
59
59
60 #Work in a temporary directory
60 #Work in a temporary directory
61 with TemporaryDirectory() as tmpdir:
61 with TemporaryDirectory() as tmpdir:
62
62
63 #Write fig to temp file
63 #Write fig to temp file
64 input_filename = os.path.join(tmpdir, 'figure.' + data_format)
64 input_filename = os.path.join(tmpdir, 'figure.svg')
65 # SVG data is unicode text
65 # SVG data is unicode text
66 with io.open(input_filename, 'w', encoding='utf8') as f:
66 with io.open(input_filename, 'w', encoding='utf8') as f:
67 f.write(data)
67 f.write(data)
68
68
69 #Call conversion application
69 #Call conversion application
70 output_filename = os.path.join(tmpdir, 'figure.pdf')
70 output_filename = os.path.join(tmpdir, 'figure.pdf')
71 shell = self.command.format(from_filename=input_filename,
71 shell = self.command.format(from_filename=input_filename,
72 to_filename=output_filename)
72 to_filename=output_filename)
73 subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
73 subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
74
74
75 #Read output from drive
75 #Read output from drive
76 # return value expects a filename
76 # return value expects a filename
77 if os.path.isfile(output_filename):
77 if os.path.isfile(output_filename):
78 with open(output_filename, 'rb') as f:
78 with open(output_filename, 'rb') as f:
79 # PDF is a nb supported binary, data type, so base64 encode.
79 # PDF is a nb supported binary, data type, so base64 encode.
80 return base64.encodestring(f.read())
80 return base64.encodestring(f.read())
81 else:
81 else:
82 raise TypeError("Inkscape svg to pdf conversion failed")
82 raise TypeError("Inkscape svg to pdf conversion failed")
@@ -1,74 +1,73 b''
1 """Tests for the svg2pdf preprocessor"""
1 """Tests for the svg2pdf preprocessor"""
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 from IPython.testing import decorators as dec
6 from IPython.testing import decorators as dec
7 from IPython.nbformat import v4 as nbformat
7 from IPython.nbformat import v4 as nbformat
8
8
9 from .base import PreprocessorTestsBase
9 from .base import PreprocessorTestsBase
10 from ..svg2pdf import SVG2PDFPreprocessor
10 from ..svg2pdf import SVG2PDFPreprocessor
11
11
12
12
13 class Testsvg2pdf(PreprocessorTestsBase):
13 class Testsvg2pdf(PreprocessorTestsBase):
14 """Contains test functions for svg2pdf.py"""
14 """Contains test functions for svg2pdf.py"""
15
15
16 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
16 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
17 <!-- Created with Inkscape (http://www.inkscape.org/) -->
17 <!-- Created with Inkscape (http://www.inkscape.org/) -->
18 <svg
18 <svg
19 xmlns:svg="http://www.w3.org/2000/svg"
19 xmlns:svg="http://www.w3.org/2000/svg"
20 xmlns="http://www.w3.org/2000/svg"
20 xmlns="http://www.w3.org/2000/svg"
21 version="1.0"
21 version="1.0"
22 x="0.00000000"
22 x="0.00000000"
23 y="0.00000000"
23 y="0.00000000"
24 width="500.00000"
24 width="500.00000"
25 height="500.00000"
25 height="500.00000"
26 id="svg2">
26 id="svg2">
27 <defs
27 <defs
28 id="defs4" />
28 id="defs4" />
29 <g
29 <g
30 id="layer1">
30 id="layer1">
31 <rect
31 <rect
32 width="300.00000"
32 width="300.00000"
33 height="300.00000"
33 height="300.00000"
34 x="100.00000"
34 x="100.00000"
35 y="100.00000"
35 y="100.00000"
36 style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
36 style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
37 id="rect5719" />
37 id="rect5719" />
38 </g>
38 </g>
39 </svg>"""
39 </svg>"""
40
40
41 def build_notebook(self):
41 def build_notebook(self):
42 """Build a reveal slides notebook in memory for use with tests.
42 """Build a reveal slides notebook in memory for use with tests.
43 Overrides base in PreprocessorTestsBase"""
43 Overrides base in PreprocessorTestsBase"""
44
44
45 outputs = [nbformat.new_output(output_type="image/svg+xml", output_svg=self.simple_svg)]
45 outputs = [nbformat.new_output(output_type='display_data',
46
46 data={'image/svg+xml':self.simple_svg})
47 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
47 ]
48 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
49
48
50 cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs)]
49 cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs)]
51
50
52 return nbformat.new_notebook(cells=cells)
51 return nbformat.new_notebook(cells=cells)
53
52
54
53
55 def build_preprocessor(self):
54 def build_preprocessor(self):
56 """Make an instance of a preprocessor"""
55 """Make an instance of a preprocessor"""
57 preprocessor = SVG2PDFPreprocessor()
56 preprocessor = SVG2PDFPreprocessor()
58 preprocessor.enabled = True
57 preprocessor.enabled = True
59 return preprocessor
58 return preprocessor
60
59
61
60
62 def test_constructor(self):
61 def test_constructor(self):
63 """Can a SVG2PDFPreprocessor be constructed?"""
62 """Can a SVG2PDFPreprocessor be constructed?"""
64 self.build_preprocessor()
63 self.build_preprocessor()
65
64
66
65
67 @dec.onlyif_cmds_exist('inkscape')
66 @dec.onlyif_cmds_exist('inkscape')
68 def test_output(self):
67 def test_output(self):
69 """Test the output of the SVG2PDFPreprocessor"""
68 """Test the output of the SVG2PDFPreprocessor"""
70 nb = self.build_notebook()
69 nb = self.build_notebook()
71 res = self.build_resources()
70 res = self.build_resources()
72 preprocessor = self.build_preprocessor()
71 preprocessor = self.build_preprocessor()
73 nb, res = preprocessor(nb, res)
72 nb, res = preprocessor(nb, res)
74 self.assertIn('application/pdf', nb.cells[0].outputs[0])
73 self.assertIn('application/pdf', nb.cells[0].outputs[0].data)
General Comments 0
You need to be logged in to leave comments. Login now