##// END OF EJS Templates
Rebase changes made by hand
Jonathan Frederic -
Show More
@@ -1,9 +1,9 b''
1 from .export import *
1 from .export import *
2 from .html import HTMLExporter
2 from .html import HTMLExporter
3 from .slides import SlidesExporter
3 from .slides import SlidesExporter
4 from .exporter import TemplateExporter
4 from .templateexporter import TemplateExporter
5 from .latex import LatexExporter
5 from .latex import LatexExporter
6 from .markdown import MarkdownExporter
6 from .markdown import MarkdownExporter
7 from .python import PythonExporter
7 from .python import PythonExporter
8 from .rst import RSTExporter
8 from .rst import RSTExporter
9 from .baseexporter import BaseExporter
9 from .exporter import Exporter
@@ -1,169 +1,169 b''
1 """
1 """
2 Module containing single call export functions.
2 Module containing single call export functions.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from functools import wraps
16 from functools import wraps
17
17
18 from IPython.nbformat.v3.nbbase import NotebookNode
18 from IPython.nbformat.v3.nbbase import NotebookNode
19 from IPython.config import Config
19 from IPython.config import Config
20
20
21 from .exporter import TemplateExporter
21 from .templateexporter import TemplateExporter
22 from .html import HTMLExporter
22 from .html import HTMLExporter
23 from .slides import SlidesExporter
23 from .slides import SlidesExporter
24 from .latex import LatexExporter
24 from .latex import LatexExporter
25 from .markdown import MarkdownExporter
25 from .markdown import MarkdownExporter
26 from .python import PythonExporter
26 from .python import PythonExporter
27 from .rst import RSTExporter
27 from .rst import RSTExporter
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes
30 # Classes
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 def DocDecorator(f):
33 def DocDecorator(f):
34
34
35 #Set docstring of function
35 #Set docstring of function
36 f.__doc__ = f.__doc__ + """
36 f.__doc__ = f.__doc__ + """
37 nb : Notebook node
37 nb : Notebook node
38 config : config (optional, keyword arg)
38 config : config (optional, keyword arg)
39 User configuration instance.
39 User configuration instance.
40 resources : dict (optional, keyword arg)
40 resources : dict (optional, keyword arg)
41 Resources used in the conversion process.
41 Resources used in the conversion process.
42
42
43 Returns
43 Returns
44 ----------
44 ----------
45 tuple- output, resources, exporter_instance
45 tuple- output, resources, exporter_instance
46 output : str
46 output : str
47 Jinja 2 output. This is the resulting converted notebook.
47 Jinja 2 output. This is the resulting converted notebook.
48 resources : dictionary
48 resources : dictionary
49 Dictionary of resources used prior to and during the conversion
49 Dictionary of resources used prior to and during the conversion
50 process.
50 process.
51 exporter_instance : Exporter
51 exporter_instance : Exporter
52 Instance of the Exporter class used to export the document. Useful
52 Instance of the Exporter class used to export the document. Useful
53 to caller because it provides a 'file_extension' property which
53 to caller because it provides a 'file_extension' property which
54 specifies what extension the output should be saved as.
54 specifies what extension the output should be saved as.
55
55
56 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT
56 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT
57 """
57 """
58
58
59 @wraps(f)
59 @wraps(f)
60 def decorator(*args, **kwargs):
60 def decorator(*args, **kwargs):
61 return f(*args, **kwargs)
61 return f(*args, **kwargs)
62
62
63 return decorator
63 return decorator
64
64
65
65
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67 # Functions
67 # Functions
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69
69
70 __all__ = [
70 __all__ = [
71 'export',
71 'export',
72 'export_html',
72 'export_html',
73 'export_custom',
73 'export_custom',
74 'export_slides',
74 'export_slides',
75 'export_latex',
75 'export_latex',
76 'export_markdown',
76 'export_markdown',
77 'export_python',
77 'export_python',
78 'export_rst',
78 'export_rst',
79 'export_by_name',
79 'export_by_name',
80 'get_export_names',
80 'get_export_names',
81 'ExporterNameError'
81 'ExporterNameError'
82 ]
82 ]
83
83
84
84
85 class ExporterNameError(NameError):
85 class ExporterNameError(NameError):
86 pass
86 pass
87
87
88 @DocDecorator
88 @DocDecorator
89 def export(exporter, nb, **kw):
89 def export(exporter, nb, **kw):
90 """
90 """
91 Export a notebook object using specific exporter class.
91 Export a notebook object using specific exporter class.
92
92
93 exporter : Exporter class type or instance
93 exporter : Exporter class type or instance
94 Class type or instance of the exporter that should be used. If the
94 Class type or instance of the exporter that should be used. If the
95 method initializes it's own instance of the class, it is ASSUMED that
95 method initializes it's own instance of the class, it is ASSUMED that
96 the class type provided exposes a constructor (__init__) with the same
96 the class type provided exposes a constructor (__init__) with the same
97 signature as the base Exporter class.
97 signature as the base Exporter class.
98 """
98 """
99
99
100 #Check arguments
100 #Check arguments
101 if exporter is None:
101 if exporter is None:
102 raise TypeError("Exporter is None")
102 raise TypeError("Exporter is None")
103 elif not isinstance(exporter, TemplateExporter) and not issubclass(exporter, TemplateExporter):
103 elif not isinstance(exporter, TemplateExporter) and not issubclass(exporter, TemplateExporter):
104 raise TypeError("exporter does not inherit from Exporter (base)")
104 raise TypeError("exporter does not inherit from Exporter (base)")
105 if nb is None:
105 if nb is None:
106 raise TypeError("nb is None")
106 raise TypeError("nb is None")
107
107
108 #Create the exporter
108 #Create the exporter
109 resources = kw.pop('resources', None)
109 resources = kw.pop('resources', None)
110 if isinstance(exporter, TemplateExporter):
110 if isinstance(exporter, TemplateExporter):
111 exporter_instance = exporter
111 exporter_instance = exporter
112 else:
112 else:
113 exporter_instance = exporter(**kw)
113 exporter_instance = exporter(**kw)
114
114
115 #Try to convert the notebook using the appropriate conversion function.
115 #Try to convert the notebook using the appropriate conversion function.
116 if isinstance(nb, NotebookNode):
116 if isinstance(nb, NotebookNode):
117 output, resources = exporter_instance.from_notebook_node(nb, resources)
117 output, resources = exporter_instance.from_notebook_node(nb, resources)
118 elif isinstance(nb, basestring):
118 elif isinstance(nb, basestring):
119 output, resources = exporter_instance.from_filename(nb, resources)
119 output, resources = exporter_instance.from_filename(nb, resources)
120 else:
120 else:
121 output, resources = exporter_instance.from_file(nb, resources)
121 output, resources = exporter_instance.from_file(nb, resources)
122 return output, resources
122 return output, resources
123
123
124 exporter_map = dict(
124 exporter_map = dict(
125 custom=TemplateExporter,
125 custom=TemplateExporter,
126 html=HTMLExporter,
126 html=HTMLExporter,
127 slides=SlidesExporter,
127 slides=SlidesExporter,
128 latex=LatexExporter,
128 latex=LatexExporter,
129 markdown=MarkdownExporter,
129 markdown=MarkdownExporter,
130 python=PythonExporter,
130 python=PythonExporter,
131 rst=RSTExporter,
131 rst=RSTExporter,
132 )
132 )
133
133
134 def _make_exporter(name, E):
134 def _make_exporter(name, E):
135 """make an export_foo function from a short key and Exporter class E"""
135 """make an export_foo function from a short key and Exporter class E"""
136 def _export(nb, **kw):
136 def _export(nb, **kw):
137 return export(E, nb, **kw)
137 return export(E, nb, **kw)
138 _export.__doc__ = """Export a notebook object to {0} format""".format(name)
138 _export.__doc__ = """Export a notebook object to {0} format""".format(name)
139 return _export
139 return _export
140
140
141 g = globals()
141 g = globals()
142
142
143 for name, E in exporter_map.items():
143 for name, E in exporter_map.items():
144 g['export_%s' % name] = DocDecorator(_make_exporter(name, E))
144 g['export_%s' % name] = DocDecorator(_make_exporter(name, E))
145
145
146 @DocDecorator
146 @DocDecorator
147 def export_by_name(format_name, nb, **kw):
147 def export_by_name(format_name, nb, **kw):
148 """
148 """
149 Export a notebook object to a template type by its name. Reflection
149 Export a notebook object to a template type by its name. Reflection
150 (Inspect) is used to find the template's corresponding explicit export
150 (Inspect) is used to find the template's corresponding explicit export
151 method defined in this module. That method is then called directly.
151 method defined in this module. That method is then called directly.
152
152
153 format_name : str
153 format_name : str
154 Name of the template style to export to.
154 Name of the template style to export to.
155 """
155 """
156
156
157 function_name = "export_" + format_name.lower()
157 function_name = "export_" + format_name.lower()
158
158
159 if function_name in globals():
159 if function_name in globals():
160 return globals()[function_name](nb, **kw)
160 return globals()[function_name](nb, **kw)
161 else:
161 else:
162 raise ExporterNameError("template for `%s` not found" % function_name)
162 raise ExporterNameError("template for `%s` not found" % function_name)
163
163
164
164
165 def get_export_names():
165 def get_export_names():
166 """Return a list of the currently supported export targets
166 """Return a list of the currently supported export targets
167
167
168 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT"""
168 WARNING: API WILL CHANGE IN FUTURE RELEASES OF NBCONVERT"""
169 return sorted(exporter_map.keys())
169 return sorted(exporter_map.keys())
@@ -1,282 +1,281 b''
1 """This module defines BaseExporter, a highly configurable converter
1 """This module defines Exporter, a highly configurable converter
2 that uses Jinja2 to export notebook files into different formats.
2 that uses Jinja2 to export notebook files into different formats.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import print_function, absolute_import
17 from __future__ import print_function, absolute_import
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import io
20 import io
21 import os
21 import os
22 import copy
22 import copy
23 import collections
23 import collections
24 import datetime
24 import datetime
25
25
26
26
27 # IPython imports
27 # IPython imports
28 from IPython.config.configurable import LoggingConfigurable
28 from IPython.config.configurable import LoggingConfigurable
29 from IPython.config import Config
29 from IPython.config import Config
30 from IPython.nbformat import current as nbformat
30 from IPython.nbformat import current as nbformat
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List
32 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
33 from IPython.utils import py3compat
33 from IPython.utils import text, py3compat
34
34
35 from IPython.nbconvert import transformers as nbtransformers
35 from IPython.nbconvert import preprocessors as nbpreprocessors
36
36
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Class
39 # Class
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 class ResourcesDict(collections.defaultdict):
42 class ResourcesDict(collections.defaultdict):
43 def __missing__(self, key):
43 def __missing__(self, key):
44 return ''
44 return ''
45
45
46
46
47 class BaseExporter(LoggingConfigurable):
47 class Exporter(LoggingConfigurable):
48 """
48 """
49 Base Exporter Class that only conver notebook to notebook
49 Exporter class that only converts from notebook to notebook
50 and apply the transformers and provide basic methods for
50 by applying the preprocessors and providing basic methods for
51 reading a notebook from different sources.
51 reading a notebook from different sources.
52
53 """
52 """
54
53
55 # finish the docstring
54 # finish the docstring
56
55
57 file_extension = Unicode(
56 file_extension = Unicode(
58 'txt', config=True,
57 'txt', config=True,
59 help="Extension of the file that should be written to disk"
58 help="Extension of the file that should be written to disk"
60 )
59 )
61
60
62 #Configurability, allows the user to easily add transformers.
61 #Configurability, allows the user to easily add filters and preprocessors.
63 transformers = List(config=True,
62 preprocessors = List(config=True,
64 help="""List of transformers, by name or namespace, to enable.""")
63 help="""List of preprocessors, by name or namespace, to enable.""")
65
64
66 _transformers = None
65 _preprocessors = None
67
66
68 default_transformers = List([nbtransformers.coalesce_streams,
67 default_preprocessors = List([nbpreprocessors.coalesce_streams,
69 nbtransformers.SVG2PDFTransformer,
68 nbpreprocessors.SVG2PDFPreprocessor,
70 nbtransformers.ExtractOutputTransformer,
69 nbpreprocessors.ExtractOutputPreprocessor,
71 nbtransformers.CSSHTMLHeaderTransformer,
70 nbpreprocessors.CSSHTMLHeaderPreprocessor,
72 nbtransformers.RevealHelpTransformer,
71 nbpreprocessors.RevealHelpPreprocessor,
73 nbtransformers.LatexTransformer,
72 nbpreprocessors.LatexPreprocessor,
74 nbtransformers.SphinxTransformer],
73 nbpreprocessors.SphinxPreprocessor],
75 config=True,
74 config=True,
76 help="""List of transformers available by default, by name, namespace,
75 help="""List of preprocessors available by default, by name, namespace,
77 instance, or type.""")
76 instance, or type.""")
78
77
79
78
80 def __init__(self, config=None, **kw):
79 def __init__(self, config=None, **kw):
81 """
80 """
82 Public constructor
81 Public constructor
83
82
84 Parameters
83 Parameters
85 ----------
84 ----------
86 config : config
85 config : config
87 User configuration instance.
86 User configuration instance.
88 """
87 """
89 if not config:
88 if not config:
90 config = self.default_config
89 config = self.default_config
91
90
92 super(BaseExporter, self).__init__(config=config, **kw)
91 super(Exporter, self).__init__(config=config, **kw)
93
92
94 #Init
93 #Init
95 self._init_transformers()
94 self._init_preprocessors()
96
95
97
96
98 @property
97 @property
99 def default_config(self):
98 def default_config(self):
100 return Config()
99 return Config()
101
100
102 def _config_changed(self, name, old, new):
101 def _config_changed(self, name, old, new):
103 """When setting config, make sure to start with our default_config"""
102 """When setting config, make sure to start with our default_config"""
104 c = self.default_config
103 c = self.default_config
105 if new:
104 if new:
106 c.merge(new)
105 c.merge(new)
107 if c != old:
106 if c != old:
108 self.config = c
107 self.config = c
109 super(BaseExporter, self)._config_changed(name, old, c)
108 super(Exporter, self)._config_changed(name, old, c)
110
109
111
110
112 def from_notebook_node(self, nb, resources=None):
111 def from_notebook_node(self, nb, resources=None):
113 """
112 """
114 Convert a notebook from a notebook node instance.
113 Convert a notebook from a notebook node instance.
115
114
116 Parameters
115 Parameters
117 ----------
116 ----------
118 nb : Notebook node
117 nb : Notebook node
119 resources : dict (**kw)
118 resources : dict (**kw)
120 of additional resources that can be accessed read/write by
119 of additional resources that can be accessed read/write by
121 transformers.
120 preprocessors.
122 """
121 """
123 nb_copy = copy.deepcopy(nb)
122 nb_copy = copy.deepcopy(nb)
124 resources = self._init_resources(resources)
123 resources = self._init_resources(resources)
125
124
126 # Preprocess
125 # Preprocess
127 nb_copy, resources = self._transform(nb_copy, resources)
126 nb_copy, resources = self._transform(nb_copy, resources)
128
127
129 return nb_copy, resources
128 return nb_copy, resources
130
129
131
130
132 def from_filename(self, filename, resources=None, **kw):
131 def from_filename(self, filename, resources=None, **kw):
133 """
132 """
134 Convert a notebook from a notebook file.
133 Convert a notebook from a notebook file.
135
134
136 Parameters
135 Parameters
137 ----------
136 ----------
138 filename : str
137 filename : str
139 Full filename of the notebook file to open and convert.
138 Full filename of the notebook file to open and convert.
140 """
139 """
141
140
142 #Pull the metadata from the filesystem.
141 # Pull the metadata from the filesystem.
143 if resources is None:
142 if resources is None:
144 resources = ResourcesDict()
143 resources = ResourcesDict()
145 if not 'metadata' in resources or resources['metadata'] == '':
144 if not 'metadata' in resources or resources['metadata'] == '':
146 resources['metadata'] = ResourcesDict()
145 resources['metadata'] = ResourcesDict()
147 basename = os.path.basename(filename)
146 basename = os.path.basename(filename)
148 notebook_name = basename[:basename.rfind('.')]
147 notebook_name = basename[:basename.rfind('.')]
149 resources['metadata']['name'] = notebook_name
148 resources['metadata']['name'] = notebook_name
150
149
151 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
150 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
152 resources['metadata']['modified_date'] = modified_date.strftime("%B %d, %Y")
151 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
153
152
154 with io.open(filename) as f:
153 with io.open(filename) as f:
155 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
154 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources, **kw)
156
155
157
156
158 def from_file(self, file_stream, resources=None, **kw):
157 def from_file(self, file_stream, resources=None, **kw):
159 """
158 """
160 Convert a notebook from a notebook file.
159 Convert a notebook from a notebook file.
161
160
162 Parameters
161 Parameters
163 ----------
162 ----------
164 file_stream : file-like object
163 file_stream : file-like object
165 Notebook file-like object to convert.
164 Notebook file-like object to convert.
166 """
165 """
167 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
166 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
168
167
169
168
170 def register_transformer(self, transformer, enabled=False):
169 def register_preprocessor(self, preprocessor, enabled=False):
171 """
170 """
172 Register a transformer.
171 Register a preprocessor.
173 Transformers are classes that act upon the notebook before it is
172 preprocessors are classes that act upon the notebook before it is
174 passed into the Jinja templating engine. Transformers are also
173 passed into the Jinja templating engine. preprocessors are also
175 capable of passing additional information to the Jinja
174 capable of passing additional information to the Jinja
176 templating engine.
175 templating engine.
177
176
178 Parameters
177 Parameters
179 ----------
178 ----------
180 transformer : transformer
179 preprocessor : preprocessor
181 """
180 """
182 if transformer is None:
181 if preprocessor is None:
183 raise TypeError('transformer')
182 raise TypeError('preprocessor')
184 isclass = isinstance(transformer, type)
183 isclass = isinstance(preprocessor, type)
185 constructed = not isclass
184 constructed = not isclass
186
185
187 #Handle transformer's registration based on it's type
186 #Handle preprocessor's registration based on it's type
188 if constructed and isinstance(transformer, py3compat.string_types):
187 if constructed and isinstance(preprocessor, py3compat.string_types):
189 #Transformer is a string, import the namespace and recursively call
188 #preprocessor is a string, import the namespace and recursively call
190 #this register_transformer method
189 #this register_preprocessor method
191 transformer_cls = import_item(transformer)
190 preprocessor_cls = import_item(preprocessor)
192 return self.register_transformer(transformer_cls, enabled)
191 return self.register_preprocessor(preprocessor_cls, enabled)
193
192
194 if constructed and hasattr(transformer, '__call__'):
193 if constructed and hasattr(preprocessor, '__call__'):
195 #Transformer is a function, no need to construct it.
194 #preprocessor is a function, no need to construct it.
196 #Register and return the transformer.
195 #Register and return the preprocessor.
197 if enabled:
196 if enabled:
198 transformer.enabled = True
197 preprocessor.enabled = True
199 self._transformers.append(transformer)
198 self._preprocessors.append(preprocessor)
200 return transformer
199 return preprocessor
201
200
202 elif isclass and isinstance(transformer, MetaHasTraits):
201 elif isclass and isinstance(preprocessor, MetaHasTraits):
203 #Transformer is configurable. Make sure to pass in new default for
202 #preprocessor is configurable. Make sure to pass in new default for
204 #the enabled flag if one was specified.
203 #the enabled flag if one was specified.
205 self.register_transformer(transformer(parent=self), enabled)
204 self.register_preprocessor(preprocessor(parent=self), enabled)
206
205
207 elif isclass:
206 elif isclass:
208 #Transformer is not configurable, construct it
207 #preprocessor is not configurable, construct it
209 self.register_transformer(transformer(), enabled)
208 self.register_preprocessor(preprocessor(), enabled)
210
209
211 else:
210 else:
212 #Transformer is an instance of something without a __call__
211 #preprocessor is an instance of something without a __call__
213 #attribute.
212 #attribute.
214 raise TypeError('transformer')
213 raise TypeError('preprocessor')
215
214
216
215
217 def _init_transformers(self):
216 def _init_preprocessors(self):
218 """
217 """
219 Register all of the transformers needed for this exporter, disabled
218 Register all of the preprocessors needed for this exporter, disabled
220 unless specified explicitly.
219 unless specified explicitly.
221 """
220 """
222 if self._transformers is None:
221 if self._preprocessors is None:
223 self._transformers = []
222 self._preprocessors = []
224
223
225 #Load default transformers (not necessarly enabled by default).
224 #Load default preprocessors (not necessarly enabled by default).
226 if self.default_transformers:
225 if self.default_preprocessors:
227 for transformer in self.default_transformers:
226 for preprocessor in self.default_preprocessors:
228 self.register_transformer(transformer)
227 self.register_preprocessor(preprocessor)
229
228
230 #Load user transformers. Enable by default.
229 #Load user preprocessors. Enable by default.
231 if self.transformers:
230 if self.preprocessors:
232 for transformer in self.transformers:
231 for preprocessor in self.preprocessors:
233 self.register_transformer(transformer, enabled=True)
232 self.register_preprocessor(preprocessor, enabled=True)
234
233
235
234
236 def _init_resources(self, resources):
235 def _init_resources(self, resources):
237
236
238 #Make sure the resources dict is of ResourcesDict type.
237 #Make sure the resources dict is of ResourcesDict type.
239 if resources is None:
238 if resources is None:
240 resources = ResourcesDict()
239 resources = ResourcesDict()
241 if not isinstance(resources, ResourcesDict):
240 if not isinstance(resources, ResourcesDict):
242 new_resources = ResourcesDict()
241 new_resources = ResourcesDict()
243 new_resources.update(resources)
242 new_resources.update(resources)
244 resources = new_resources
243 resources = new_resources
245
244
246 #Make sure the metadata extension exists in resources
245 #Make sure the metadata extension exists in resources
247 if 'metadata' in resources:
246 if 'metadata' in resources:
248 if not isinstance(resources['metadata'], ResourcesDict):
247 if not isinstance(resources['metadata'], ResourcesDict):
249 resources['metadata'] = ResourcesDict(resources['metadata'])
248 resources['metadata'] = ResourcesDict(resources['metadata'])
250 else:
249 else:
251 resources['metadata'] = ResourcesDict()
250 resources['metadata'] = ResourcesDict()
252 if not resources['metadata']['name']:
251 if not resources['metadata']['name']:
253 resources['metadata']['name'] = 'Notebook'
252 resources['metadata']['name'] = 'Notebook'
254
253
255 #Set the output extension
254 #Set the output extension
256 resources['output_extension'] = self.file_extension
255 resources['output_extension'] = self.file_extension
257 return resources
256 return resources
258
257
259
258
260 def _transform(self, nb, resources):
259 def _transform(self, nb, resources):
261 """
260 """
262 Preprocess the notebook before passing it into the Jinja engine.
261 Preprocess the notebook before passing it into the Jinja engine.
263 To preprocess the notebook is to apply all of the
262 To preprocess the notebook is to apply all of the
264
263
265 Parameters
264 Parameters
266 ----------
265 ----------
267 nb : notebook node
266 nb : notebook node
268 notebook that is being exported.
267 notebook that is being exported.
269 resources : a dict of additional resources that
268 resources : a dict of additional resources that
270 can be accessed read/write by transformers
269 can be accessed read/write by preprocessors
271 """
270 """
272
271
273 # Do a copy.deepcopy first,
272 # Do a copy.deepcopy first,
274 # we are never safe enough with what the transformers could do.
273 # we are never safe enough with what the preprocessors could do.
275 nbc = copy.deepcopy(nb)
274 nbc = copy.deepcopy(nb)
276 resc = copy.deepcopy(resources)
275 resc = copy.deepcopy(resources)
277
276
278 #Run each transformer on the notebook. Carry the output along
277 #Run each preprocessor on the notebook. Carry the output along
279 #to each transformer
278 #to each preprocessor
280 for transformer in self._transformers:
279 for preprocessor in self._preprocessors:
281 nbc, resc = transformer(nbc, resc)
280 nbc, resc = preprocessor(nbc, resc)
282 return nbc, resc
281 return nbc, resc
@@ -1,52 +1,52 b''
1 """
1 """
2 Exporter that exports Basic HTML.
2 Exporter that exports Basic HTML.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.utils.traitlets import Unicode, List
17 from IPython.utils.traitlets import Unicode, List
18
18
19 from IPython.nbconvert import preprocessors
19 from IPython.nbconvert import preprocessors
20 from IPython.config import Config
20 from IPython.config import Config
21
21
22 from .exporter import TemplateExporter
22 from .templateexporter import TemplateExporter
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Classes
25 # Classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class HTMLExporter(TemplateExporter):
28 class HTMLExporter(TemplateExporter):
29 """
29 """
30 Exports a basic HTML document. This exporter assists with the export of
30 Exports a basic HTML document. This exporter assists with the export of
31 HTML. Inherit from it if you are writing your own HTML template and need
31 HTML. Inherit from it if you are writing your own HTML template and need
32 custom preprocessors/filters. If you don't need custom preprocessors/
32 custom preprocessors/filters. If you don't need custom preprocessors/
33 filters, just change the 'template_file' config option.
33 filters, just change the 'template_file' config option.
34 """
34 """
35
35
36 file_extension = Unicode(
36 file_extension = Unicode(
37 'html', config=True,
37 'html', config=True,
38 help="Extension of the file that should be written to disk"
38 help="Extension of the file that should be written to disk"
39 )
39 )
40
40
41 default_template = Unicode('full', config=True, help="""Flavor of the data
41 default_template = Unicode('full', config=True, help="""Flavor of the data
42 format to use. I.E. 'full' or 'basic'""")
42 format to use. I.E. 'full' or 'basic'""")
43
43
44 @property
44 @property
45 def default_config(self):
45 def default_config(self):
46 c = Config({
46 c = Config({
47 'CSSHTMLHeaderPreprocessor':{
47 'CSSHTMLHeaderPreprocessor':{
48 'enabled':True
48 'enabled':True
49 }
49 }
50 })
50 })
51 c.merge(super(HTMLExporter,self).default_config)
51 c.merge(super(HTMLExporter,self).default_config)
52 return c
52 return c
@@ -1,91 +1,91 b''
1 """
1 """
2 Exporter that allows Latex Jinja templates to work. Contains logic to
2 Exporter that allows Latex Jinja templates to work. Contains logic to
3 appropriately prepare IPYNB files for export to LaTeX. Including but
3 appropriately prepare IPYNB files for export to LaTeX. Including but
4 not limited to escaping LaTeX, fixing math region tags, using special
4 not limited to escaping LaTeX, fixing math region tags, using special
5 tags to circumvent Jinja/Latex syntax conflicts.
5 tags to circumvent Jinja/Latex syntax conflicts.
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2013, the IPython Development Team.
8 # Copyright (c) 2013, the IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import os
20 import os
21
21
22 # IPython imports
22 # IPython imports
23 from IPython.utils.traitlets import Unicode, List
23 from IPython.utils.traitlets import Unicode, List
24 from IPython.config import Config
24 from IPython.config import Config
25
25
26 from IPython.nbconvert import filters, preprocessors
26 from IPython.nbconvert import filters, preprocessors
27 from .exporter import Exporter
27 from .templateexporter import TemplateExporter
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes and functions
30 # Classes and functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 class LatexExporter(Exporter):
33 class LatexExporter(TemplateExporter):
34 """
34 """
35 Exports to a Latex template. Inherit from this class if your template is
35 Exports to a Latex template. Inherit from this class if your template is
36 LaTeX based and you need custom tranformers/filters. Inherit from it if
36 LaTeX based and you need custom tranformers/filters. Inherit from it if
37 you are writing your own HTML template and need custom tranformers/filters.
37 you are writing your own HTML template and need custom tranformers/filters.
38 If you don't need custom tranformers/filters, just change the
38 If you don't need custom tranformers/filters, just change the
39 'template_file' config option. Place your template in the special "/latex"
39 'template_file' config option. Place your template in the special "/latex"
40 subfolder of the "../templates" folder.
40 subfolder of the "../templates" folder.
41 """
41 """
42
42
43 file_extension = Unicode(
43 file_extension = Unicode(
44 'tex', config=True,
44 'tex', config=True,
45 help="Extension of the file that should be written to disk")
45 help="Extension of the file that should be written to disk")
46
46
47 default_template = Unicode('article', config=True, help="""Template of the
47 default_template = Unicode('article', config=True, help="""Template of the
48 data format to use. I.E. 'full' or 'basic'""")
48 data format to use. I.E. 'full' or 'basic'""")
49
49
50 #Latex constants
50 #Latex constants
51 default_template_path = Unicode(
51 default_template_path = Unicode(
52 os.path.join("..", "templates", "latex"), config=True,
52 os.path.join("..", "templates", "latex"), config=True,
53 help="Path where the template files are located.")
53 help="Path where the template files are located.")
54
54
55 template_skeleton_path = Unicode(
55 template_skeleton_path = Unicode(
56 os.path.join("..", "templates", "latex", "skeleton"), config=True,
56 os.path.join("..", "templates", "latex", "skeleton"), config=True,
57 help="Path where the template skeleton files are located.")
57 help="Path where the template skeleton files are located.")
58
58
59 #Special Jinja2 syntax that will not conflict when exporting latex.
59 #Special Jinja2 syntax that will not conflict when exporting latex.
60 jinja_comment_block_start = Unicode("((=", config=True)
60 jinja_comment_block_start = Unicode("((=", config=True)
61 jinja_comment_block_end = Unicode("=))", config=True)
61 jinja_comment_block_end = Unicode("=))", config=True)
62 jinja_variable_block_start = Unicode("(((", config=True)
62 jinja_variable_block_start = Unicode("(((", config=True)
63 jinja_variable_block_end = Unicode(")))", config=True)
63 jinja_variable_block_end = Unicode(")))", config=True)
64 jinja_logic_block_start = Unicode("((*", config=True)
64 jinja_logic_block_start = Unicode("((*", config=True)
65 jinja_logic_block_end = Unicode("*))", config=True)
65 jinja_logic_block_end = Unicode("*))", config=True)
66
66
67 #Extension that the template files use.
67 #Extension that the template files use.
68 template_extension = Unicode(".tplx", config=True)
68 template_extension = Unicode(".tplx", config=True)
69
69
70
70
71 @property
71 @property
72 def default_config(self):
72 def default_config(self):
73 c = Config({
73 c = Config({
74 'NbConvertBase': {
74 'NbConvertBase': {
75 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
75 'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
76 },
76 },
77 'ExtractOutputPreprocessor': {
77 'ExtractOutputPreprocessor': {
78 'enabled':True
78 'enabled':True
79 },
79 },
80 'SVG2PDFPreprocessor': {
80 'SVG2PDFPreprocessor': {
81 'enabled':True
81 'enabled':True
82 },
82 },
83 'LatexPreprocessor': {
83 'LatexPreprocessor': {
84 'enabled':True
84 'enabled':True
85 },
85 },
86 'SphinxPreprocessor': {
86 'SphinxPreprocessor': {
87 'enabled':True
87 'enabled':True
88 }
88 }
89 })
89 })
90 c.merge(super(LatexExporter,self).default_config)
90 c.merge(super(LatexExporter,self).default_config)
91 return c
91 return c
@@ -1,38 +1,38 b''
1 """
1 """
2 Exporter that will export your ipynb to Markdown.
2 Exporter that will export your ipynb to Markdown.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.config import Config
16 from IPython.config import Config
17 from IPython.utils.traitlets import Unicode
17 from IPython.utils.traitlets import Unicode
18
18
19 from .exporter import TemplateExporter
19 from .templateexporter import TemplateExporter
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Classes
22 # Classes
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class MarkdownExporter(TemplateExporter):
25 class MarkdownExporter(TemplateExporter):
26 """
26 """
27 Exports to a markdown document (.md)
27 Exports to a markdown document (.md)
28 """
28 """
29
29
30 file_extension = Unicode(
30 file_extension = Unicode(
31 'md', config=True,
31 'md', config=True,
32 help="Extension of the file that should be written to disk")
32 help="Extension of the file that should be written to disk")
33
33
34 @property
34 @property
35 def default_config(self):
35 def default_config(self):
36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
37 c.merge(super(MarkdownExporter,self).default_config)
37 c.merge(super(MarkdownExporter,self).default_config)
38 return c
38 return c
@@ -1,31 +1,31 b''
1 """
1 """
2 Python exporter which exports Notebook code into a PY file.
2 Python exporter which exports Notebook code into a PY file.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.utils.traitlets import Unicode
16 from IPython.utils.traitlets import Unicode
17
17
18 from .exporter import TemplateExporter
18 from .templateexporter import TemplateExporter
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes
21 # Classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 class PythonExporter(TemplateExporter):
24 class PythonExporter(TemplateExporter):
25 """
25 """
26 Exports a Python code file.
26 Exports a Python code file.
27 """
27 """
28
28
29 file_extension = Unicode(
29 file_extension = Unicode(
30 'py', config=True,
30 'py', config=True,
31 help="Extension of the file that should be written to disk")
31 help="Extension of the file that should be written to disk")
@@ -1,38 +1,38 b''
1 """
1 """
2 Exporter for exporting notebooks to restructured text.
2 Exporter for exporting notebooks to restructured text.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.utils.traitlets import Unicode
16 from IPython.utils.traitlets import Unicode
17 from IPython.config import Config
17 from IPython.config import Config
18
18
19 from .exporter import TemplateExporter
19 from .templateexporter import TemplateExporter
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Classes
22 # Classes
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class RSTExporter(TemplateExporter):
25 class RSTExporter(TemplateExporter):
26 """
26 """
27 Exports restructured text documents.
27 Exports restructured text documents.
28 """
28 """
29
29
30 file_extension = Unicode(
30 file_extension = Unicode(
31 'rst', config=True,
31 'rst', config=True,
32 help="Extension of the file that should be written to disk")
32 help="Extension of the file that should be written to disk")
33
33
34 @property
34 @property
35 def default_config(self):
35 def default_config(self):
36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
36 c = Config({'ExtractOutputPreprocessor':{'enabled':True}})
37 c.merge(super(RSTExporter,self).default_config)
37 c.merge(super(RSTExporter,self).default_config)
38 return c
38 return c
@@ -1,52 +1,52 b''
1 """
1 """
2 Contains slide show exporter
2 Contains slide show exporter
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.utils.traitlets import Unicode
17 from IPython.utils.traitlets import Unicode
18
18
19 from IPython.nbconvert import preprocessors
19 from IPython.nbconvert import preprocessors
20 from IPython.config import Config
20 from IPython.config import Config
21
21
22 from .exporter import TemplateExporter
22 from .templateexporter import TemplateExporter
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Classes
25 # Classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class SlidesExporter(TemplateExporter):
28 class SlidesExporter(TemplateExporter):
29 """
29 """
30 Exports slides
30 Exports slides
31 """
31 """
32
32
33 file_extension = Unicode(
33 file_extension = Unicode(
34 'slides.html', config=True,
34 'slides.html', config=True,
35 help="Extension of the file that should be written to disk"
35 help="Extension of the file that should be written to disk"
36 )
36 )
37
37
38 default_template = Unicode('reveal', config=True, help="""Template of the
38 default_template = Unicode('reveal', config=True, help="""Template of the
39 data format to use. I.E. 'reveal'""")
39 data format to use. I.E. 'reveal'""")
40
40
41 @property
41 @property
42 def default_config(self):
42 def default_config(self):
43 c = Config({
43 c = Config({
44 'CSSHTMLHeaderPreprocessor':{
44 'CSSHTMLHeaderPreprocessor':{
45 'enabled':True
45 'enabled':True
46 },
46 },
47 'RevealHelpPreprocessor':{
47 'RevealHelpPreprocessor':{
48 'enabled':True,
48 'enabled':True,
49 },
49 },
50 })
50 })
51 c.merge(super(SlidesExporter,self).default_config)
51 c.merge(super(SlidesExporter,self).default_config)
52 return c
52 return c
@@ -1,520 +1,315 b''
1 """This module defines Exporter, a highly configurable converter
1 """This module defines Exporter, a highly configurable converter
2 that uses Jinja2 to export notebook files into different formats.
2 that uses Jinja2 to export notebook files into different formats.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import print_function, absolute_import
17 from __future__ import print_function, absolute_import
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import io
21 import os
20 import os
22 import inspect
23 import copy
24 import collections
25 import datetime
26
21
27 # other libs/dependencies
22 # other libs/dependencies
28 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
23 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
29
24
30 # IPython imports
25 # IPython imports
31 from IPython.config.configurable import LoggingConfigurable
26 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any
32 from IPython.config import Config
33 from IPython.nbformat import current as nbformat
34 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict, Any
35 from IPython.utils.importstring import import_item
27 from IPython.utils.importstring import import_item
36 from IPython.utils import text
28 from IPython.utils import py3compat, text
37 from IPython.utils import py3compat
38
29
39 from IPython.nbconvert import preprocessors as nbpreprocessors
40 from IPython.nbconvert import filters
30 from IPython.nbconvert import filters
31 from .exporter import Exporter
41
32
42 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
43 # Globals and constants
34 # Globals and constants
44 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
45
36
46 #Jinja2 extensions to load.
37 #Jinja2 extensions to load.
47 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
38 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
48
39
49 default_filters = {
40 default_filters = {
50 'indent': text.indent,
41 'indent': text.indent,
51 'markdown2html': filters.markdown2html,
42 'markdown2html': filters.markdown2html,
52 'ansi2html': filters.ansi2html,
43 'ansi2html': filters.ansi2html,
53 'filter_data_type': filters.DataTypeFilter,
44 'filter_data_type': filters.DataTypeFilter,
54 'get_lines': filters.get_lines,
45 'get_lines': filters.get_lines,
55 'highlight2html': filters.highlight2html,
46 'highlight2html': filters.highlight2html,
56 'highlight2latex': filters.highlight2latex,
47 'highlight2latex': filters.highlight2latex,
57 'ipython2python': filters.ipython2python,
48 'ipython2python': filters.ipython2python,
58 'posix_path': filters.posix_path,
49 'posix_path': filters.posix_path,
59 'markdown2latex': filters.markdown2latex,
50 'markdown2latex': filters.markdown2latex,
60 'markdown2rst': filters.markdown2rst,
51 'markdown2rst': filters.markdown2rst,
61 'comment_lines': filters.comment_lines,
52 'comment_lines': filters.comment_lines,
62 'strip_ansi': filters.strip_ansi,
53 'strip_ansi': filters.strip_ansi,
63 'strip_dollars': filters.strip_dollars,
54 'strip_dollars': filters.strip_dollars,
64 'strip_files_prefix': filters.strip_files_prefix,
55 'strip_files_prefix': filters.strip_files_prefix,
65 'html2text' : filters.html2text,
56 'html2text' : filters.html2text,
66 'add_anchor': filters.add_anchor,
57 'add_anchor': filters.add_anchor,
67 'ansi2latex': filters.ansi2latex,
58 'ansi2latex': filters.ansi2latex,
68 'strip_math_space': filters.strip_math_space,
59 'strip_math_space': filters.strip_math_space,
69 'wrap_text': filters.wrap_text,
60 'wrap_text': filters.wrap_text,
70 'escape_latex': filters.escape_latex,
61 'escape_latex': filters.escape_latex,
71 'citation2latex': filters.citation2latex,
62 'citation2latex': filters.citation2latex,
72 'path2url': filters.path2url,
63 'path2url': filters.path2url,
73 }
64 }
74
65
75 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
76 # Class
67 # Class
77 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
78
69
79 class ResourcesDict(collections.defaultdict):
70 class TemplateExporter(Exporter):
80 def __missing__(self, key):
81 return ''
82
83
84 class Exporter(LoggingConfigurable):
85 """
71 """
86 Exports notebooks into other file formats. Uses Jinja 2 templating engine
72 Exports notebooks into other file formats. Uses Jinja 2 templating engine
87 to output new formats. Inherit from this class if you are creating a new
73 to output new formats. Inherit from this class if you are creating a new
88 template type along with new filters/preprocessors. If the filters/
74 template type along with new filters/preprocessors. If the filters/
89 preprocessors provided by default suffice, there is no need to inherit from
75 preprocessors provided by default suffice, there is no need to inherit from
90 this class. Instead, override the template_file and file_extension
76 this class. Instead, override the template_file and file_extension
91 traits via a config file.
77 traits via a config file.
92
78
93 {filters}
79 {filters}
94 """
80 """
95
81
96 # finish the docstring
82 # finish the docstring
97 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
83 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
98
84
99
85
100 template_file = Unicode(u'default',
86 template_file = Unicode(u'default',
101 config=True,
87 config=True,
102 help="Name of the template file to use")
88 help="Name of the template file to use")
103 def _template_file_changed(self, name, old, new):
89 def _template_file_changed(self, name, old, new):
104 if new=='default':
90 if new == 'default':
105 self.template_file = self.default_template
91 self.template_file = self.default_template
106 else:
92 else:
107 self.template_file = new
93 self.template_file = new
108 self.template = None
94 self.template = None
109 self._load_template()
95 self._load_template()
110
96
111 default_template = Unicode(u'')
97 default_template = Unicode(u'')
112 template = Any()
98 template = Any()
113 environment = Any()
99 environment = Any()
114
100
115 file_extension = Unicode(
116 'txt', config=True,
117 help="Extension of the file that should be written to disk"
118 )
119
120 template_path = List(['.'], config=True)
101 template_path = List(['.'], config=True)
121 def _template_path_changed(self, name, old, new):
102 def _template_path_changed(self, name, old, new):
122 self._load_template()
103 self._load_template()
123
104
124 default_template_path = Unicode(
105 default_template_path = Unicode(
125 os.path.join("..", "templates"),
106 os.path.join("..", "templates"),
126 help="Path where the template files are located.")
107 help="Path where the template files are located.")
127
108
128 template_skeleton_path = Unicode(
109 template_skeleton_path = Unicode(
129 os.path.join("..", "templates", "skeleton"),
110 os.path.join("..", "templates", "skeleton"),
130 help="Path where the template skeleton files are located.")
111 help="Path where the template skeleton files are located.")
131
112
132 #Jinja block definitions
113 #Jinja block definitions
133 jinja_comment_block_start = Unicode("", config=True)
114 jinja_comment_block_start = Unicode("", config=True)
134 jinja_comment_block_end = Unicode("", config=True)
115 jinja_comment_block_end = Unicode("", config=True)
135 jinja_variable_block_start = Unicode("", config=True)
116 jinja_variable_block_start = Unicode("", config=True)
136 jinja_variable_block_end = Unicode("", config=True)
117 jinja_variable_block_end = Unicode("", config=True)
137 jinja_logic_block_start = Unicode("", config=True)
118 jinja_logic_block_start = Unicode("", config=True)
138 jinja_logic_block_end = Unicode("", config=True)
119 jinja_logic_block_end = Unicode("", config=True)
139
120
140 #Extension that the template files use.
121 #Extension that the template files use.
141 template_extension = Unicode(".tpl", config=True)
122 template_extension = Unicode(".tpl", config=True)
142
123
143 #Configurability, allows the user to easily add filters and preprocessors.
144 preprocessors = List(config=True,
145 help="""List of preprocessors, by name or namespace, to enable.""")
146
147 filters = Dict(config=True,
124 filters = Dict(config=True,
148 help="""Dictionary of filters, by name and namespace, to add to the Jinja
125 help="""Dictionary of filters, by name and namespace, to add to the Jinja
149 environment.""")
126 environment.""")
150
127
151 default_preprocessors = List([nbpreprocessors.coalesce_streams,
152 nbpreprocessors.SVG2PDFPreprocessor,
153 nbpreprocessors.ExtractOutputPreprocessor,
154 nbpreprocessors.CSSHTMLHeaderPreprocessor,
155 nbpreprocessors.RevealHelpPreprocessor,
156 nbpreprocessors.LatexPreprocessor,
157 nbpreprocessors.SphinxPreprocessor],
158 config=True,
159 help="""List of preprocessors available by default, by name, namespace,
160 instance, or type.""")
161
162
128
163 def __init__(self, config=None, extra_loaders=None, **kw):
129 def __init__(self, config=None, extra_loaders=None, **kw):
164 """
130 """
165 Public constructor
131 Public constructor
166
132
167 Parameters
133 Parameters
168 ----------
134 ----------
169 config : config
135 config : config
170 User configuration instance.
136 User configuration instance.
171 extra_loaders : list[of Jinja Loaders]
137 extra_loaders : list[of Jinja Loaders]
172 ordered list of Jinja loader to find templates. Will be tried in order
138 ordered list of Jinja loader to find templates. Will be tried in order
173 before the default FileSystem ones.
139 before the default FileSystem ones.
174 template : str (optional, kw arg)
140 template : str (optional, kw arg)
175 Template to use when exporting.
141 Template to use when exporting.
176 """
142 """
177 if not config:
143 if not config:
178 config = self.default_config
144 config = self.default_config
179
145
180 super(Exporter, self).__init__(config=config, **kw)
146 super(Exporter, self).__init__(config=config, **kw)
181
147
182 #Init
148 #Init
183 self._init_template()
149 self._init_template()
184 self._init_environment(extra_loaders=extra_loaders)
150 self._init_environment(extra_loaders=extra_loaders)
185 self._init_preprocessors()
151 self._init_preprocessors()
186 self._init_filters()
152 self._init_filters()
187
153
188
154
189 @property
190 def default_config(self):
191 return Config()
192
193 def _config_changed(self, name, old, new):
194 """When setting config, make sure to start with our default_config"""
195 c = self.default_config
196 if new:
197 c.merge(new)
198 if c != old:
199 self.config = c
200 super(Exporter, self)._config_changed(name, old, c)
201
202
203 def _load_template(self):
155 def _load_template(self):
204 """Load the Jinja template object from the template file
156 """Load the Jinja template object from the template file
205
157
206 This is a no-op if the template attribute is already defined,
158 This is a no-op if the template attribute is already defined,
207 or the Jinja environment is not setup yet.
159 or the Jinja environment is not setup yet.
208
160
209 This is triggered by various trait changes that would change the template.
161 This is triggered by various trait changes that would change the template.
210 """
162 """
211 if self.template is not None:
163 if self.template is not None:
212 return
164 return
213 # called too early, do nothing
165 # called too early, do nothing
214 if self.environment is None:
166 if self.environment is None:
215 return
167 return
216 # Try different template names during conversion. First try to load the
168 # Try different template names during conversion. First try to load the
217 # template by name with extension added, then try loading the template
169 # template by name with extension added, then try loading the template
218 # as if the name is explicitly specified, then try the name as a
170 # as if the name is explicitly specified, then try the name as a
219 # 'flavor', and lastly just try to load the template by module name.
171 # 'flavor', and lastly just try to load the template by module name.
220 module_name = self.__module__.rsplit('.', 1)[-1]
172 module_name = self.__module__.rsplit('.', 1)[-1]
221 try_names = []
173 try_names = []
222 if self.template_file:
174 if self.template_file:
223 try_names.extend([
175 try_names.extend([
224 self.template_file + self.template_extension,
176 self.template_file + self.template_extension,
225 self.template_file,
177 self.template_file,
226 module_name + '_' + self.template_file + self.template_extension,
178 module_name + '_' + self.template_file + self.template_extension,
227 ])
179 ])
228 try_names.append(module_name + self.template_extension)
180 try_names.append(module_name + self.template_extension)
229 for try_name in try_names:
181 for try_name in try_names:
230 self.log.debug("Attempting to load template %s", try_name)
182 self.log.debug("Attempting to load template %s", try_name)
231 try:
183 try:
232 self.template = self.environment.get_template(try_name)
184 self.template = self.environment.get_template(try_name)
233 except (TemplateNotFound, IOError):
185 except (TemplateNotFound, IOError):
234 pass
186 pass
235 except Exception as e:
187 except Exception as e:
236 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
188 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
237 else:
189 else:
238 self.log.info("Loaded template %s", try_name)
190 self.log.info("Loaded template %s", try_name)
239 break
191 break
240
192
241 def from_notebook_node(self, nb, resources=None, **kw):
193 def from_notebook_node(self, nb, resources=None, **kw):
242 """
194 """
243 Convert a notebook from a notebook node instance.
195 Convert a notebook from a notebook node instance.
244
196
245 Parameters
197 Parameters
246 ----------
198 ----------
247 nb : Notebook node
199 nb : Notebook node
248 resources : dict (**kw)
200 resources : dict (**kw)
249 of additional resources that can be accessed read/write by
201 of additional resources that can be accessed read/write by
250 preprocessors and filters.
202 preprocessors and filters.
251 """
203 """
252 nb_copy = copy.deepcopy(nb)
204 nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
253 resources = self._init_resources(resources)
254
255 # Preprocess
256 nb_copy, resources = self._preprocess(nb_copy, resources)
257
205
258 self._load_template()
206 self._load_template()
259
207
260 if self.template is not None:
208 if self.template is not None:
261 output = self.template.render(nb=nb_copy, resources=resources)
209 output = self.template.render(nb=nb_copy, resources=resources)
262 else:
210 else:
263 raise IOError('template file "%s" could not be found' % self.template_file)
211 raise IOError('template file "%s" could not be found' % self.template_file)
264 return output, resources
212 return output, resources
265
213
266
214
267 def from_filename(self, filename, resources=None, **kw):
268 """
269 Convert a notebook from a notebook file.
270
271 Parameters
272 ----------
273 filename : str
274 Full filename of the notebook file to open and convert.
275 """
276
277 #Pull the metadata from the filesystem.
278 if resources is None:
279 resources = ResourcesDict()
280 if not 'metadata' in resources or resources['metadata'] == '':
281 resources['metadata'] = ResourcesDict()
282 basename = os.path.basename(filename)
283 notebook_name = basename[:basename.rfind('.')]
284 resources['metadata']['name'] = notebook_name
285
286 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
287 resources['metadata']['modified_date'] = modified_date.strftime(text.date_format)
288
289 with io.open(filename) as f:
290 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
291
292
293 def from_file(self, file_stream, resources=None, **kw):
294 """
295 Convert a notebook from a notebook file.
296
297 Parameters
298 ----------
299 file_stream : file-like object
300 Notebook file-like object to convert.
301 """
302 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
303
304
305 def register_preprocessor(self, preprocessor, enabled=False):
306 """
307 Register a preprocessor.
308 Preprocessors are classes that act upon the notebook before it is
309 passed into the Jinja templating engine. Preprocessors are also
310 capable of passing additional information to the Jinja
311 templating engine.
312
313 Parameters
314 ----------
315 preprocessor : preprocessor
316 """
317 if preprocessor is None:
318 raise TypeError('preprocessor')
319 isclass = isinstance(preprocessor, type)
320 constructed = not isclass
321
322 #Handle preprocessor's registration based on it's type
323 if constructed and isinstance(preprocessor, py3compat.string_types):
324 #Preprocessor is a string, import the namespace and recursively call
325 #this register_preprocessor method
326 preprocessor_cls = import_item(preprocessor)
327 return self.register_preprocessor(preprocessor_cls, enabled)
328
329 if constructed and hasattr(preprocessor, '__call__'):
330 #Preprocessor is a function, no need to construct it.
331 #Register and return the preprocessor.
332 if enabled:
333 preprocessor.enabled = True
334 self._preprocessors.append(preprocessor)
335 return preprocessor
336
337 elif isclass and isinstance(preprocessor, MetaHasTraits):
338 #Preprocessor is configurable. Make sure to pass in new default for
339 #the enabled flag if one was specified.
340 self.register_preprocessor(preprocessor(parent=self), enabled)
341
342 elif isclass:
343 #Preprocessor is not configurable, construct it
344 self.register_preprocessor(preprocessor(), enabled)
345
346 else:
347 #Preprocessor is an instance of something without a __call__
348 #attribute.
349 raise TypeError('preprocessor')
350
351
352 def register_filter(self, name, jinja_filter):
215 def register_filter(self, name, jinja_filter):
353 """
216 """
354 Register a filter.
217 Register a filter.
355 A filter is a function that accepts and acts on one string.
218 A filter is a function that accepts and acts on one string.
356 The filters are accesible within the Jinja templating engine.
219 The filters are accesible within the Jinja templating engine.
357
220
358 Parameters
221 Parameters
359 ----------
222 ----------
360 name : str
223 name : str
361 name to give the filter in the Jinja engine
224 name to give the filter in the Jinja engine
362 filter : filter
225 filter : filter
363 """
226 """
364 if jinja_filter is None:
227 if jinja_filter is None:
365 raise TypeError('filter')
228 raise TypeError('filter')
366 isclass = isinstance(jinja_filter, type)
229 isclass = isinstance(jinja_filter, type)
367 constructed = not isclass
230 constructed = not isclass
368
231
369 #Handle filter's registration based on it's type
232 #Handle filter's registration based on it's type
370 if constructed and isinstance(jinja_filter, py3compat.string_types):
233 if constructed and isinstance(jinja_filter, py3compat.string_types):
371 #filter is a string, import the namespace and recursively call
234 #filter is a string, import the namespace and recursively call
372 #this register_filter method
235 #this register_filter method
373 filter_cls = import_item(jinja_filter)
236 filter_cls = import_item(jinja_filter)
374 return self.register_filter(name, filter_cls)
237 return self.register_filter(name, filter_cls)
375
238
376 if constructed and hasattr(jinja_filter, '__call__'):
239 if constructed and hasattr(jinja_filter, '__call__'):
377 #filter is a function, no need to construct it.
240 #filter is a function, no need to construct it.
378 self.environment.filters[name] = jinja_filter
241 self.environment.filters[name] = jinja_filter
379 return jinja_filter
242 return jinja_filter
380
243
381 elif isclass and isinstance(jinja_filter, MetaHasTraits):
244 elif isclass and isinstance(jinja_filter, MetaHasTraits):
382 #filter is configurable. Make sure to pass in new default for
245 #filter is configurable. Make sure to pass in new default for
383 #the enabled flag if one was specified.
246 #the enabled flag if one was specified.
384 filter_instance = jinja_filter(parent=self)
247 filter_instance = jinja_filter(parent=self)
385 self.register_filter(name, filter_instance )
248 self.register_filter(name, filter_instance )
386
249
387 elif isclass:
250 elif isclass:
388 #filter is not configurable, construct it
251 #filter is not configurable, construct it
389 filter_instance = jinja_filter()
252 filter_instance = jinja_filter()
390 self.register_filter(name, filter_instance)
253 self.register_filter(name, filter_instance)
391
254
392 else:
255 else:
393 #filter is an instance of something without a __call__
256 #filter is an instance of something without a __call__
394 #attribute.
257 #attribute.
395 raise TypeError('filter')
258 raise TypeError('filter')
396
259
397
260
398 def _init_template(self):
261 def _init_template(self):
399 """
262 """
400 Make sure a template name is specified. If one isn't specified, try to
263 Make sure a template name is specified. If one isn't specified, try to
401 build one from the information we know.
264 build one from the information we know.
402 """
265 """
403 self._template_file_changed('template_file', self.template_file, self.template_file)
266 self._template_file_changed('template_file', self.template_file, self.template_file)
404
267
405
268
406 def _init_environment(self, extra_loaders=None):
269 def _init_environment(self, extra_loaders=None):
407 """
270 """
408 Create the Jinja templating environment.
271 Create the Jinja templating environment.
409 """
272 """
410 here = os.path.dirname(os.path.realpath(__file__))
273 here = os.path.dirname(os.path.realpath(__file__))
411 loaders = []
274 loaders = []
412 if extra_loaders:
275 if extra_loaders:
413 loaders.extend(extra_loaders)
276 loaders.extend(extra_loaders)
414
277
415 paths = self.template_path
278 paths = self.template_path
416 paths.extend([os.path.join(here, self.default_template_path),
279 paths.extend([os.path.join(here, self.default_template_path),
417 os.path.join(here, self.template_skeleton_path)])
280 os.path.join(here, self.template_skeleton_path)])
418 loaders.append(FileSystemLoader(paths))
281 loaders.append(FileSystemLoader(paths))
419
282
420 self.environment = Environment(
283 self.environment = Environment(
421 loader= ChoiceLoader(loaders),
284 loader= ChoiceLoader(loaders),
422 extensions=JINJA_EXTENSIONS
285 extensions=JINJA_EXTENSIONS
423 )
286 )
424
287
425 #Set special Jinja2 syntax that will not conflict with latex.
288 #Set special Jinja2 syntax that will not conflict with latex.
426 if self.jinja_logic_block_start:
289 if self.jinja_logic_block_start:
427 self.environment.block_start_string = self.jinja_logic_block_start
290 self.environment.block_start_string = self.jinja_logic_block_start
428 if self.jinja_logic_block_end:
291 if self.jinja_logic_block_end:
429 self.environment.block_end_string = self.jinja_logic_block_end
292 self.environment.block_end_string = self.jinja_logic_block_end
430 if self.jinja_variable_block_start:
293 if self.jinja_variable_block_start:
431 self.environment.variable_start_string = self.jinja_variable_block_start
294 self.environment.variable_start_string = self.jinja_variable_block_start
432 if self.jinja_variable_block_end:
295 if self.jinja_variable_block_end:
433 self.environment.variable_end_string = self.jinja_variable_block_end
296 self.environment.variable_end_string = self.jinja_variable_block_end
434 if self.jinja_comment_block_start:
297 if self.jinja_comment_block_start:
435 self.environment.comment_start_string = self.jinja_comment_block_start
298 self.environment.comment_start_string = self.jinja_comment_block_start
436 if self.jinja_comment_block_end:
299 if self.jinja_comment_block_end:
437 self.environment.comment_end_string = self.jinja_comment_block_end
300 self.environment.comment_end_string = self.jinja_comment_block_end
438
301
439
302
440 def _init_preprocessors(self):
441 """
442 Register all of the preprocessors needed for this exporter, disabled
443 unless specified explicitly.
444 """
445 self._preprocessors = []
446
447 #Load default preprocessors (not necessarly enabled by default).
448 if self.default_preprocessors:
449 for preprocessor in self.default_preprocessors:
450 self.register_preprocessor(preprocessor)
451
452 #Load user preprocessors. Enable by default.
453 if self.preprocessors:
454 for preprocessor in self.preprocessors:
455 self.register_preprocessor(preprocessor, enabled=True)
456
457
458 def _init_filters(self):
303 def _init_filters(self):
459 """
304 """
460 Register all of the filters required for the exporter.
305 Register all of the filters required for the exporter.
461 """
306 """
462
307
463 #Add default filters to the Jinja2 environment
308 #Add default filters to the Jinja2 environment
464 for key, value in default_filters.items():
309 for key, value in default_filters.items():
465 self.register_filter(key, value)
310 self.register_filter(key, value)
466
311
467 #Load user filters. Overwrite existing filters if need be.
312 #Load user filters. Overwrite existing filters if need be.
468 if self.filters:
313 if self.filters:
469 for key, user_filter in self.filters.items():
314 for key, user_filter in self.filters.items():
470 self.register_filter(key, user_filter)
315 self.register_filter(key, user_filter)
471
472
473 def _init_resources(self, resources):
474
475 #Make sure the resources dict is of ResourcesDict type.
476 if resources is None:
477 resources = ResourcesDict()
478 if not isinstance(resources, ResourcesDict):
479 new_resources = ResourcesDict()
480 new_resources.update(resources)
481 resources = new_resources
482
483 #Make sure the metadata extension exists in resources
484 if 'metadata' in resources:
485 if not isinstance(resources['metadata'], ResourcesDict):
486 resources['metadata'] = ResourcesDict(resources['metadata'])
487 else:
488 resources['metadata'] = ResourcesDict()
489 if not resources['metadata']['name']:
490 resources['metadata']['name'] = 'Notebook'
491
492 #Set the output extension
493 resources['output_extension'] = self.file_extension
494 return resources
495
496
497 def _preprocess(self, nb, resources):
498 """
499 Preprocess the notebook before passing it into the Jinja engine.
500 To preprocess the notebook is to apply all of the
501
502 Parameters
503 ----------
504 nb : notebook node
505 notebook that is being exported.
506 resources : a dict of additional resources that
507 can be accessed read/write by preprocessors
508 and filters.
509 """
510
511 # Do a copy.deepcopy first,
512 # we are never safe enough with what the preprocessors could do.
513 nbc = copy.deepcopy(nb)
514 resc = copy.deepcopy(resources)
515
516 #Run each preprocessor on the notebook. Carry the output along
517 #to each preprocessor
518 for preprocessor in self._preprocessors:
519 nbc, resc = preprocessor(nbc, resc)
520 return nbc, resc
@@ -1,108 +1,108 b''
1 """
1 """
2 Module with tests for exporter.py
2 Module with tests for exporter.py
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.config import Config
17 from IPython.config import Config
18
18
19 from .base import ExportersTestsBase
19 from .base import ExportersTestsBase
20 from .cheese import CheesePreprocessor
20 from .cheese import CheesePreprocessor
21 from ..exporter import Exporter
21 from ..templateexporter import TemplateExporter
22
22
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Class
25 # Class
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class TestExporter(ExportersTestsBase):
28 class TestExporter(ExportersTestsBase):
29 """Contains test functions for exporter.py"""
29 """Contains test functions for exporter.py"""
30
30
31
31
32 def test_constructor(self):
32 def test_constructor(self):
33 """
33 """
34 Can an Exporter be constructed?
34 Can an TemplateExporter be constructed?
35 """
35 """
36 Exporter()
36 TemplateExporter()
37
37
38
38
39 def test_export(self):
39 def test_export(self):
40 """
40 """
41 Can an Exporter export something?
41 Can an Exporter export something?
42 """
42 """
43 exporter = self._make_exporter()
43 exporter = self._make_exporter()
44 (output, resources) = exporter.from_filename(self._get_notebook())
44 (output, resources) = exporter.from_filename(self._get_notebook())
45 assert len(output) > 0
45 assert len(output) > 0
46
46
47
47
48 def test_extract_outputs(self):
48 def test_extract_outputs(self):
49 """
49 """
50 If the ExtractOutputPreprocessor is enabled, are outputs extracted?
50 If the ExtractOutputPreprocessor is enabled, are outputs extracted?
51 """
51 """
52 config = Config({'ExtractOutputPreprocessor': {'enabled': True}})
52 config = Config({'ExtractOutputPreprocessor': {'enabled': True}})
53 exporter = self._make_exporter(config=config)
53 exporter = self._make_exporter(config=config)
54 (output, resources) = exporter.from_filename(self._get_notebook())
54 (output, resources) = exporter.from_filename(self._get_notebook())
55 assert resources is not None
55 assert resources is not None
56 assert isinstance(resources['outputs'], dict)
56 assert isinstance(resources['outputs'], dict)
57 assert len(resources['outputs']) > 0
57 assert len(resources['outputs']) > 0
58
58
59
59
60 def test_preprocessor_class(self):
60 def test_preprocessor_class(self):
61 """
61 """
62 Can a preprocessor be added to the preprocessors list by class type?
62 Can a preprocessor be added to the preprocessors list by class type?
63 """
63 """
64 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor]}})
64 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor]}})
65 exporter = self._make_exporter(config=config)
65 exporter = self._make_exporter(config=config)
66 (output, resources) = exporter.from_filename(self._get_notebook())
66 (output, resources) = exporter.from_filename(self._get_notebook())
67 assert resources is not None
67 assert resources is not None
68 assert resources['cheese'] == 'real'
68 assert resources['cheese'] == 'real'
69
69
70
70
71 def test_preprocessor_instance(self):
71 def test_preprocessor_instance(self):
72 """
72 """
73 Can a preprocessor be added to the preprocessors list by instance?
73 Can a preprocessor be added to the preprocessors list by instance?
74 """
74 """
75 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor()]}})
75 config = Config({'Exporter': {'preprocessors': [CheesePreprocessor()]}})
76 exporter = self._make_exporter(config=config)
76 exporter = self._make_exporter(config=config)
77 (output, resources) = exporter.from_filename(self._get_notebook())
77 (output, resources) = exporter.from_filename(self._get_notebook())
78 assert resources is not None
78 assert resources is not None
79 assert resources['cheese'] == 'real'
79 assert resources['cheese'] == 'real'
80
80
81
81
82 def test_preprocessor_dottedobjectname(self):
82 def test_preprocessor_dottedobjectname(self):
83 """
83 """
84 Can a preprocessor be added to the preprocessors list by dotted object name?
84 Can a preprocessor be added to the preprocessors list by dotted object name?
85 """
85 """
86 config = Config({'Exporter': {'preprocessors': ['IPython.nbconvert.exporters.tests.cheese.CheesePreprocessor']}})
86 config = Config({'Exporter': {'preprocessors': ['IPython.nbconvert.exporters.tests.cheese.CheesePreprocessor']}})
87 exporter = self._make_exporter(config=config)
87 exporter = self._make_exporter(config=config)
88 (output, resources) = exporter.from_filename(self._get_notebook())
88 (output, resources) = exporter.from_filename(self._get_notebook())
89 assert resources is not None
89 assert resources is not None
90 assert resources['cheese'] == 'real'
90 assert resources['cheese'] == 'real'
91
91
92
92
93 def test_preprocessor_via_method(self):
93 def test_preprocessor_via_method(self):
94 """
94 """
95 Can a preprocessor be added via the Exporter convenience method?
95 Can a preprocessor be added via the Exporter convenience method?
96 """
96 """
97 exporter = self._make_exporter()
97 exporter = self._make_exporter()
98 exporter.register_preprocessor(CheesePreprocessor, enabled=True)
98 exporter.register_preprocessor(CheesePreprocessor, enabled=True)
99 (output, resources) = exporter.from_filename(self._get_notebook())
99 (output, resources) = exporter.from_filename(self._get_notebook())
100 assert resources is not None
100 assert resources is not None
101 assert resources['cheese'] == 'real'
101 assert resources['cheese'] == 'real'
102
102
103
103
104 def _make_exporter(self, config=None):
104 def _make_exporter(self, config=None):
105 #Create the exporter instance, make sure to set a template name since
105 #Create the exporter instance, make sure to set a template name since
106 #the base Exporter doesn't have a template associated with it.
106 #the base Exporter doesn't have a template associated with it.
107 exporter = Exporter(config=config, template_file='python')
107 exporter = TemplateExporter(config=config, template_file='python')
108 return exporter
108 return exporter
@@ -1,7 +1,7 b''
1 from .ansi import *
1 from .ansi import *
2 from .citation import *
2 from .datatypefilter import *
3 from .datatypefilter import *
3 from .highlight import *
4 from .highlight import *
4 from .latex import *
5 from .latex import *
5 from .markdown import *
6 from .markdown import *
6 from .strings import *
7 from .strings import *
7 from .citation import * No newline at end of file
@@ -1,53 +1,53 b''
1 """
1 """
2 Module with utility functions for preprocessor tests
2 Module with utility functions for preprocessor tests
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.nbformat import current as nbformat
17 from IPython.nbformat import current as nbformat
18
18
19 from ...tests.base import TestsBase
19 from ...tests.base import TestsBase
20 from ...exporters.baseexporter import ResourcesDict
20 from ...exporters.exporter import ResourcesDict
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Class
23 # Class
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 class PreprocessorTestsBase(TestsBase):
26 class PreprocessorTestsBase(TestsBase):
27 """Contains test functions preprocessor tests"""
27 """Contains test functions preprocessor tests"""
28
28
29
29
30 def build_notebook(self):
30 def build_notebook(self):
31 """Build a notebook in memory for use with preprocessor tests"""
31 """Build a notebook in memory for use with preprocessor tests"""
32
32
33 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a"),
33 outputs = [nbformat.new_output(output_type="stream", stream="stdout", output_text="a"),
34 nbformat.new_output(output_type="text", output_text="b"),
34 nbformat.new_output(output_type="text", output_text="b"),
35 nbformat.new_output(output_type="stream", stream="stdout", output_text="c"),
35 nbformat.new_output(output_type="stream", stream="stdout", output_text="c"),
36 nbformat.new_output(output_type="stream", stream="stdout", output_text="d"),
36 nbformat.new_output(output_type="stream", stream="stdout", output_text="d"),
37 nbformat.new_output(output_type="stream", stream="stderr", output_text="e"),
37 nbformat.new_output(output_type="stream", stream="stderr", output_text="e"),
38 nbformat.new_output(output_type="stream", stream="stderr", output_text="f"),
38 nbformat.new_output(output_type="stream", stream="stderr", output_text="f"),
39 nbformat.new_output(output_type="png", output_png='Zw==')] #g
39 nbformat.new_output(output_type="png", output_png='Zw==')] #g
40
40
41 cells=[nbformat.new_code_cell(input="$ e $", prompt_number=1,outputs=outputs),
41 cells=[nbformat.new_code_cell(input="$ e $", prompt_number=1,outputs=outputs),
42 nbformat.new_text_cell('markdown', source="$ e $")]
42 nbformat.new_text_cell('markdown', source="$ e $")]
43 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
43 worksheets = [nbformat.new_worksheet(name="worksheet1", cells=cells)]
44
44
45 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
45 return nbformat.new_notebook(name="notebook1", worksheets=worksheets)
46
46
47
47
48 def build_resources(self):
48 def build_resources(self):
49 """Build an empty resources dictionary."""
49 """Build an empty resources dictionary."""
50
50
51 res = ResourcesDict()
51 res = ResourcesDict()
52 res['metadata'] = ResourcesDict()
52 res['metadata'] = ResourcesDict()
53 return res
53 return res
General Comments 0
You need to be logged in to leave comments. Login now