##// END OF EJS Templates
Exporter -> TemplateExporter / BaseExporter
Matthias BUSSONNIER -
Show More
@@ -1,9 +1,9 b''
1 1 from .export import *
2 2 from .html import HTMLExporter
3 3 from .slides import SlidesExporter
4 from .exporter import Exporter
4 from .exporter import TemplateExporter
5 5 from .latex import LatexExporter
6 6 from .markdown import MarkdownExporter
7 7 from .python import PythonExporter
8 8 from .rst import RSTExporter
9 9 from .baseexporter import BaseExporter
@@ -1,282 +1,282 b''
1 """This module defines Exporter, a highly configurable converter
1 """This module defines BaseExporter, a highly configurable converter
2 2 that uses Jinja2 to export notebook files into different formats.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from __future__ import print_function, absolute_import
18 18
19 19 # Stdlib imports
20 20 import io
21 21 import os
22 22 import copy
23 23 import collections
24 24 import datetime
25 25
26 26
27 27 # IPython imports
28 28 from IPython.config.configurable import LoggingConfigurable
29 29 from IPython.config import Config
30 30 from IPython.nbformat import current as nbformat
31 31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
32 32 from IPython.utils.importstring import import_item
33 33 from IPython.utils import py3compat
34 34
35 35 from IPython.nbconvert import transformers as nbtransformers
36 36
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Class
40 40 #-----------------------------------------------------------------------------
41 41
42 42 class ResourcesDict(collections.defaultdict):
43 43 def __missing__(self, key):
44 44 return ''
45 45
46 46
47 47 class BaseExporter(LoggingConfigurable):
48 48 """
49 49 Base Exporter Class that only conver notebook to notebook
50 50 and apply the transformers and provide basic methods for
51 51 reading a notebook from different sources.
52 52
53 53 """
54 54
55 55 # finish the docstring
56 56
57 57 file_extension = Unicode(
58 58 'txt', config=True,
59 59 help="Extension of the file that should be written to disk"
60 60 )
61 61
62 62 #Configurability, allows the user to easily add transformers.
63 63 transformers = List(config=True,
64 64 help="""List of transformers, by name or namespace, to enable.""")
65 65
66 66 _transformers = None
67 67
68 68 default_transformers = List([nbtransformers.coalesce_streams,
69 69 nbtransformers.SVG2PDFTransformer,
70 70 nbtransformers.ExtractOutputTransformer,
71 71 nbtransformers.CSSHTMLHeaderTransformer,
72 72 nbtransformers.RevealHelpTransformer,
73 73 nbtransformers.LatexTransformer,
74 74 nbtransformers.SphinxTransformer],
75 75 config=True,
76 76 help="""List of transformers available by default, by name, namespace,
77 77 instance, or type.""")
78 78
79 79
80 80 def __init__(self, config=None, **kw):
81 81 """
82 82 Public constructor
83 83
84 84 Parameters
85 85 ----------
86 86 config : config
87 87 User configuration instance.
88 88 """
89 89 if not config:
90 90 config = self.default_config
91 91
92 92 super(BaseExporter, self).__init__(config=config, **kw)
93 93
94 94 #Init
95 95 self._init_transformers()
96 96
97 97
98 98 @property
99 99 def default_config(self):
100 100 return Config()
101 101
102 102 def _config_changed(self, name, old, new):
103 103 """When setting config, make sure to start with our default_config"""
104 104 c = self.default_config
105 105 if new:
106 106 c.merge(new)
107 107 if c != old:
108 108 self.config = c
109 109 super(BaseExporter, self)._config_changed(name, old, c)
110 110
111 111
112 112 def from_notebook_node(self, nb, resources=None):
113 113 """
114 114 Convert a notebook from a notebook node instance.
115 115
116 116 Parameters
117 117 ----------
118 118 nb : Notebook node
119 119 resources : dict (**kw)
120 120 of additional resources that can be accessed read/write by
121 121 transformers.
122 122 """
123 123 nb_copy = copy.deepcopy(nb)
124 124 resources = self._init_resources(resources)
125 125
126 126 # Preprocess
127 127 nb_copy, resources = self._transform(nb_copy, resources)
128 128
129 129 return nb_copy, resources
130 130
131 131
132 132 def from_filename(self, filename, resources=None, **kw):
133 133 """
134 134 Convert a notebook from a notebook file.
135 135
136 136 Parameters
137 137 ----------
138 138 filename : str
139 139 Full filename of the notebook file to open and convert.
140 140 """
141 141
142 142 #Pull the metadata from the filesystem.
143 143 if resources is None:
144 144 resources = ResourcesDict()
145 145 if not 'metadata' in resources or resources['metadata'] == '':
146 146 resources['metadata'] = ResourcesDict()
147 147 basename = os.path.basename(filename)
148 148 notebook_name = basename[:basename.rfind('.')]
149 149 resources['metadata']['name'] = notebook_name
150 150
151 151 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
152 152 resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y")
153 153
154 154 with io.open(filename) as f:
155 155 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
156 156
157 157
158 158 def from_file(self, file_stream, resources=None, **kw):
159 159 """
160 160 Convert a notebook from a notebook file.
161 161
162 162 Parameters
163 163 ----------
164 164 file_stream : file-like object
165 165 Notebook file-like object to convert.
166 166 """
167 167 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
168 168
169 169
170 170 def register_transformer(self, transformer, enabled=False):
171 171 """
172 172 Register a transformer.
173 173 Transformers are classes that act upon the notebook before it is
174 174 passed into the Jinja templating engine. Transformers are also
175 175 capable of passing additional information to the Jinja
176 176 templating engine.
177 177
178 178 Parameters
179 179 ----------
180 180 transformer : transformer
181 181 """
182 182 if transformer is None:
183 183 raise TypeError('transformer')
184 184 isclass = isinstance(transformer, type)
185 185 constructed = not isclass
186 186
187 187 #Handle transformer's registration based on it's type
188 188 if constructed and isinstance(transformer, py3compat.string_types):
189 189 #Transformer is a string, import the namespace and recursively call
190 190 #this register_transformer method
191 191 transformer_cls = import_item(transformer)
192 192 return self.register_transformer(transformer_cls, enabled)
193 193
194 194 if constructed and hasattr(transformer, '__call__'):
195 195 #Transformer is a function, no need to construct it.
196 196 #Register and return the transformer.
197 197 if enabled:
198 198 transformer.enabled = True
199 199 self._transformers.append(transformer)
200 200 return transformer
201 201
202 202 elif isclass and isinstance(transformer, MetaHasTraits):
203 203 #Transformer is configurable. Make sure to pass in new default for
204 204 #the enabled flag if one was specified.
205 205 self.register_transformer(transformer(parent=self), enabled)
206 206
207 207 elif isclass:
208 208 #Transformer is not configurable, construct it
209 209 self.register_transformer(transformer(), enabled)
210 210
211 211 else:
212 212 #Transformer is an instance of something without a __call__
213 213 #attribute.
214 214 raise TypeError('transformer')
215 215
216 216
217 217 def _init_transformers(self):
218 218 """
219 219 Register all of the transformers needed for this exporter, disabled
220 220 unless specified explicitly.
221 221 """
222 222 if self._transformers is None:
223 223 self._transformers = []
224 224
225 225 #Load default transformers (not necessarly enabled by default).
226 226 if self.default_transformers:
227 227 for transformer in self.default_transformers:
228 228 self.register_transformer(transformer)
229 229
230 230 #Load user transformers. Enable by default.
231 231 if self.transformers:
232 232 for transformer in self.transformers:
233 233 self.register_transformer(transformer, enabled=True)
234 234
235 235
236 236 def _init_resources(self, resources):
237 237
238 238 #Make sure the resources dict is of ResourcesDict type.
239 239 if resources is None:
240 240 resources = ResourcesDict()
241 241 if not isinstance(resources, ResourcesDict):
242 242 new_resources = ResourcesDict()
243 243 new_resources.update(resources)
244 244 resources = new_resources
245 245
246 246 #Make sure the metadata extension exists in resources
247 247 if 'metadata' in resources:
248 248 if not isinstance(resources['metadata'], ResourcesDict):
249 249 resources['metadata'] = ResourcesDict(resources['metadata'])
250 250 else:
251 251 resources['metadata'] = ResourcesDict()
252 252 if not resources['metadata']['name']:
253 253 resources['metadata']['name'] = 'Notebook'
254 254
255 255 #Set the output extension
256 256 resources['output_extension'] = self.file_extension
257 257 return resources
258 258
259 259
260 260 def _transform(self, nb, resources):
261 261 """
262 262 Preprocess the notebook before passing it into the Jinja engine.
263 263 To preprocess the notebook is to apply all of the
264 264
265 265 Parameters
266 266 ----------
267 267 nb : notebook node
268 268 notebook that is being exported.
269 269 resources : a dict of additional resources that
270 270 can be accessed read/write by transformers
271 271 """
272 272
273 273 # Do a copy.deepcopy first,
274 274 # we are never safe enough with what the transformers could do.
275 275 nbc = copy.deepcopy(nb)
276 276 resc = copy.deepcopy(resources)
277 277
278 278 #Run each transformer on the notebook. Carry the output along
279 279 #to each transformer
280 280 for transformer in self._transformers:
281 281 nbc, resc = transformer(nbc, resc)
282 282 return nbc, resc
@@ -1,169 +1,169 b''
1 1 """
2 2 Module containing single call export functions.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from functools import wraps
17 17
18 18 from IPython.nbformat.v3.nbbase import NotebookNode
19 19 from IPython.config import Config
20 20
21 from .exporter import Exporter
21 from .exporter import TemplateExporter
22 22 from .html import HTMLExporter
23 23 from .slides import SlidesExporter
24 24 from .latex import LatexExporter
25 25 from .markdown import MarkdownExporter
26 26 from .python import PythonExporter
27 27 from .rst import RSTExporter
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Classes
31 31 #-----------------------------------------------------------------------------
32 32
33 33 def DocDecorator(f):
34 34
35 35 #Set docstring of function
36 36 f.__doc__ = f.__doc__ + """
37 37 nb : Notebook node
38 38 config : config (optional, keyword arg)
39 39 User configuration instance.
40 40 resources : dict (optional, keyword arg)
41 41 Resources used in the conversion process.
42 42
43 43 Returns
44 44 ----------
45 45 tuple- output, resources, exporter_instance
46 46 output : str
47 47 Jinja 2 output. This is the resulting converted notebook.
48 48 resources : dictionary
49 49 Dictionary of resources used prior to and during the conversion
50 50 process.
51 51 exporter_instance : Exporter
52 52 Instance of the Exporter class used to export the document. Useful
53 53 to caller because it provides a 'file_extension' property which
54 54 specifies what extension the output should be saved as.
55 55
56 56 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT
57 57 """
58 58
59 59 @wraps(f)
60 60 def decorator(*args, **kwargs):
61 61 return f(*args, **kwargs)
62 62
63 63 return decorator
64 64
65 65
66 66 #-----------------------------------------------------------------------------
67 67 # Functions
68 68 #-----------------------------------------------------------------------------
69 69
70 70 __all__ = [
71 71 'export',
72 72 'export_html',
73 73 'export_custom',
74 74 'export_slides',
75 75 'export_latex',
76 76 'export_markdown',
77 77 'export_python',
78 78 'export_rst',
79 79 'export_by_name',
80 80 'get_export_names',
81 81 'ExporterNameError'
82 82 ]
83 83
84 84
85 85 class ExporterNameError(NameError):
86 86 pass
87 87
88 88 @DocDecorator
89 89 def export(exporter, nb, **kw):
90 90 """
91 91 Export a notebook object using specific exporter class.
92 92
93 93 exporter : Exporter class type or instance
94 94 Class type or instance of the exporter that should be used. If the
95 95 method initializes it's own instance of the class, it is ASSUMED that
96 96 the class type provided exposes a constructor (__init__) with the same
97 97 signature as the base Exporter class.
98 98 """
99 99
100 100 #Check arguments
101 101 if exporter is None:
102 102 raise TypeError("Exporter is None")
103 elif not isinstance(exporter, Exporter) and not issubclass(exporter, Exporter):
103 elif not isinstance(exporter, TemplateExporter) and not issubclass(exporter, TemplateExporter):
104 104 raise TypeError("exporter does not inherit from Exporter (base)")
105 105 if nb is None:
106 106 raise TypeError("nb is None")
107 107
108 108 #Create the exporter
109 109 resources = kw.pop('resources', None)
110 if isinstance(exporter, Exporter):
110 if isinstance(exporter, TemplateExporter):
111 111 exporter_instance = exporter
112 112 else:
113 113 exporter_instance = exporter(**kw)
114 114
115 115 #Try to convert the notebook using the appropriate conversion function.
116 116 if isinstance(nb, NotebookNode):
117 117 output, resources = exporter_instance.from_notebook_node(nb, resources)
118 118 elif isinstance(nb, basestring):
119 119 output, resources = exporter_instance.from_filename(nb, resources)
120 120 else:
121 121 output, resources = exporter_instance.from_file(nb, resources)
122 122 return output, resources
123 123
124 124 exporter_map = dict(
125 custom=Exporter,
125 custom=TemplateExporter,
126 126 html=HTMLExporter,
127 127 slides=SlidesExporter,
128 128 latex=LatexExporter,
129 129 markdown=MarkdownExporter,
130 130 python=PythonExporter,
131 131 rst=RSTExporter,
132 132 )
133 133
134 134 def _make_exporter(name, E):
135 135 """make an export_foo function from a short key and Exporter class E"""
136 136 def _export(nb, **kw):
137 137 return export(E, nb, **kw)
138 138 _export.__doc__ = """Export a notebook object to {0} format""".format(name)
139 139 return _export
140 140
141 141 g = globals()
142 142
143 143 for name, E in exporter_map.items():
144 144 g['export_%s' % name] = DocDecorator(_make_exporter(name, E))
145 145
146 146 @DocDecorator
147 147 def export_by_name(format_name, nb, **kw):
148 148 """
149 149 Export a notebook object to a template type by its name. Reflection
150 150 (Inspect) is used to find the template's corresponding explicit export
151 151 method defined in this module. That method is then called directly.
152 152
153 153 format_name : str
154 154 Name of the template style to export to.
155 155 """
156 156
157 157 function_name = "export_" + format_name.lower()
158 158
159 159 if function_name in globals():
160 160 return globals()[function_name](nb, **kw)
161 161 else:
162 162 raise ExporterNameError("template for `%s` not found" % function_name)
163 163
164 164
165 165 def get_export_names():
166 166 """Return a list of the currently supported export targets
167 167
168 168 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT"""
169 169 return sorted(exporter_map.keys())
@@ -1,52 +1,52 b''
1 1 """
2 2 Exporter that exports Basic HTML.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from IPython.utils.traitlets import Unicode, List
18 18
19 19 from IPython.nbconvert import preprocessors
20 20 from IPython.config import Config
21 21
22 from .exporter import Exporter
22 from .exporter import TemplateExporter
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes
26 26 #-----------------------------------------------------------------------------
27 27
28 class HTMLExporter(Exporter):
28 class HTMLExporter(TemplateExporter):
29 29 """
30 30 Exports a basic HTML document. This exporter assists with the export of
31 31 HTML. Inherit from it if you are writing your own HTML template and need
32 32 custom preprocessors/filters. If you don't need custom preprocessors/
33 33 filters, just change the 'template_file' config option.
34 34 """
35 35
36 36 file_extension = Unicode(
37 37 'html', config=True,
38 38 help="Extension of the file that should be written to disk"
39 39 )
40 40
41 41 default_template = Unicode('full', config=True, help="""Flavor of the data
42 42 format to use. I.E. 'full' or 'basic'""")
43 43
44 44 @property
45 45 def default_config(self):
46 46 c = Config({
47 47 'CSSHTMLHeaderPreprocessor':{
48 48 'enabled':True
49 49 }
50 50 })
51 51 c.merge(super(HTMLExporter,self).default_config)
52 52 return c
@@ -1,38 +1,38 b''
1 1 """
2 2 Exporter that will export your ipynb to Markdown.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from IPython.config import Config
17 17 from IPython.utils.traitlets import Unicode
18 18
19 from .exporter import Exporter
19 from .exporter import TemplateExporter
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Classes
23 23 #-----------------------------------------------------------------------------
24 24
25 class MarkdownExporter(Exporter):
25 class MarkdownExporter(TemplateExporter):
26 26 """
27 27 Exports to a markdown document (.md)
28 28 """
29 29
30 30 file_extension = Unicode(
31 31 'md', config=True,
32 32 help="Extension of the file that should be written to disk")
33 33
34 34 @property
35 35 def default_config(self):
36 36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
37 37 c.merge(super(MarkdownExporter,self).default_config)
38 38 return c
@@ -1,31 +1,31 b''
1 1 """
2 2 Python exporter which exports Notebook code into a PY file.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from IPython.utils.traitlets import Unicode
17 17
18 from .exporter import Exporter
18 from .exporter import TemplateExporter
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Classes
22 22 #-----------------------------------------------------------------------------
23 23
24 class PythonExporter(Exporter):
24 class PythonExporter(TemplateExporter):
25 25 """
26 26 Exports a Python code file.
27 27 """
28 28
29 29 file_extension = Unicode(
30 30 'py', config=True,
31 31 help="Extension of the file that should be written to disk")
@@ -1,38 +1,38 b''
1 1 """
2 2 Exporter for exporting notebooks to restructured text.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from IPython.utils.traitlets import Unicode
17 17 from IPython.config import Config
18 18
19 from .exporter import Exporter
19 from .exporter import TemplateExporter
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Classes
23 23 #-----------------------------------------------------------------------------
24 24
25 class RSTExporter(Exporter):
25 class RSTExporter(TemplateExporter):
26 26 """
27 27 Exports restructured text documents.
28 28 """
29 29
30 30 file_extension = Unicode(
31 31 'rst', config=True,
32 32 help="Extension of the file that should be written to disk")
33 33
34 34 @property
35 35 def default_config(self):
36 36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
37 37 c.merge(super(RSTExporter,self).default_config)
38 38 return c
@@ -1,52 +1,52 b''
1 1 """
2 2 Contains slide show exporter
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from IPython.utils.traitlets import Unicode
18 18
19 19 from IPython.nbconvert import preprocessors
20 20 from IPython.config import Config
21 21
22 from .exporter import Exporter
22 from .exporter import TemplateExporter
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes
26 26 #-----------------------------------------------------------------------------
27 27
28 class SlidesExporter(Exporter):
28 class SlidesExporter(TemplateExporter):
29 29 """
30 30 Exports slides
31 31 """
32 32
33 33 file_extension = Unicode(
34 34 'slides.html', config=True,
35 35 help="Extension of the file that should be written to disk"
36 36 )
37 37
38 38 default_template = Unicode('reveal', config=True, help="""Template of the
39 39 data format to use. I.E. 'reveal'""")
40 40
41 41 @property
42 42 def default_config(self):
43 43 c = Config({
44 44 'CSSHTMLHeaderPreprocessor':{
45 45 'enabled':True
46 46 },
47 47 'RevealHelpPreprocessor':{
48 48 'enabled':True,
49 49 },
50 50 })
51 51 c.merge(super(SlidesExporter,self).default_config)
52 52 return c
@@ -1,30 +1,30 b''
1 1 """
2 2 Module with tests base for exporters
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import os
18 18
19 19 from ...tests.base import TestsBase
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Class
23 23 #-----------------------------------------------------------------------------
24 24
25 25 class ExportersTestsBase(TestsBase):
26 26 """Contains base test functions for exporters"""
27 27
28 28 def _get_notebook(self):
29 29 return os.path.join(self._get_files_path(), 'notebook2.ipynb')
30 No newline at end of file
30
@@ -1,102 +1,102 b''
1 1 """
2 2 Module with tests for export.py
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import os
18 18
19 19 from IPython.nbformat import current as nbformat
20 20
21 21 from .base import ExportersTestsBase
22 22 from ..export import *
23 23 from ..python import PythonExporter
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Class
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class TestExport(ExportersTestsBase):
30 30 """Contains test functions for export.py"""
31 31
32 32
33 33 def test_export_wrong_name(self):
34 34 """
35 35 Is the right error thrown when a bad template name is used?
36 36 """
37 37 try:
38 38 export_by_name('not_a_name', self._get_notebook())
39 39 except ExporterNameError as e:
40 40 pass
41 41
42 42
43 43 def test_export_filename(self):
44 44 """
45 45 Can a notebook be exported by filename?
46 46 """
47 47 (output, resources) = export_by_name('python', self._get_notebook())
48 48 assert len(output) > 0
49 49
50 50
51 51 def test_export_nbnode(self):
52 52 """
53 53 Can a notebook be exported by a notebook node handle?
54 54 """
55 55 with open(self._get_notebook(), 'r') as f:
56 56 notebook = nbformat.read(f, 'json')
57 57 (output, resources) = export_by_name('python', notebook)
58 58 assert len(output) > 0
59 59
60 60
61 61 def test_export_filestream(self):
62 62 """
63 63 Can a notebook be exported by a filesteam?
64 64 """
65 65 with open(self._get_notebook(), 'r') as f:
66 66 (output, resources) = export_by_name('python', f)
67 67 assert len(output) > 0
68 68
69 69
70 70 def test_export_using_exporter(self):
71 71 """
72 72 Can a notebook be exported using an instanciated exporter?
73 73 """
74 74 (output, resources) = export(PythonExporter(), self._get_notebook())
75 75 assert len(output) > 0
76 76
77 77
78 78 def test_export_using_exporter_class(self):
79 79 """
80 80 Can a notebook be exported using an exporter class type?
81 81 """
82 82 (output, resources) = export(PythonExporter, self._get_notebook())
83 83 assert len(output) > 0
84 84
85 85
86 86 def test_export_resources(self):
87 87 """
88 88 Can a notebook be exported along with a custom resources dict?
89 89 """
90 90 (output, resources) = export(PythonExporter, self._get_notebook(), resources={})
91 91 assert len(output) > 0
92 92
93 93
94 94 def test_no_exporter(self):
95 95 """
96 96 Is the right error thrown if no exporter is provided?
97 97 """
98 98 try:
99 99 (output, resources) = export(None, self._get_notebook())
100 100 except TypeError:
101 101 pass
102 No newline at end of file
102
@@ -1,324 +1,324 b''
1 1 #!/usr/bin/env python
2 2 """NBConvert is a utility for conversion of .ipynb files.
3 3
4 4 Command-line interface for the NbConvert conversion utility.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 #Copyright (c) 2013, the IPython Development Team.
8 8 #
9 9 #Distributed under the terms of the Modified BSD License.
10 10 #
11 11 #The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 #Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Stdlib imports
19 19 from __future__ import print_function
20 20
21 21 import logging
22 22 import sys
23 23 import os
24 24 import glob
25 25
26 26 # From IPython
27 27 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
28 28 from IPython.core.profiledir import ProfileDir
29 29 from IPython.config import catch_config_error, Configurable
30 30 from IPython.utils.traitlets import (
31 31 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
32 32 )
33 33 from IPython.utils.importstring import import_item
34 34 from IPython.utils.text import dedent
35 35
36 36 from .exporters.export import get_export_names, exporter_map
37 37 from IPython.nbconvert import exporters, preprocessors, writers, postprocessors
38 38 from .utils.base import NbConvertBase
39 39 from .utils.exceptions import ConversionException
40 40
41 41 #-----------------------------------------------------------------------------
42 42 #Classes and functions
43 43 #-----------------------------------------------------------------------------
44 44
45 45 class DottedOrNone(DottedObjectName):
46 46 """
47 47 A string holding a valid dotted object name in Python, such as A.b3._c
48 48 Also allows for None type."""
49 49
50 50 default_value = u''
51 51
52 52 def validate(self, obj, value):
53 53 if value is not None and len(value) > 0:
54 54 return super(DottedOrNone, self).validate(obj, value)
55 55 else:
56 56 return value
57 57
58 58 nbconvert_aliases = {}
59 59 nbconvert_aliases.update(base_aliases)
60 60 nbconvert_aliases.update({
61 61 'to' : 'NbConvertApp.export_format',
62 'template' : 'Exporter.template_file',
62 'template' : 'TemplateExporter.template_file',
63 63 'writer' : 'NbConvertApp.writer_class',
64 64 'post': 'NbConvertApp.postprocessor_class',
65 65 'output': 'NbConvertApp.output_base',
66 66 'offline-slides': 'RevealHelpPreprocessor.url_prefix',
67 67 'slide-notes': 'RevealHelpPreprocessor.speaker_notes'
68 68 })
69 69
70 70 nbconvert_flags = {}
71 71 nbconvert_flags.update(base_flags)
72 72 nbconvert_flags.update({
73 73 'stdout' : (
74 74 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
75 75 "Write notebook output to stdout instead of files."
76 76 )
77 77 })
78 78
79 79
80 80 class NbConvertApp(BaseIPythonApplication):
81 81 """Application used to convert to and from notebook file type (*.ipynb)"""
82 82
83 83 name = 'ipython-nbconvert'
84 84 aliases = nbconvert_aliases
85 85 flags = nbconvert_flags
86 86
87 87 def _log_level_default(self):
88 88 return logging.INFO
89 89
90 90 def _classes_default(self):
91 91 classes = [NbConvertBase, ProfileDir]
92 92 for pkg in (exporters, preprocessors, writers):
93 93 for name in dir(pkg):
94 94 cls = getattr(pkg, name)
95 95 if isinstance(cls, type) and issubclass(cls, Configurable):
96 96 classes.append(cls)
97 97
98 98 return classes
99 99
100 100 description = Unicode(
101 101 u"""This application is used to convert notebook files (*.ipynb)
102 102 to various other formats.
103 103
104 104 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
105 105
106 106 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
107 107 can only be use when converting one notebook at a time.
108 108 ''')
109 109
110 110 examples = Unicode(u"""
111 111 The simplest way to use nbconvert is
112 112
113 113 > ipython nbconvert mynotebook.ipynb
114 114
115 115 which will convert mynotebook.ipynb to the default format (probably HTML).
116 116
117 117 You can specify the export format with `--to`.
118 118 Options include {0}
119 119
120 120 > ipython nbconvert --to latex mynotebook.ipnynb
121 121
122 122 Both HTML and LaTeX support multiple output templates. LaTeX includes
123 123 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
124 124 can specify the flavor of the format used.
125 125
126 126 > ipython nbconvert --to html --template basic mynotebook.ipynb
127 127
128 128 You can also pipe the output to stdout, rather than a file
129 129
130 130 > ipython nbconvert mynotebook.ipynb --stdout
131 131
132 132 A post-processor can be used to compile a PDF
133 133
134 134 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
135 135
136 136 You can get (and serve) a Reveal.js-powered slideshow
137 137
138 138 > ipython nbconvert myslides.ipynb --to slides --post serve
139 139
140 140 Multiple notebooks can be given at the command line in a couple of
141 141 different ways:
142 142
143 143 > ipython nbconvert notebook*.ipynb
144 144 > ipython nbconvert notebook1.ipynb notebook2.ipynb
145 145
146 146 or you can specify the notebooks list in a config file, containing::
147 147
148 148 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
149 149
150 150 > ipython nbconvert --config mycfg.py
151 151 """.format(get_export_names()))
152 152
153 153 # Writer specific variables
154 154 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
155 155 help="""Instance of the writer class used to write the
156 156 results of the conversion.""")
157 157 writer_class = DottedObjectName('FilesWriter', config=True,
158 158 help="""Writer class used to write the
159 159 results of the conversion""")
160 160 writer_aliases = {'fileswriter': 'IPython.nbconvert.writers.files.FilesWriter',
161 161 'debugwriter': 'IPython.nbconvert.writers.debug.DebugWriter',
162 162 'stdoutwriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
163 163 writer_factory = Type()
164 164
165 165 def _writer_class_changed(self, name, old, new):
166 166 if new.lower() in self.writer_aliases:
167 167 new = self.writer_aliases[new.lower()]
168 168 self.writer_factory = import_item(new)
169 169
170 170 # Post-processor specific variables
171 171 postprocessor = Instance('IPython.nbconvert.postprocessors.base.PostProcessorBase',
172 172 help="""Instance of the PostProcessor class used to write the
173 173 results of the conversion.""")
174 174
175 175 postprocessor_class = DottedOrNone(config=True,
176 176 help="""PostProcessor class used to write the
177 177 results of the conversion""")
178 178 postprocessor_aliases = {'pdf': 'IPython.nbconvert.postprocessors.pdf.PDFPostProcessor',
179 179 'serve': 'IPython.nbconvert.postprocessors.serve.ServePostProcessor'}
180 180 postprocessor_factory = Type()
181 181
182 182 def _postprocessor_class_changed(self, name, old, new):
183 183 if new.lower() in self.postprocessor_aliases:
184 184 new = self.postprocessor_aliases[new.lower()]
185 185 if new:
186 186 self.postprocessor_factory = import_item(new)
187 187
188 188
189 189 # Other configurable variables
190 190 export_format = CaselessStrEnum(get_export_names(),
191 191 default_value="html",
192 192 config=True,
193 193 help="""The export format to be used."""
194 194 )
195 195
196 196 notebooks = List([], config=True, help="""List of notebooks to convert.
197 197 Wildcards are supported.
198 198 Filenames passed positionally will be added to the list.
199 199 """)
200 200
201 201 @catch_config_error
202 202 def initialize(self, argv=None):
203 203 super(NbConvertApp, self).initialize(argv)
204 204 self.init_syspath()
205 205 self.init_notebooks()
206 206 self.init_writer()
207 207 self.init_postprocessor()
208 208
209 209
210 210
211 211 def init_syspath(self):
212 212 """
213 213 Add the cwd to the sys.path ($PYTHONPATH)
214 214 """
215 215 sys.path.insert(0, os.getcwd())
216 216
217 217
218 218 def init_notebooks(self):
219 219 """Construct the list of notebooks.
220 220 If notebooks are passed on the command-line,
221 221 they override notebooks specified in config files.
222 222 Glob each notebook to replace notebook patterns with filenames.
223 223 """
224 224
225 225 # Specifying notebooks on the command-line overrides (rather than adds)
226 226 # the notebook list
227 227 if self.extra_args:
228 228 patterns = self.extra_args
229 229 else:
230 230 patterns = self.notebooks
231 231
232 232 # Use glob to replace all the notebook patterns with filenames.
233 233 filenames = []
234 234 for pattern in patterns:
235 235
236 236 # Use glob to find matching filenames. Allow the user to convert
237 237 # notebooks without having to type the extension.
238 238 globbed_files = glob.glob(pattern)
239 239 globbed_files.extend(glob.glob(pattern + '.ipynb'))
240 240 if not globbed_files:
241 241 self.log.warn("pattern %r matched no files", pattern)
242 242
243 243 for filename in globbed_files:
244 244 if not filename in filenames:
245 245 filenames.append(filename)
246 246 self.notebooks = filenames
247 247
248 248 def init_writer(self):
249 249 """
250 250 Initialize the writer (which is stateless)
251 251 """
252 252 self._writer_class_changed(None, self.writer_class, self.writer_class)
253 253 self.writer = self.writer_factory(parent=self)
254 254
255 255 def init_postprocessor(self):
256 256 """
257 257 Initialize the postprocessor (which is stateless)
258 258 """
259 259 self._postprocessor_class_changed(None, self.postprocessor_class,
260 260 self.postprocessor_class)
261 261 if self.postprocessor_factory:
262 262 self.postprocessor = self.postprocessor_factory(parent=self)
263 263
264 264 def start(self):
265 265 """
266 266 Ran after initialization completed
267 267 """
268 268 super(NbConvertApp, self).start()
269 269 self.convert_notebooks()
270 270
271 271 def convert_notebooks(self):
272 272 """
273 273 Convert the notebooks in the self.notebook traitlet
274 274 """
275 275 # Export each notebook
276 276 conversion_success = 0
277 277
278 278 if self.output_base != '' and len(self.notebooks) > 1:
279 279 self.log.error(
280 280 """UsageError: --output flag or `NbConvertApp.output_base` config option
281 281 cannot be used when converting multiple notebooks.
282 282 """)
283 283 self.exit(1)
284 284
285 285 exporter = exporter_map[self.export_format](config=self.config)
286 286
287 287 for notebook_filename in self.notebooks:
288 288 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
289 289
290 290 # Get a unique key for the notebook and set it in the resources object.
291 291 basename = os.path.basename(notebook_filename)
292 292 notebook_name = basename[:basename.rfind('.')]
293 293 if self.output_base:
294 294 notebook_name = self.output_base
295 295 resources = {}
296 296 resources['unique_key'] = notebook_name
297 297 resources['output_files_dir'] = '%s_files' % notebook_name
298 298 self.log.info("Support files will be in %s", os.path.join(resources['output_files_dir'], ''))
299 299
300 300 # Try to export
301 301 try:
302 302 output, resources = exporter.from_filename(notebook_filename, resources=resources)
303 303 except ConversionException as e:
304 304 self.log.error("Error while converting '%s'", notebook_filename,
305 305 exc_info=True)
306 306 self.exit(1)
307 307 else:
308 308 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
309 309
310 310 #Post-process if post processor has been defined.
311 311 if hasattr(self, 'postprocessor') and self.postprocessor:
312 312 self.postprocessor(write_resultes)
313 313 conversion_success += 1
314 314
315 315 # If nothing was converted successfully, help the user.
316 316 if conversion_success == 0:
317 317 self.print_help()
318 318 sys.exit(-1)
319 319
320 320 #-----------------------------------------------------------------------------
321 321 # Main entry point
322 322 #-----------------------------------------------------------------------------
323 323
324 324 launch_new_instance = NbConvertApp.launch_instance
General Comments 0
You need to be logged in to leave comments. Login now