##// END OF EJS Templates
Don't use nbformat.current in nbconvert
MinRK -
Show More
@@ -1,174 +1,174 b''
1 1 """Module containing single call export functions."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from functools import wraps
7 7
8 from IPython.nbformat.current import NotebookNode
8 from IPython.nbformat.v4 import NotebookNode
9 9 from IPython.utils.decorators import undoc
10 10 from IPython.utils.py3compat import string_types
11 11
12 12 from .exporter import Exporter
13 13 from .templateexporter import TemplateExporter
14 14 from .html import HTMLExporter
15 15 from .slides import SlidesExporter
16 16 from .latex import LatexExporter
17 17 from .pdf import PDFExporter
18 18 from .markdown import MarkdownExporter
19 19 from .python import PythonExporter
20 20 from .rst import RSTExporter
21 21 from .notebook import NotebookExporter
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Classes
25 25 #-----------------------------------------------------------------------------
26 26
27 27 @undoc
28 28 def DocDecorator(f):
29 29
30 30 #Set docstring of function
31 31 f.__doc__ = f.__doc__ + """
32 32 nb : :class:`~{nbnode_mod}.NotebookNode`
33 33 The notebook to export.
34 34 config : config (optional, keyword arg)
35 35 User configuration instance.
36 36 resources : dict (optional, keyword arg)
37 37 Resources used in the conversion process.
38 38
39 39 Returns
40 40 -------
41 41 tuple- output, resources, exporter_instance
42 42 output : str
43 43 Jinja 2 output. This is the resulting converted notebook.
44 44 resources : dictionary
45 45 Dictionary of resources used prior to and during the conversion
46 46 process.
47 47 exporter_instance : Exporter
48 48 Instance of the Exporter class used to export the document. Useful
49 49 to caller because it provides a 'file_extension' property which
50 50 specifies what extension the output should be saved as.
51 51
52 52 Notes
53 53 -----
54 54 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT
55 55 """.format(nbnode_mod=NotebookNode.__module__)
56 56
57 57 @wraps(f)
58 58 def decorator(*args, **kwargs):
59 59 return f(*args, **kwargs)
60 60
61 61 return decorator
62 62
63 63
64 64 #-----------------------------------------------------------------------------
65 65 # Functions
66 66 #-----------------------------------------------------------------------------
67 67
68 68 __all__ = [
69 69 'export',
70 70 'export_html',
71 71 'export_custom',
72 72 'export_slides',
73 73 'export_latex',
74 74 'export_pdf',
75 75 'export_markdown',
76 76 'export_python',
77 77 'export_rst',
78 78 'export_by_name',
79 79 'get_export_names',
80 80 'ExporterNameError'
81 81 ]
82 82
83 83
84 84 class ExporterNameError(NameError):
85 85 pass
86 86
87 87 @DocDecorator
88 88 def export(exporter, nb, **kw):
89 89 """
90 90 Export a notebook object using specific exporter class.
91 91
92 92 Parameters
93 93 ----------
94 94 exporter : class:`~IPython.nbconvert.exporters.exporter.Exporter` class or instance
95 95 Class type or instance of the exporter that should be used. If the
96 96 method initializes it's own instance of the class, it is ASSUMED that
97 97 the class type provided exposes a constructor (``__init__``) with the same
98 98 signature as the base Exporter class.
99 99 """
100 100
101 101 #Check arguments
102 102 if exporter is None:
103 103 raise TypeError("Exporter is None")
104 104 elif not isinstance(exporter, Exporter) and not issubclass(exporter, Exporter):
105 105 raise TypeError("exporter does not inherit from Exporter (base)")
106 106 if nb is None:
107 107 raise TypeError("nb is None")
108 108
109 109 #Create the exporter
110 110 resources = kw.pop('resources', None)
111 111 if isinstance(exporter, Exporter):
112 112 exporter_instance = exporter
113 113 else:
114 114 exporter_instance = exporter(**kw)
115 115
116 116 #Try to convert the notebook using the appropriate conversion function.
117 117 if isinstance(nb, NotebookNode):
118 118 output, resources = exporter_instance.from_notebook_node(nb, resources)
119 119 elif isinstance(nb, string_types):
120 120 output, resources = exporter_instance.from_filename(nb, resources)
121 121 else:
122 122 output, resources = exporter_instance.from_file(nb, resources)
123 123 return output, resources
124 124
125 125 exporter_map = dict(
126 126 custom=TemplateExporter,
127 127 html=HTMLExporter,
128 128 slides=SlidesExporter,
129 129 latex=LatexExporter,
130 130 pdf=PDFExporter,
131 131 markdown=MarkdownExporter,
132 132 python=PythonExporter,
133 133 rst=RSTExporter,
134 134 notebook=NotebookExporter,
135 135 )
136 136
137 137 def _make_exporter(name, E):
138 138 """make an export_foo function from a short key and Exporter class E"""
139 139 def _export(nb, **kw):
140 140 return export(E, nb, **kw)
141 141 _export.__doc__ = """Export a notebook object to {0} format""".format(name)
142 142 return _export
143 143
144 144 g = globals()
145 145
146 146 for name, E in exporter_map.items():
147 147 g['export_%s' % name] = DocDecorator(_make_exporter(name, E))
148 148
149 149 @DocDecorator
150 150 def export_by_name(format_name, nb, **kw):
151 151 """
152 152 Export a notebook object to a template type by its name. Reflection
153 153 (Inspect) is used to find the template's corresponding explicit export
154 154 method defined in this module. That method is then called directly.
155 155
156 156 Parameters
157 157 ----------
158 158 format_name : str
159 159 Name of the template style to export to.
160 160 """
161 161
162 162 function_name = "export_" + format_name.lower()
163 163
164 164 if function_name in globals():
165 165 return globals()[function_name](nb, **kw)
166 166 else:
167 167 raise ExporterNameError("template for `%s` not found" % function_name)
168 168
169 169
170 170 def get_export_names():
171 171 """Return a list of the currently supported export targets
172 172
173 173 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT"""
174 174 return sorted(exporter_map.keys())
@@ -1,276 +1,259 b''
1 1 """This module defines a base Exporter class. For Jinja template-based export,
2 2 see templateexporter.py.
3 3 """
4 4
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16 5
17 6 from __future__ import print_function, absolute_import
18 7
19 # Stdlib imports
20 8 import io
21 9 import os
22 10 import copy
23 11 import collections
24 12 import datetime
25 13
26
27 # IPython imports
28 14 from IPython.config.configurable import LoggingConfigurable
29 15 from IPython.config import Config
30 from IPython.nbformat import current as nbformat
16 from IPython import nbformat
31 17 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
32 18 from IPython.utils.importstring import import_item
33 19 from IPython.utils import text, py3compat
34 20
35 #-----------------------------------------------------------------------------
36 # Class
37 #-----------------------------------------------------------------------------
38 21
39 22 class ResourcesDict(collections.defaultdict):
40 23 def __missing__(self, key):
41 24 return ''
42 25
43 26
44 27 class Exporter(LoggingConfigurable):
45 28 """
46 29 Class containing methods that sequentially run a list of preprocessors on a
47 30 NotebookNode object and then return the modified NotebookNode object and
48 31 accompanying resources dict.
49 32 """
50 33
51 34 file_extension = Unicode(
52 35 'txt', config=True,
53 36 help="Extension of the file that should be written to disk"
54 37 )
55 38
56 39 # MIME type of the result file, for HTTP response headers.
57 40 # This is *not* a traitlet, because we want to be able to access it from
58 41 # the class, not just on instances.
59 42 output_mimetype = ''
60 43
61 44 #Configurability, allows the user to easily add filters and preprocessors.
62 45 preprocessors = List(config=True,
63 46 help="""List of preprocessors, by name or namespace, to enable.""")
64 47
65 48 _preprocessors = List()
66 49
67 50 default_preprocessors = List(['IPython.nbconvert.preprocessors.coalesce_streams',
68 51 'IPython.nbconvert.preprocessors.SVG2PDFPreprocessor',
69 52 'IPython.nbconvert.preprocessors.ExtractOutputPreprocessor',
70 53 'IPython.nbconvert.preprocessors.CSSHTMLHeaderPreprocessor',
71 54 'IPython.nbconvert.preprocessors.RevealHelpPreprocessor',
72 55 'IPython.nbconvert.preprocessors.LatexPreprocessor',
73 56 'IPython.nbconvert.preprocessors.ClearOutputPreprocessor',
74 57 'IPython.nbconvert.preprocessors.ExecutePreprocessor',
75 58 'IPython.nbconvert.preprocessors.HighlightMagicsPreprocessor'],
76 59 config=True,
77 60 help="""List of preprocessors available by default, by name, namespace,
78 61 instance, or type.""")
79 62
80 63
81 64 def __init__(self, config=None, **kw):
82 65 """
83 66 Public constructor
84 67
85 68 Parameters
86 69 ----------
87 70 config : config
88 71 User configuration instance.
89 72 """
90 73 with_default_config = self.default_config
91 74 if config:
92 75 with_default_config.merge(config)
93 76
94 77 super(Exporter, self).__init__(config=with_default_config, **kw)
95 78
96 79 self._init_preprocessors()
97 80
98 81
99 82 @property
100 83 def default_config(self):
101 84 return Config()
102 85
103 86 def from_notebook_node(self, nb, resources=None, **kw):
104 87 """
105 88 Convert a notebook from a notebook node instance.
106 89
107 90 Parameters
108 91 ----------
109 92 nb : :class:`~IPython.nbformat.current.NotebookNode`
110 Notebook node
93 Notebook node (dict-like with attr-access)
111 94 resources : dict
112 95 Additional resources that can be accessed read/write by
113 96 preprocessors and filters.
114 97 **kw
115 98 Ignored (?)
116 99 """
117 100 nb_copy = copy.deepcopy(nb)
118 101 resources = self._init_resources(resources)
119 102
120 103 if 'language' in nb['metadata']:
121 104 resources['language'] = nb['metadata']['language'].lower()
122 105
123 106 # Preprocess
124 107 nb_copy, resources = self._preprocess(nb_copy, resources)
125 108
126 109 return nb_copy, resources
127 110
128 111
129 112 def from_filename(self, filename, resources=None, **kw):
130 113 """
131 114 Convert a notebook from a notebook file.
132 115
133 116 Parameters
134 117 ----------
135 118 filename : str
136 119 Full filename of the notebook file to open and convert.
137 120 """
138 121
139 122 # Pull the metadata from the filesystem.
140 123 if resources is None:
141 124 resources = ResourcesDict()
142 125 if not 'metadata' in resources or resources['metadata'] == '':
143 126 resources['metadata'] = ResourcesDict()
144 127 basename = os.path.basename(filename)
145 128 notebook_name = basename[:basename.rfind('.')]
146 129 resources['metadata']['name'] = notebook_name
147 130
148 131 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
149 132 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
150 133
151 134 with io.open(filename, encoding='utf-8') as f:
152 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
135 return self.from_notebook_node(nbformat.read(f, as_version=4), resources=resources, **kw)
153 136
154 137
155 138 def from_file(self, file_stream, resources=None, **kw):
156 139 """
157 140 Convert a notebook from a notebook file.
158 141
159 142 Parameters
160 143 ----------
161 144 file_stream : file-like object
162 145 Notebook file-like object to convert.
163 146 """
164 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
147 return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw)
165 148
166 149
167 150 def register_preprocessor(self, preprocessor, enabled=False):
168 151 """
169 152 Register a preprocessor.
170 153 Preprocessors are classes that act upon the notebook before it is
171 154 passed into the Jinja templating engine. preprocessors are also
172 155 capable of passing additional information to the Jinja
173 156 templating engine.
174 157
175 158 Parameters
176 159 ----------
177 160 preprocessor : preprocessor
178 161 """
179 162 if preprocessor is None:
180 163 raise TypeError('preprocessor')
181 164 isclass = isinstance(preprocessor, type)
182 165 constructed = not isclass
183 166
184 167 # Handle preprocessor's registration based on it's type
185 168 if constructed and isinstance(preprocessor, py3compat.string_types):
186 169 # Preprocessor is a string, import the namespace and recursively call
187 170 # this register_preprocessor method
188 171 preprocessor_cls = import_item(preprocessor)
189 172 return self.register_preprocessor(preprocessor_cls, enabled)
190 173
191 174 if constructed and hasattr(preprocessor, '__call__'):
192 175 # Preprocessor is a function, no need to construct it.
193 176 # Register and return the preprocessor.
194 177 if enabled:
195 178 preprocessor.enabled = True
196 179 self._preprocessors.append(preprocessor)
197 180 return preprocessor
198 181
199 182 elif isclass and isinstance(preprocessor, MetaHasTraits):
200 183 # Preprocessor is configurable. Make sure to pass in new default for
201 184 # the enabled flag if one was specified.
202 185 self.register_preprocessor(preprocessor(parent=self), enabled)
203 186
204 187 elif isclass:
205 188 # Preprocessor is not configurable, construct it
206 189 self.register_preprocessor(preprocessor(), enabled)
207 190
208 191 else:
209 192 # Preprocessor is an instance of something without a __call__
210 193 # attribute.
211 194 raise TypeError('preprocessor')
212 195
213 196
214 197 def _init_preprocessors(self):
215 198 """
216 199 Register all of the preprocessors needed for this exporter, disabled
217 200 unless specified explicitly.
218 201 """
219 202 self._preprocessors = []
220 203
221 204 # Load default preprocessors (not necessarly enabled by default).
222 205 for preprocessor in self.default_preprocessors:
223 206 self.register_preprocessor(preprocessor)
224 207
225 208 # Load user-specified preprocessors. Enable by default.
226 209 for preprocessor in self.preprocessors:
227 210 self.register_preprocessor(preprocessor, enabled=True)
228 211
229 212
230 213 def _init_resources(self, resources):
231 214
232 215 #Make sure the resources dict is of ResourcesDict type.
233 216 if resources is None:
234 217 resources = ResourcesDict()
235 218 if not isinstance(resources, ResourcesDict):
236 219 new_resources = ResourcesDict()
237 220 new_resources.update(resources)
238 221 resources = new_resources
239 222
240 223 #Make sure the metadata extension exists in resources
241 224 if 'metadata' in resources:
242 225 if not isinstance(resources['metadata'], ResourcesDict):
243 226 resources['metadata'] = ResourcesDict(resources['metadata'])
244 227 else:
245 228 resources['metadata'] = ResourcesDict()
246 229 if not resources['metadata']['name']:
247 230 resources['metadata']['name'] = 'Notebook'
248 231
249 232 #Set the output extension
250 233 resources['output_extension'] = self.file_extension
251 234 return resources
252 235
253 236
254 237 def _preprocess(self, nb, resources):
255 238 """
256 239 Preprocess the notebook before passing it into the Jinja engine.
257 240 To preprocess the notebook is to apply all of the
258 241
259 242 Parameters
260 243 ----------
261 244 nb : notebook node
262 245 notebook that is being exported.
263 246 resources : a dict of additional resources that
264 247 can be accessed read/write by preprocessors
265 248 """
266 249
267 250 # Do a copy.deepcopy first,
268 251 # we are never safe enough with what the preprocessors could do.
269 252 nbc = copy.deepcopy(nb)
270 253 resc = copy.deepcopy(resources)
271 254
272 255 #Run each preprocessor on the notebook. Carry the output along
273 256 #to each preprocessor
274 257 for preprocessor in self._preprocessors:
275 258 nbc, resc = preprocessor(nbc, resc)
276 259 return nbc, resc
@@ -1,32 +1,32 b''
1 1 """NotebookExporter class"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from .exporter import Exporter
7 from IPython.nbformat import current as nbformat
7 from IPython import nbformat
8 8 from IPython.utils.traitlets import Enum
9 9
10 10 class NotebookExporter(Exporter):
11 11 """Exports to an IPython notebook."""
12 12
13 nbformat_version = Enum(list(range(2, nbformat.current_nbformat + 1)),
13 nbformat_version = Enum(list(nbformat.versions),
14 14 default_value=nbformat.current_nbformat,
15 15 config=True,
16 16 help="""The nbformat version to write.
17 17 Use this to downgrade notebooks.
18 18 """
19 19 )
20 20 def _file_extension_default(self):
21 21 return 'ipynb'
22 22
23 23 output_mimetype = 'application/json'
24 24
25 25 def from_notebook_node(self, nb, resources=None, **kw):
26 26 nb_copy, resources = super(NotebookExporter, self).from_notebook_node(nb, resources, **kw)
27 if self.nbformat_version != nbformat.current_nbformat:
27 if self.nbformat_version != nb_copy.nbformat:
28 28 resources['output_suffix'] = '.v%i' % self.nbformat_version
29 29 else:
30 30 resources['output_suffix'] = '.nbconvert'
31 31 output = nbformat.writes(nb_copy, version=self.nbformat_version)
32 32 return output, resources
@@ -1,102 +1,90 b''
1 1 """
2 2 Module with tests for export.py
3 3 """
4 4
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
7 #
5 # Copyright (c) IPython Development Team.
8 6 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16 7
17 8 import os
18 9
19 from IPython.nbformat import current as nbformat
10 from IPython import nbformat
20 11
21 12 from .base import ExportersTestsBase
22 13 from ..export import *
23 14 from ..python import PythonExporter
24 15
25 #-----------------------------------------------------------------------------
26 # Class
27 #-----------------------------------------------------------------------------
28 16
29 17 class TestExport(ExportersTestsBase):
30 18 """Contains test functions for export.py"""
31 19
32 20
33 21 def test_export_wrong_name(self):
34 22 """
35 23 Is the right error thrown when a bad template name is used?
36 24 """
37 25 try:
38 26 export_by_name('not_a_name', self._get_notebook())
39 27 except ExporterNameError as e:
40 28 pass
41 29
42 30
43 31 def test_export_filename(self):
44 32 """
45 33 Can a notebook be exported by filename?
46 34 """
47 35 (output, resources) = export_by_name('python', self._get_notebook())
48 36 assert len(output) > 0
49 37
50 38
51 39 def test_export_nbnode(self):
52 40 """
53 41 Can a notebook be exported by a notebook node handle?
54 42 """
55 43 with open(self._get_notebook(), 'r') as f:
56 notebook = nbformat.read(f, 'json')
44 notebook = nbformat.read(f, 4)
57 45 (output, resources) = export_by_name('python', notebook)
58 46 assert len(output) > 0
59 47
60 48
61 49 def test_export_filestream(self):
62 50 """
63 51 Can a notebook be exported by a filesteam?
64 52 """
65 53 with open(self._get_notebook(), 'r') as f:
66 54 (output, resources) = export_by_name('python', f)
67 55 assert len(output) > 0
68 56
69 57
70 58 def test_export_using_exporter(self):
71 59 """
72 60 Can a notebook be exported using an instanciated exporter?
73 61 """
74 62 (output, resources) = export(PythonExporter(), self._get_notebook())
75 63 assert len(output) > 0
76 64
77 65
78 66 def test_export_using_exporter_class(self):
79 67 """
80 68 Can a notebook be exported using an exporter class type?
81 69 """
82 70 (output, resources) = export(PythonExporter, self._get_notebook())
83 71 assert len(output) > 0
84 72
85 73
86 74 def test_export_resources(self):
87 75 """
88 76 Can a notebook be exported along with a custom resources dict?
89 77 """
90 78 (output, resources) = export(PythonExporter, self._get_notebook(), resources={})
91 79 assert len(output) > 0
92 80
93 81
94 82 def test_no_exporter(self):
95 83 """
96 84 Is the right error thrown if no exporter is provided?
97 85 """
98 86 try:
99 87 (output, resources) = export(None, self._get_notebook())
100 88 except TypeError:
101 89 pass
102 90
@@ -1,116 +1,117 b''
1 1 """Tests for Latex exporter"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import os.path
7 7 import textwrap
8 8 import re
9 9
10 10 from .base import ExportersTestsBase
11 11 from ..latex import LatexExporter
12 from IPython.nbformat import current
12 from IPython.nbformat import write
13 from IPython.nbformat import v4
13 14 from IPython.testing.decorators import onlyif_cmds_exist
14 15 from IPython.utils.tempdir import TemporaryDirectory
15 16
16 17
17 18 class TestLatexExporter(ExportersTestsBase):
18 19 """Contains test functions for latex.py"""
19 20
20 21 exporter_class = LatexExporter
21 22 should_include_raw = ['latex']
22 23
23 24 def test_constructor(self):
24 25 """
25 26 Can a LatexExporter be constructed?
26 27 """
27 28 LatexExporter()
28 29
29 30
30 31 @onlyif_cmds_exist('pandoc')
31 32 def test_export(self):
32 33 """
33 34 Can a LatexExporter export something?
34 35 """
35 36 (output, resources) = LatexExporter().from_filename(self._get_notebook())
36 37 assert len(output) > 0
37 38
38 39
39 40 @onlyif_cmds_exist('pandoc')
40 41 def test_export_book(self):
41 42 """
42 43 Can a LatexExporter export using 'report' template?
43 44 """
44 45 (output, resources) = LatexExporter(template_file='report').from_filename(self._get_notebook())
45 46 assert len(output) > 0
46 47
47 48
48 49 @onlyif_cmds_exist('pandoc')
49 50 def test_export_basic(self):
50 51 """
51 52 Can a LatexExporter export using 'article' template?
52 53 """
53 54 (output, resources) = LatexExporter(template_file='article').from_filename(self._get_notebook())
54 55 assert len(output) > 0
55 56
56 57
57 58 @onlyif_cmds_exist('pandoc')
58 59 def test_export_article(self):
59 60 """
60 61 Can a LatexExporter export using 'article' template?
61 62 """
62 63 (output, resources) = LatexExporter(template_file='article').from_filename(self._get_notebook())
63 64 assert len(output) > 0
64 65
65 66 @onlyif_cmds_exist('pandoc')
66 67 def test_very_long_cells(self):
67 68 """
68 69 Torture test that long cells do not cause issues
69 70 """
70 71 lorem_ipsum_text = textwrap.dedent("""\
71 72 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
72 73 dignissim, ipsum non facilisis tempus, dui felis tincidunt metus,
73 74 nec pulvinar neque odio eget risus. Nulla nisi lectus, cursus
74 75 suscipit interdum at, ultrices sit amet orci. Mauris facilisis
75 76 imperdiet elit, vitae scelerisque ipsum dignissim non. Integer
76 77 consequat malesuada neque sit amet pulvinar. Curabitur pretium
77 78 ut turpis eget aliquet. Maecenas sagittis lacus sed lectus
78 79 volutpat, eu adipiscing purus pulvinar. Maecenas consequat
79 80 luctus urna, eget cursus quam mollis a. Aliquam vitae ornare
80 81 erat, non hendrerit urna. Sed eu diam nec massa egestas pharetra
81 82 at nec tellus. Fusce feugiat lacus quis urna sollicitudin volutpat.
82 83 Quisque at sapien non nibh feugiat tempus ac ultricies purus.
83 84 """)
84 85 lorem_ipsum_text = lorem_ipsum_text.replace("\n"," ") + "\n\n"
85 86 large_lorem_ipsum_text = "".join([lorem_ipsum_text]*3000)
86 87
87 88 notebook_name = "lorem_ipsum_long.ipynb"
88 nb = current.new_notebook(
89 nb = v4.new_notebook(
89 90 cells=[
90 current.new_markdown_cell(source=large_lorem_ipsum_text)
91 v4.new_markdown_cell(source=large_lorem_ipsum_text)
91 92 ]
92 93 )
93 94
94 95 with TemporaryDirectory() as td:
95 96 nbfile = os.path.join(td, notebook_name)
96 97 with open(nbfile, 'w') as f:
97 current.write(nb, f, 'ipynb')
98 write(f, nb, 4)
98 99
99 (output, resources) = LatexExporter(template_file='article').from_filename(nbfile)
100 (output, resources) = LatexExporter(template_file='article').from_filename(nbfile)
100 101 assert len(output) > 0
101 102
102 103 @onlyif_cmds_exist('pandoc')
103 104 def test_prompt_number_color(self):
104 105 """
105 106 Does LatexExporter properly format input and output prompts in color?
106 107 """
107 108 (output, resources) = LatexExporter().from_filename(
108 109 self._get_notebook(nb_name="prompt_numbers.ipynb"))
109 110 in_regex = r"In \[\{\\color\{incolor\}(.*)\}\]:"
110 111 out_regex = r"Out\[\{\\color\{outcolor\}(.*)\}\]:"
111 112
112 113 ins = ["2", "10", " ", " ", "*", "0"]
113 114 outs = ["10"]
114 115
115 116 assert re.findall(in_regex, output) == ins
116 117 assert re.findall(out_regex, output) == outs
@@ -1,39 +1,39 b''
1 1 """Tests for notebook.py"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import json
7 7
8 8 from .base import ExportersTestsBase
9 9 from ..notebook import NotebookExporter
10 10
11 from IPython.nbformat.current import validate
11 from IPython.nbformat import validate
12 12 from IPython.testing.tools import assert_big_text_equal
13 13
14 14 class TestNotebookExporter(ExportersTestsBase):
15 15 """Contains test functions for notebook.py"""
16 16
17 17 exporter_class = NotebookExporter
18 18
19 19 def test_export(self):
20 20 """
21 21 Does the NotebookExporter return the file unchanged?
22 22 """
23 23 with open(self._get_notebook()) as f:
24 24 file_contents = f.read()
25 25 (output, resources) = self.exporter_class().from_filename(self._get_notebook())
26 26 assert len(output) > 0
27 27 assert_big_text_equal(output, file_contents)
28 28
29 29 def test_downgrade_3(self):
30 30 exporter = self.exporter_class(nbformat_version=3)
31 31 (output, resources) = exporter.from_filename(self._get_notebook())
32 32 nb = json.loads(output)
33 33 validate(nb)
34 34
35 35 def test_downgrade_2(self):
36 36 exporter = self.exporter_class(nbformat_version=2)
37 37 (output, resources) = exporter.from_filename(self._get_notebook())
38 38 nb = json.loads(output)
39 39 self.assertEqual(nb['nbformat'], 2)
@@ -1,62 +1,54 b''
1 1 """Tests for RSTExporter"""
2 2
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
5 #
3 # Copyright (c) IPython Development Team.
6 4 # Distributed under the terms of the Modified BSD License.
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14 5
15 6 import io
16 7
17 from IPython.nbformat import current
8 from IPython import nbformat
9 from IPython.nbformat import v4
18 10
19 11 from .base import ExportersTestsBase
20 12 from ..rst import RSTExporter
21 13 from IPython.testing.decorators import onlyif_cmds_exist
22 14
23 15
24 16 class TestRSTExporter(ExportersTestsBase):
25 17 """Tests for RSTExporter"""
26 18
27 19 exporter_class = RSTExporter
28 20 should_include_raw = ['rst']
29 21
30 22 def test_constructor(self):
31 23 """
32 24 Can a RSTExporter be constructed?
33 25 """
34 26 RSTExporter()
35 27
36 28
37 29 @onlyif_cmds_exist('pandoc')
38 30 def test_export(self):
39 31 """
40 32 Can a RSTExporter export something?
41 33 """
42 34 (output, resources) = RSTExporter().from_filename(self._get_notebook())
43 35 assert len(output) > 0
44 36
45 37 @onlyif_cmds_exist('pandoc')
46 38 def test_empty_code_cell(self):
47 39 """No empty code cells in rst"""
48 40 nbname = self._get_notebook()
49 41 with io.open(nbname, encoding='utf8') as f:
50 nb = current.read(f, 'json')
42 nb = nbformat.read(f, 4)
51 43
52 44 exporter = self.exporter_class()
53 45
54 46 (output, resources) = exporter.from_notebook_node(nb)
55 47 # add an empty code cell
56 48 nb.cells.append(
57 current.new_code_cell(source="")
49 v4.new_code_cell(source="")
58 50 )
59 51 (output2, resources) = exporter.from_notebook_node(nb)
60 52 # adding an empty code cell shouldn't change output
61 53 self.assertEqual(output.strip(), output2.strip())
62 54
@@ -1,111 +1,111 b''
1 1 """Module containing a preprocessor that removes the outputs from code cells"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import os
7 import sys
8 7
9 8 try:
10 9 from queue import Empty # Py 3
11 10 except ImportError:
12 11 from Queue import Empty # Py 2
13 12
14 13 from IPython.utils.traitlets import List, Unicode
15 14
16 from IPython.nbformat.current import reads, writes, output_from_msg
15 from IPython.nbformat.v4 import output_from_msg
17 16 from .base import Preprocessor
18 17 from IPython.utils.traitlets import Integer
19 18
19
20 20 class ExecutePreprocessor(Preprocessor):
21 21 """
22 22 Executes all the cells in a notebook
23 23 """
24 24
25 25 timeout = Integer(30, config=True,
26 26 help="The time to wait (in seconds) for output from executions."
27 27 )
28 28
29 29 extra_arguments = List(Unicode)
30 30
31 31 def preprocess(self, nb, resources):
32 32 from IPython.kernel import run_kernel
33 33 kernel_name = nb.metadata.get('kernelspec', {}).get('name', 'python')
34 34 self.log.info("Executing notebook with kernel: %s" % kernel_name)
35 35 with run_kernel(kernel_name=kernel_name,
36 36 extra_arguments=self.extra_arguments,
37 37 stderr=open(os.devnull, 'w')) as kc:
38 38 self.kc = kc
39 39 nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources)
40 40 return nb, resources
41 41
42 42 def preprocess_cell(self, cell, resources, cell_index):
43 43 """
44 44 Apply a transformation on each code cell. See base.py for details.
45 45 """
46 46 if cell.cell_type != 'code':
47 47 return cell, resources
48 48 try:
49 49 outputs = self.run_cell(self.kc.shell_channel, self.kc.iopub_channel, cell)
50 50 except Exception as e:
51 51 self.log.error("failed to run cell: " + repr(e))
52 52 self.log.error(str(cell.source))
53 53 raise
54 54 cell.outputs = outputs
55 55 return cell, resources
56 56
57 57 def run_cell(self, shell, iopub, cell):
58 58 msg_id = shell.execute(cell.source)
59 59 self.log.debug("Executing cell:\n%s", cell.source)
60 60 # wait for finish, with timeout
61 61 while True:
62 62 try:
63 63 msg = shell.get_msg(timeout=self.timeout)
64 64 except Empty:
65 65 self.log.error("Timeout waiting for execute reply")
66 66 raise
67 67 if msg['parent_header'].get('msg_id') == msg_id:
68 68 break
69 69 else:
70 70 # not our reply
71 71 continue
72 72
73 73 outs = []
74 74
75 75 while True:
76 76 try:
77 77 msg = iopub.get_msg(timeout=self.timeout)
78 78 except Empty:
79 79 self.log.warn("Timeout waiting for IOPub output")
80 80 break
81 81 if msg['parent_header'].get('msg_id') != msg_id:
82 82 # not an output from our execution
83 83 continue
84 84
85 85 msg_type = msg['msg_type']
86 86 self.log.debug("output: %s", msg_type)
87 87 content = msg['content']
88 88
89 89 # set the prompt number for the input and the output
90 90 if 'execution_count' in content:
91 91 cell['execution_count'] = content['execution_count']
92 92
93 93 if msg_type == 'status':
94 94 if content['execution_state'] == 'idle':
95 95 break
96 96 else:
97 97 continue
98 98 elif msg_type == 'execute_input':
99 99 continue
100 100 elif msg_type == 'clear_output':
101 101 outs = []
102 102 continue
103 103
104 104 try:
105 105 out = output_from_msg(msg)
106 106 except ValueError:
107 107 self.log.error("unhandled iopub msg: " + msg_type)
108 108 else:
109 109 outs.append(out)
110 110
111 111 return outs
@@ -1,41 +1,41 b''
1 1 """utility functions for preprocessor tests"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 from IPython.nbformat import current as nbformat
6 from IPython.nbformat import v4 as nbformat
7 7
8 8 from ...tests.base import TestsBase
9 9 from ...exporters.exporter import ResourcesDict
10 10
11 11
12 12 class PreprocessorTestsBase(TestsBase):
13 13 """Contains test functions preprocessor tests"""
14 14
15 15
16 16 def build_notebook(self):
17 17 """Build a notebook in memory for use with preprocessor tests"""
18 18
19 19 outputs = [
20 20 nbformat.new_output("stream", name="stdout", text="a"),
21 21 nbformat.new_output("display_data", data={'text/plain': 'b'}),
22 22 nbformat.new_output("stream", name="stdout", text="c"),
23 23 nbformat.new_output("stream", name="stdout", text="d"),
24 24 nbformat.new_output("stream", name="stderr", text="e"),
25 25 nbformat.new_output("stream", name="stderr", text="f"),
26 26 nbformat.new_output("display_data", data={'image/png': 'Zw=='}), # g
27 27 nbformat.new_output("display_data", data={'application/pdf': 'aA=='}), # h
28 28 ]
29 29
30 30 cells=[nbformat.new_code_cell(source="$ e $", execution_count=1, outputs=outputs),
31 31 nbformat.new_markdown_cell(source="$ e $")]
32 32
33 33 return nbformat.new_notebook(cells=cells)
34 34
35 35
36 36 def build_resources(self):
37 37 """Build an empty resources dictionary."""
38 38
39 39 res = ResourcesDict()
40 40 res['metadata'] = ResourcesDict()
41 41 return res
@@ -1,35 +1,33 b''
1 1 """
2 2 Module with tests for the clearoutput preprocessor.
3 3 """
4 4
5 5 # Copyright (c) IPython Development Team.
6 6 # Distributed under the terms of the Modified BSD License.
7 7
8 from IPython.nbformat import current as nbformat
9
10 8 from .base import PreprocessorTestsBase
11 9 from ..clearoutput import ClearOutputPreprocessor
12 10
13 11
14 12 class TestClearOutput(PreprocessorTestsBase):
15 13 """Contains test functions for clearoutput.py"""
16 14
17 15
18 16 def build_preprocessor(self):
19 17 """Make an instance of a preprocessor"""
20 18 preprocessor = ClearOutputPreprocessor()
21 19 preprocessor.enabled = True
22 20 return preprocessor
23 21
24 22 def test_constructor(self):
25 23 """Can a ClearOutputPreprocessor be constructed?"""
26 24 self.build_preprocessor()
27 25
28 26 def test_output(self):
29 27 """Test the output of the ClearOutputPreprocessor"""
30 28 nb = self.build_notebook()
31 29 res = self.build_resources()
32 30 preprocessor = self.build_preprocessor()
33 31 nb, res = preprocessor(nb, res)
34 32 assert nb.cells[0].outputs == []
35 33 assert nb.cells[0].execution_count is None
@@ -1,58 +1,58 b''
1 1 """Tests for the coalescestreams preprocessor"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 from IPython.nbformat import current as nbformat
6 from IPython.nbformat import v4 as nbformat
7 7
8 8 from .base import PreprocessorTestsBase
9 9 from ..coalescestreams import coalesce_streams
10 10
11 11
12 12 class TestCoalesceStreams(PreprocessorTestsBase):
13 13 """Contains test functions for coalescestreams.py"""
14 14
15 15 def test_coalesce_streams(self):
16 16 """coalesce_streams preprocessor output test"""
17 17 nb = self.build_notebook()
18 18 res = self.build_resources()
19 19 nb, res = coalesce_streams(nb, res)
20 20 outputs = nb.cells[0].outputs
21 21 self.assertEqual(outputs[0].text, "a")
22 22 self.assertEqual(outputs[1].output_type, "display_data")
23 23 self.assertEqual(outputs[2].text, "cd")
24 24 self.assertEqual(outputs[3].text, "ef")
25 25
26 26 def test_coalesce_sequenced_streams(self):
27 27 """Can the coalesce streams preprocessor merge a sequence of streams?"""
28 28 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="0"),
29 29 nbformat.new_output(output_type="stream", name="stdout", text="1"),
30 30 nbformat.new_output(output_type="stream", name="stdout", text="2"),
31 31 nbformat.new_output(output_type="stream", name="stdout", text="3"),
32 32 nbformat.new_output(output_type="stream", name="stdout", text="4"),
33 33 nbformat.new_output(output_type="stream", name="stdout", text="5"),
34 34 nbformat.new_output(output_type="stream", name="stdout", text="6"),
35 35 nbformat.new_output(output_type="stream", name="stdout", text="7")]
36 36 cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)]
37 37
38 38 nb = nbformat.new_notebook(cells=cells)
39 39 res = self.build_resources()
40 40 nb, res = coalesce_streams(nb, res)
41 41 outputs = nb.cells[0].outputs
42 42 self.assertEqual(outputs[0].text, u'01234567')
43 43
44 44 def test_coalesce_replace_streams(self):
45 45 """Are \\r characters handled?"""
46 46 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="z"),
47 47 nbformat.new_output(output_type="stream", name="stdout", text="\ra"),
48 48 nbformat.new_output(output_type="stream", name="stdout", text="\nz\rb"),
49 49 nbformat.new_output(output_type="stream", name="stdout", text="\nz"),
50 50 nbformat.new_output(output_type="stream", name="stdout", text="\rc\n"),
51 51 nbformat.new_output(output_type="stream", name="stdout", text="z\rz\rd")]
52 52 cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)]
53 53
54 54 nb = nbformat.new_notebook(cells=cells)
55 55 res = self.build_resources()
56 56 nb, res = coalesce_streams(nb, res)
57 57 outputs = nb.cells[0].outputs
58 58 self.assertEqual(outputs[0].text, u'a\nb\nc\nd')
@@ -1,91 +1,92 b''
1 1 """
2 2 Module with tests for the execute preprocessor.
3 3 """
4 4
5 5 # Copyright (c) IPython Development Team.
6 6 # Distributed under the terms of the Modified BSD License.
7 7
8 8 import copy
9 9 import glob
10 import io
10 11 import os
11 12 import re
12 13
13 from IPython.nbformat import current as nbformat
14 from IPython import nbformat
14 15
15 16 from .base import PreprocessorTestsBase
16 17 from ..execute import ExecutePreprocessor
17 18
18 19 from IPython.nbconvert.filters import strip_ansi
19 20
20 21 addr_pat = re.compile(r'0x[0-9a-f]{7,9}')
21 22
22 23 class TestExecute(PreprocessorTestsBase):
23 24 """Contains test functions for execute.py"""
24 25
25 26 @staticmethod
26 27 def normalize_output(output):
27 28 """
28 29 Normalizes outputs for comparison.
29 30 """
30 31 output = dict(output)
31 32 if 'metadata' in output:
32 33 del output['metadata']
33 34 if 'text' in output:
34 35 output['text'] = re.sub(addr_pat, '<HEXADDR>', output['text'])
35 36 if 'text/plain' in output.get('data', {}):
36 37 output['data']['text/plain'] = \
37 38 re.sub(addr_pat, '<HEXADDR>', output['data']['text/plain'])
38 39 if 'traceback' in output:
39 40 tb = []
40 41 for line in output['traceback']:
41 42 tb.append(strip_ansi(line))
42 43 output['traceback'] = tb
43 44
44 45 return output
45 46
46 47
47 48 def assert_notebooks_equal(self, expected, actual):
48 49 expected_cells = expected['cells']
49 50 actual_cells = actual['cells']
50 51 self.assertEqual(len(expected_cells), len(actual_cells))
51 52
52 53 for expected_cell, actual_cell in zip(expected_cells, actual_cells):
53 54 expected_outputs = expected_cell.get('outputs', [])
54 55 actual_outputs = actual_cell.get('outputs', [])
55 56 normalized_expected_outputs = list(map(self.normalize_output, expected_outputs))
56 57 normalized_actual_outputs = list(map(self.normalize_output, actual_outputs))
57 58 self.assertEqual(normalized_expected_outputs, normalized_actual_outputs)
58 59
59 60 expected_execution_count = expected_cell.get('execution_count', None)
60 61 actual_execution_count = actual_cell.get('execution_count', None)
61 62 self.assertEqual(expected_execution_count, actual_execution_count)
62 63
63 64
64 65 def build_preprocessor(self):
65 66 """Make an instance of a preprocessor"""
66 67 preprocessor = ExecutePreprocessor()
67 68 preprocessor.enabled = True
68 69 return preprocessor
69 70
70 71
71 72 def test_constructor(self):
72 73 """Can a ExecutePreprocessor be constructed?"""
73 74 self.build_preprocessor()
74 75
75 76
76 77 def test_run_notebooks(self):
77 78 """Runs a series of test notebooks and compares them to their actual output"""
78 79 current_dir = os.path.dirname(__file__)
79 80 input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb'))
80 81 for filename in input_files:
81 with open(os.path.join(current_dir, 'files', filename)) as f:
82 input_nb = nbformat.read(f, 'ipynb')
82 with io.open(os.path.join(current_dir, 'files', filename)) as f:
83 input_nb = nbformat.read(f, 4)
83 84 res = self.build_resources()
84 85 preprocessor = self.build_preprocessor()
85 86 cleaned_input_nb = copy.deepcopy(input_nb)
86 87 for cell in cleaned_input_nb.cells:
87 88 if 'execution_count' in cell:
88 89 del cell['execution_count']
89 90 cell['outputs'] = []
90 91 output_nb, _ = preprocessor(cleaned_input_nb, res)
91 92 self.assert_notebooks_equal(output_nb, input_nb)
@@ -1,78 +1,78 b''
1 1 """Tests for the revealhelp preprocessor"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 from IPython.nbformat import current as nbformat
6 from IPython.nbformat import v4 as nbformat
7 7
8 8 from .base import PreprocessorTestsBase
9 9 from ..revealhelp import RevealHelpPreprocessor
10 10
11 11
12 12 class Testrevealhelp(PreprocessorTestsBase):
13 13 """Contains test functions for revealhelp.py"""
14 14
15 15 def build_notebook(self):
16 16 """Build a reveal slides notebook in memory for use with tests.
17 17 Overrides base in PreprocessorTestsBase"""
18 18
19 19 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a")]
20 20
21 21 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
22 22 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
23 23
24 24 cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs),
25 25 nbformat.new_markdown_cell(source="", metadata=slide_metadata),
26 26 nbformat.new_code_cell(source="", execution_count=2, outputs=outputs),
27 27 nbformat.new_markdown_cell(source="", metadata=slide_metadata),
28 28 nbformat.new_markdown_cell(source="", metadata=subslide_metadata)]
29 29
30 30 return nbformat.new_notebook(cells=cells)
31 31
32 32
33 33 def build_preprocessor(self):
34 34 """Make an instance of a preprocessor"""
35 35 preprocessor = RevealHelpPreprocessor()
36 36 preprocessor.enabled = True
37 37 return preprocessor
38 38
39 39
40 40 def test_constructor(self):
41 41 """Can a RevealHelpPreprocessor be constructed?"""
42 42 self.build_preprocessor()
43 43
44 44
45 45 def test_reveal_attribute(self):
46 46 """Make sure the reveal url_prefix resources is set"""
47 47 nb = self.build_notebook()
48 48 res = self.build_resources()
49 49 preprocessor = self.build_preprocessor()
50 50 nb, res = preprocessor(nb, res)
51 51 assert 'reveal' in res
52 52 assert 'url_prefix' in res['reveal']
53 53
54 54
55 55 def test_reveal_output(self):
56 56 """Make sure that the reveal preprocessor """
57 57 nb = self.build_notebook()
58 58 res = self.build_resources()
59 59 preprocessor = self.build_preprocessor()
60 60 nb, res = preprocessor(nb, res)
61 61 cells = nb.cells
62 62
63 63 # Make sure correct metadata tags are available on every cell.
64 64 for cell in cells:
65 65 assert 'slide_type' in cell.metadata
66 66
67 67 # Make sure slide end is only applied to the cells preceeding slide
68 68 # cells.
69 69 assert 'slide_helper' in cells[1].metadata
70 70 self.assertEqual(cells[1].metadata['slide_helper'], '-')
71 71
72 72 # Verify 'slide-end'
73 73 assert 'slide_helper' in cells[0].metadata
74 74 self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end')
75 75 assert 'slide_helper' in cells[2].metadata
76 76 self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end')
77 77 assert 'slide_helper' in cells[3].metadata
78 78 self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end')
@@ -1,74 +1,74 b''
1 1 """Tests for the svg2pdf preprocessor"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from IPython.testing import decorators as dec
7 from IPython.nbformat import current as nbformat
7 from IPython.nbformat import v4 as nbformat
8 8
9 9 from .base import PreprocessorTestsBase
10 10 from ..svg2pdf import SVG2PDFPreprocessor
11 11
12 12
13 13 class Testsvg2pdf(PreprocessorTestsBase):
14 14 """Contains test functions for svg2pdf.py"""
15 15
16 16 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
17 17 <!-- Created with Inkscape (http://www.inkscape.org/) -->
18 18 <svg
19 19 xmlns:svg="http://www.w3.org/2000/svg"
20 20 xmlns="http://www.w3.org/2000/svg"
21 21 version="1.0"
22 22 x="0.00000000"
23 23 y="0.00000000"
24 24 width="500.00000"
25 25 height="500.00000"
26 26 id="svg2">
27 27 <defs
28 28 id="defs4" />
29 29 <g
30 30 id="layer1">
31 31 <rect
32 32 width="300.00000"
33 33 height="300.00000"
34 34 x="100.00000"
35 35 y="100.00000"
36 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 37 id="rect5719" />
38 38 </g>
39 39 </svg>"""
40 40
41 41 def build_notebook(self):
42 42 """Build a reveal slides notebook in memory for use with tests.
43 43 Overrides base in PreprocessorTestsBase"""
44 44
45 45 outputs = [nbformat.new_output(output_type="image/svg+xml", output_svg=self.simple_svg)]
46 46
47 47 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
48 48 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
49 49
50 50 cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs)]
51 51
52 52 return nbformat.new_notebook(cells=cells)
53 53
54 54
55 55 def build_preprocessor(self):
56 56 """Make an instance of a preprocessor"""
57 57 preprocessor = SVG2PDFPreprocessor()
58 58 preprocessor.enabled = True
59 59 return preprocessor
60 60
61 61
62 62 def test_constructor(self):
63 63 """Can a SVG2PDFPreprocessor be constructed?"""
64 64 self.build_preprocessor()
65 65
66 66
67 67 @dec.onlyif_cmds_exist('inkscape')
68 68 def test_output(self):
69 69 """Test the output of the SVG2PDFPreprocessor"""
70 70 nb = self.build_notebook()
71 71 res = self.build_resources()
72 72 preprocessor = self.build_preprocessor()
73 73 nb, res = preprocessor(nb, res)
74 74 self.assertIn('application/pdf', nb.cells[0].outputs[0])
@@ -1,149 +1,148 b''
1 1 """Base test class for nbconvert"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import io
7 7 import os
8 8 import glob
9 9 import shutil
10 10 import unittest
11 11
12 12 import IPython
13 from IPython.nbformat import current
13 from IPython.nbformat import v4, write
14 14 from IPython.utils.tempdir import TemporaryWorkingDirectory
15 15 from IPython.utils.path import get_ipython_package_dir
16 16 from IPython.utils.process import get_output_error_code
17 17 from IPython.testing.tools import get_ipython_cmd
18 18
19 19 # a trailing space allows for simpler concatenation with the other arguments
20 20 ipy_cmd = get_ipython_cmd(as_string=True) + " "
21 21
22 22
23 23 class TestsBase(unittest.TestCase):
24 24 """Base tests class. Contains useful fuzzy comparison and nbconvert
25 25 functions."""
26 26
27 27
28 28 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
29 29 fuzzy_spacing=True, ignore_spaces=False,
30 30 ignore_newlines=False, case_sensitive=False, leave_padding=False):
31 31 """
32 32 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
33 33 comparison that ignores insignificant differences in the two comparands.
34 34 The significance of certain differences can be specified via the keyword
35 35 parameters of this method.
36 36 """
37 37
38 38 if not leave_padding:
39 39 a = a.strip()
40 40 b = b.strip()
41 41
42 42 if ignore_newlines:
43 43 a = a.replace('\n', '')
44 44 b = b.replace('\n', '')
45 45
46 46 if newlines_are_spaces:
47 47 a = a.replace('\n', ' ')
48 48 b = b.replace('\n', ' ')
49 49
50 50 if tabs_are_spaces:
51 51 a = a.replace('\t', ' ')
52 52 b = b.replace('\t', ' ')
53 53
54 54 if ignore_spaces:
55 55 a = a.replace(' ', '')
56 56 b = b.replace(' ', '')
57 57
58 58 if fuzzy_spacing:
59 59 a = self.recursive_replace(a, ' ', ' ')
60 60 b = self.recursive_replace(b, ' ', ' ')
61 61
62 62 if not case_sensitive:
63 63 a = a.lower()
64 64 b = b.lower()
65 65
66 66 self.assertEqual(a, b)
67 67
68 68
69 69 def recursive_replace(self, text, search, replacement):
70 70 """
71 71 Performs a recursive replacement operation. Replaces all instances
72 72 of a search string in a text string with a replacement string until
73 73 the search string no longer exists. Recursion is needed because the
74 74 replacement string may generate additional search strings.
75 75
76 76 For example:
77 77 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
78 78 Another replacement cds "Hi" (the desired output)
79 79
80 80 Parameters
81 81 ----------
82 82 text : string
83 83 Text to replace in.
84 84 search : string
85 85 String to search for within "text"
86 86 replacement : string
87 87 String to replace "search" with
88 88 """
89 89 while search in text:
90 90 text = text.replace(search, replacement)
91 91 return text
92 92
93 93 def create_temp_cwd(self, copy_filenames=None):
94 94 temp_dir = TemporaryWorkingDirectory()
95 95
96 96 #Copy the files if requested.
97 97 if copy_filenames is not None:
98 98 self.copy_files_to(copy_filenames, dest=temp_dir.name)
99 99
100 100 #Return directory handler
101 101 return temp_dir
102 102
103 103 def create_empty_notebook(self, path):
104 nb = current.new_notebook()
104 nb = v4.new_notebook()
105 105 with io.open(path, 'w', encoding='utf-8') as f:
106 current.write(nb, f, 'json')
107
106 write(f, nb, 4)
108 107
109 108 def copy_files_to(self, copy_filenames, dest='.'):
110 109 "Copy test files into the destination directory"
111 110 if not os.path.isdir(dest):
112 111 os.makedirs(dest)
113 112 files_path = self._get_files_path()
114 113 for pattern in copy_filenames:
115 114 for match in glob.glob(os.path.join(files_path, pattern)):
116 115 shutil.copyfile(match, os.path.join(dest, os.path.basename(match)))
117 116
118 117
119 118 def _get_files_path(self):
120 119
121 120 #Get the relative path to this module in the IPython directory.
122 121 names = self.__module__.split('.')[1:-1]
123 122 names.append('files')
124 123
125 124 #Build a path using the IPython directory and the relative path we just
126 125 #found.
127 126 path = get_ipython_package_dir()
128 127 for name in names:
129 128 path = os.path.join(path, name)
130 129 return path
131 130
132 131
133 132 def call(self, parameters, ignore_return_code=False):
134 133 """
135 134 Execute a, IPython shell command, listening for both Errors and non-zero
136 135 return codes.
137 136
138 137 Parameters
139 138 ----------
140 139 parameters : str
141 140 List of parameters to pass to IPython.
142 141 ignore_return_code : optional bool (default False)
143 142 Throw an OSError if the return code
144 143 """
145 144
146 145 stdout, stderr, retcode = get_output_error_code(ipy_cmd + parameters)
147 146 if not (retcode == 0 or ignore_return_code):
148 147 raise OSError(stderr)
149 148 return stdout, stderr
General Comments 0
You need to be logged in to leave comments. Login now