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