##// END OF EJS Templates
Do not use mutable class defautl parameter...
Matthias BUSSONNIER -
Show More
@@ -1,317 +1,317 b''
1 1 """This module defines Exporter, 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 inspect
23 23
24 24 # IPython imports
25 25 from IPython.config.configurable import Configurable
26 26 from IPython.nbformat import current as nbformat
27 27 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
28 28 from IPython.utils.text import indent
29 29
30 30 # other libs/dependencies
31 31 from jinja2 import Environment, FileSystemLoader
32 32 from markdown import markdown
33 33
34 34 # local import
35 35 import nbconvert.filters.strings
36 36 import nbconvert.filters.markdown
37 37 import nbconvert.filters.latex
38 38 import nbconvert.filters.datatypefilter
39 39 import nbconvert.filters.highlight
40 40 import nbconvert.filters.ansi
41 41
42 42 import nbconvert.transformers.extractfigure
43 43 import nbconvert.transformers.coalescestreams
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Globals and constants
47 47 #-----------------------------------------------------------------------------
48 48
49 49 #Jinja2 extensions to load.
50 50 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Class
54 54 #-----------------------------------------------------------------------------
55 55
56 56 class Exporter(Configurable):
57 57 """
58 58 Exports notebooks into other file formats. Uses Jinja 2 templating engine
59 59 to output new formats. Inherit from this class if you are creating a new
60 60 template type along with new filters/transformers. If the filters/
61 61 transformers provided by default suffice, there is no need to inherit from
62 62 this class. Instead, override the template_file and file_extension
63 63 traits via a config file.
64 64 """
65 65
66 66 template_file = Unicode(
67 67 '', config=True,
68 68 help="Name of the template file to use")
69 69
70 70 file_extension = Unicode(
71 71 'txt', config=True,
72 72 help="Extension of the file that should be written to disk"
73 73 )
74 74
75 75 template_path = Unicode(
76 76 "/../templates/", config=True,
77 77 help="Path where the template files are located.")
78 78
79 79 template_skeleton_path = Unicode(
80 80 "/../templates/skeleton/", config=True,
81 81 help="Path where the template skeleton files are located.")
82 82
83 83 #Jinja block definitions
84 84 jinja_comment_block_start = Unicode("", config=True)
85 85 jinja_comment_block_end = Unicode("", config=True)
86 86 jinja_variable_block_start = Unicode("", config=True)
87 87 jinja_variable_block_end = Unicode("", config=True)
88 88 jinja_logic_block_start = Unicode("", config=True)
89 89 jinja_logic_block_end = Unicode("", config=True)
90 90
91 91 #Extension that the template files use.
92 92 template_extension = Unicode(".tpl", config=True)
93 93
94 94 #Processors that process the input data prior to the export, set in the
95 95 #constructor for this class.
96 transformers = []
96 transformers = None
97 97
98 98
99 99 def __init__(self, transformers=None, filters=None, config=None, **kw):
100 100 """
101 101 Public constructor
102 102
103 103 Parameters
104 104 ----------
105 105 transformers : list[of transformer]
106 106 Custom transformers to apply to the notebook prior to engaging
107 107 the Jinja template engine. Any transformers specified here
108 108 will override existing transformers if a naming conflict
109 109 occurs.
110 110 filters : list[of filter]
111 111 Custom filters to make accessible to the Jinja templates. Any
112 112 filters specified here will override existing filters if a
113 113 naming conflict occurs.
114 114 config : config
115 115 User configuration instance.
116 116 """
117 117
118 118 #Call the base class constructor
119 119 super(Exporter, self).__init__(config=config, **kw)
120 120
121 121 #Standard environment
122 122 self._init_environment()
123 123
124 124 #Add transformers
125 125 self._register_transformers()
126 126
127 127 #Add filters to the Jinja2 environment
128 128 self._register_filters()
129 129
130 130 #Load user transformers. Overwrite existing transformers if need be.
131 if not transformers is None:
131 if transformers :
132 132 for transformer in transformers:
133 133 self.register_transformer(transformer)
134 134
135 135 #Load user filters. Overwrite existing filters if need be.
136 136 if not filters is None:
137 137 for key, user_filter in filters.iteritems():
138 138 if issubclass(user_filter, MetaHasTraits):
139 139 self.environment.filters[key] = user_filter(config=config)
140 140 else:
141 141 self.environment.filters[key] = user_filter
142 142
143 143
144 144 def from_notebook_node(self, nb):
145 145 """
146 146 Convert a notebook from a notebook node instance.
147 147
148 148 Parameters
149 149 ----------
150 150 nb : Notebook node
151 151 """
152 152
153 153 nb, resources = self._preprocess(nb)
154 154
155 155 #Load the template file.
156 156 self.template = self.environment.get_template(self.template_file+self.template_extension)
157 157
158 158 return self.template.render(nb=nb, resources=resources), resources
159 159
160 160
161 161 def from_filename(self, filename):
162 162 """
163 163 Convert a notebook from a notebook file.
164 164
165 165 Parameters
166 166 ----------
167 167 filename : str
168 168 Full filename of the notebook file to open and convert.
169 169 """
170 170
171 171 with io.open(filename) as f:
172 172 return self.from_notebook_node(nbformat.read(f, 'json'))
173 173
174 174
175 175 def from_file(self, file_stream):
176 176 """
177 177 Convert a notebook from a notebook file.
178 178
179 179 Parameters
180 180 ----------
181 181 file_stream : file-like object
182 182 Notebook file-like object to convert.
183 183 """
184 184 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
185 185
186 186
187 187 def register_transformer(self, transformer):
188 188 """
189 189 Register a transformer.
190 190 Transformers are classes that act upon the notebook before it is
191 191 passed into the Jinja templating engine. Transformers are also
192 192 capable of passing additional information to the Jinja
193 193 templating engine.
194 194
195 195 Parameters
196 196 ----------
197 197 transformer : transformer
198 198 """
199 199 if self.transformers is None:
200 200 self.transformers = []
201 201
202 202 if inspect.isfunction(transformer):
203 203 self.transformers.append(transformer)
204 204 return transformer
205 205 elif isinstance(transformer, MetaHasTraits):
206 206 transformer_instance = transformer(config=self.config)
207 207 self.transformers.append(transformer_instance)
208 208 return transformer_instance
209 209 else:
210 210 transformer_instance = transformer()
211 211 self.transformers.append(transformer_instance)
212 212 return transformer_instance
213 213
214 214
215 215 def register_filter(self, name, filter):
216 216 """
217 217 Register a filter.
218 218 A filter is a function that accepts and acts on one string.
219 219 The filters are accesible within the Jinja templating engine.
220 220
221 221 Parameters
222 222 ----------
223 223 name : str
224 224 name to give the filter in the Jinja engine
225 225 filter : filter
226 226 """
227 227 if inspect.isfunction(filter):
228 228 self.environment.filters[name] = filter
229 229 elif isinstance(filter, MetaHasTraits):
230 230 self.environment.filters[name] = filter(config=self.config)
231 231 else:
232 232 self.environment.filters[name] = filter()
233 233 return self.environment.filters[name]
234 234
235 235
236 236 def _register_transformers(self):
237 237 """
238 238 Register all of the transformers needed for this exporter.
239 239 """
240 240
241 241 self.register_transformer(nbconvert.transformers.coalescestreams.coalesce_streams)
242 242
243 243 #Remember the figure extraction transformer so it can be enabled and
244 244 #disabled easily later.
245 245 self.extract_figure_transformer = self.register_transformer(nbconvert.transformers.extractfigure.ExtractFigureTransformer)
246 246
247 247
248 248 def _register_filters(self):
249 249 """
250 250 Register all of the filters required for the exporter.
251 251 """
252 252
253 253 self.register_filter('indent', indent)
254 254 self.register_filter('markdown', markdown)
255 255 self.register_filter('ansi2html', nbconvert.filters.ansi.ansi2html)
256 256 self.register_filter('filter_data_type', nbconvert.filters.datatypefilter.DataTypeFilter)
257 257 self.register_filter('get_lines', nbconvert.filters.strings.get_lines)
258 258 self.register_filter('highlight', nbconvert.filters.highlight.highlight)
259 259 self.register_filter('highlight2html', nbconvert.filters.highlight.highlight)
260 260 self.register_filter('highlight2latex', nbconvert.filters.highlight.highlight2latex)
261 261 self.register_filter('markdown2latex', nbconvert.filters.markdown.markdown2latex)
262 262 self.register_filter('markdown2rst', nbconvert.filters.markdown.markdown2rst)
263 263 self.register_filter('pycomment', nbconvert.filters.strings.python_comment)
264 264 self.register_filter('rm_ansi', nbconvert.filters.ansi.remove_ansi)
265 265 self.register_filter('rm_dollars', nbconvert.filters.strings.strip_dollars)
266 266 self.register_filter('rm_fake', nbconvert.filters.strings.rm_fake)
267 267 self.register_filter('rm_math_space', nbconvert.filters.latex.rm_math_space)
268 268 self.register_filter('wrap', nbconvert.filters.strings.wrap)
269 269
270 270
271 271 def _init_environment(self):
272 272 """
273 273 Create the Jinja templating environment.
274 274 """
275 275
276 276 self.environment = Environment(
277 277 loader=FileSystemLoader([
278 278 os.path.dirname(os.path.realpath(__file__)) + self.template_path,
279 279 os.path.dirname(os.path.realpath(__file__)) + self.template_skeleton_path,
280 280 ]),
281 281 extensions=JINJA_EXTENSIONS
282 282 )
283 283
284 284 #Set special Jinja2 syntax that will not conflict with latex.
285 285 if self.jinja_logic_block_start:
286 286 self.environment.block_start_string = self.jinja_logic_block_start
287 287 if self.jinja_logic_block_end:
288 288 self.environment.block_end_string = self.jinja_logic_block_end
289 289 if self.jinja_variable_block_start:
290 290 self.environment.variable_start_string = self.jinja_variable_block_start
291 291 if self.jinja_variable_block_end:
292 292 self.environment.variable_end_string = self.jinja_variable_block_end
293 293 if self.jinja_comment_block_start:
294 294 self.environment.comment_start_string = self.jinja_comment_block_start
295 295 if self.jinja_comment_block_end:
296 296 self.environment.comment_end_string = self.jinja_comment_block_end
297 297
298 298
299 299 def _preprocess(self, nb):
300 300 """
301 301 Preprocess the notebook before passing it into the Jinja engine.
302 302 To preprocess the notebook is to apply all of the
303 303
304 304 Parameters
305 305 ----------
306 306 nb : notebook node
307 307 notebook that is being exported.
308 308 """
309 309
310 310 #Dict of 'resources' that can be filled by the transformers.
311 311 resources = {}
312 312
313 313 #Run each transformer on the notebook. Carry the output along
314 314 #to each transformer
315 315 for transformer in self.transformers:
316 316 nb, resources = transformer(nb, resources)
317 317 return nb, resources
General Comments 0
You need to be logged in to leave comments. Login now