##// END OF EJS Templates
Merge pull request #73 from scopatz/master...
Bussonnier Matthias -
r8948:c38103d2 merge
parent child Browse files
Show More
@@ -1,411 +1,411 b''
1 1 """Base classes for the notebook conversion pipeline.
2 2
3 3 This module defines Converter, from which all objects designed to implement
4 4 a conversion of IPython notebooks to some other format should inherit.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012, the IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import print_function, absolute_import
19 19
20 20 # Stdlib imports
21 21 import codecs
22 22 import io
23 23 import logging
24 24 import os
25 25 import pprint
26 26 import re
27 27 from types import FunctionType
28 28
29 29 # IPython imports
30 30 from IPython.nbformat import current as nbformat
31 31
32 32 # Our own imports
33 from converters.utils import remove_fake_files_url
33 from .utils import remove_fake_files_url
34 34
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Local utilities
38 38 #-----------------------------------------------------------------------------
39 39
40 40 def clean_filename(filename):
41 41 """
42 42 Remove non-alphanumeric characters from filenames.
43 43
44 44 Parameters
45 45 ----------
46 46 filename : str
47 47 The filename to be sanitized.
48 48
49 49 Returns
50 50 -------
51 51 clean : str
52 52 A sanitized filename that contains only alphanumeric
53 53 characters and underscores.
54 54 """
55 55 filename = re.sub(r'[^a-zA-Z0-9_]', '_', filename)
56 56 return filename
57 57
58 58
59 59 #-----------------------------------------------------------------------------
60 60 # Class declarations
61 61 #-----------------------------------------------------------------------------
62 62
63 63 class ConversionException(Exception):
64 64 pass
65 65
66 66
67 67 class DocStringInheritor(type):
68 68 """
69 69 This metaclass will walk the list of bases until the desired
70 70 superclass method is found AND if that method has a docstring and only
71 71 THEN does it attach the superdocstring to the derived class method.
72 72
73 73 Please use carefully, I just did the metaclass thing by following
74 74 Michael Foord's Metaclass tutorial
75 75 (http://www.voidspace.org.uk/python/articles/metaclasses.shtml), I may
76 76 have missed a step or two.
77 77
78 78 source:
79 79 http://groups.google.com/group/comp.lang.python/msg/26f7b4fcb4d66c95
80 80 by Paul McGuire
81 81 """
82 82 def __new__(meta, classname, bases, classDict):
83 83 newClassDict = {}
84 84 for attributeName, attribute in classDict.items():
85 85 if type(attribute) == FunctionType:
86 86 # look through bases for matching function by name
87 87 for baseclass in bases:
88 88 if hasattr(baseclass, attributeName):
89 89 basefn = getattr(baseclass, attributeName)
90 90 if basefn.__doc__:
91 91 attribute.__doc__ = basefn.__doc__
92 92 break
93 93 newClassDict[attributeName] = attribute
94 94 return type.__new__(meta, classname, bases, newClassDict)
95 95
96 96
97 97 class Converter(object):
98 98 __metaclass__ = DocStringInheritor
99 99 #-------------------------------------------------------------------------
100 100 # Class-level attributes determining the behaviour of the class but
101 101 # probably not varying from instance to instance.
102 102 #-------------------------------------------------------------------------
103 103 default_encoding = 'utf-8'
104 104 extension = str()
105 105 blank_symbol = " "
106 106 # Which display data format is best? Subclasses can override if
107 107 # they have specific requirements.
108 108 display_data_priority = ['pdf', 'svg', 'png', 'jpg', 'text']
109 109 #-------------------------------------------------------------------------
110 110 # Instance-level attributes that are set in the constructor for this
111 111 # class.
112 112 #-------------------------------------------------------------------------
113 113 infile = str()
114 114 highlight_source = True
115 115 infile_dir = str()
116 116 infile_root = str()
117 117 clean_name = str()
118 118 files_dir = str()
119 119 outbase = str()
120 120 #-------------------------------------------------------------------------
121 121 # Instance-level attributes that are set by other methods in the base
122 122 # class.
123 123 #-------------------------------------------------------------------------
124 124 figures_counter = 0
125 125 output = unicode()
126 126 #-------------------------------------------------------------------------
127 127 # Instance-level attributes that are not actually mentioned further
128 128 # in this class. TODO: Could they be usefully moved to a subclass?
129 129 #-------------------------------------------------------------------------
130 130 with_preamble = True
131 131 user_preamble = None
132 132 raw_as_verbatim = False
133 133
134 134 def __init__(self, infile, highlight_source=True, exclude=[]):
135 135 # N.B. Initialized in the same order as defined above. Please try to
136 136 # keep in this way for readability's sake.
137 137 self.exclude_cells = exclude
138 138 self.infile = infile
139 139 self.highlight_source = highlight_source
140 140 self.infile_dir, infile_root = os.path.split(infile)
141 141 self.infile_root = os.path.splitext(infile_root)[0]
142 142 self.clean_name = clean_filename(self.infile_root)
143 143 # Handle the creation of a directory for ancillary files, for
144 144 # formats that need one.
145 145 files_dir = os.path.join(self.infile_dir, self.clean_name + '_files')
146 146 if not os.path.isdir(files_dir):
147 147 os.mkdir(files_dir)
148 148 self.files_dir = files_dir
149 149 self.outbase = os.path.join(self.infile_dir, self.infile_root)
150 150
151 151 def __del__(self):
152 152 if os.path.isdir(self.files_dir) and not os.listdir(self.files_dir):
153 153 os.rmdir(self.files_dir)
154 154
155 155 def _get_prompt_number(self, cell):
156 156 return cell.prompt_number if hasattr(cell, 'prompt_number') \
157 157 else self.blank_symbol
158 158
159 159 def dispatch(self, cell_type):
160 160 """return cell_type dependent render method, for example render_code
161 161 """
162 162 return getattr(self, 'render_' + cell_type, self.render_unknown)
163 163
164 164 def dispatch_display_format(self, format):
165 165 """
166 166 return output_type dependent render method, for example
167 167 render_output_text
168 168 """
169 169 return getattr(self, 'render_display_format_' + format,
170 170 self.render_unknown_display)
171 171
172 172 def convert(self, cell_separator='\n'):
173 173 """
174 174 Generic method to converts notebook to a string representation.
175 175
176 176 This is accomplished by dispatching on the cell_type, so subclasses of
177 177 Convereter class do not need to re-implement this method, but just
178 178 need implementation for the methods that will be dispatched.
179 179
180 180 Parameters
181 181 ----------
182 182 cell_separator : string
183 183 Character or string to join cells with. Default is "\n"
184 184
185 185 Returns
186 186 -------
187 187 out : string
188 188 """
189 189 lines = []
190 190 lines.extend(self.optional_header())
191 191 lines.extend(self.main_body(cell_separator))
192 192 lines.extend(self.optional_footer())
193 193 return u'\n'.join(lines)
194 194
195 195 def main_body(self, cell_separator='\n'):
196 196 converted_cells = []
197 197 for worksheet in self.nb.worksheets:
198 198 for cell in worksheet.cells:
199 199 #print(cell.cell_type) # dbg
200 200 conv_fn = self.dispatch(cell.cell_type)
201 201 if cell.cell_type in ('markdown', 'raw'):
202 202 remove_fake_files_url(cell)
203 203 converted_cells.append('\n'.join(conv_fn(cell)))
204 204 cell_lines = cell_separator.join(converted_cells).split('\n')
205 205 return cell_lines
206 206
207 207 def render(self):
208 208 "read, convert, and save self.infile"
209 209 if not hasattr(self, 'nb'):
210 210 self.read()
211 211 self.output = self.convert()
212 212 assert(type(self.output) == unicode)
213 213 return self.save()
214 214
215 215 def read(self):
216 216 "read and parse notebook into NotebookNode called self.nb"
217 217 with open(self.infile) as f:
218 218 self.nb = nbformat.read(f, 'json')
219 219
220 220 def save(self, outfile=None, encoding=None):
221 221 "read and parse notebook into self.nb"
222 222 if outfile is None:
223 223 outfile = self.outbase + '.' + self.extension
224 224 if encoding is None:
225 225 encoding = self.default_encoding
226 226 with io.open(outfile, 'w', encoding=encoding) as f:
227 227 f.write(self.output)
228 228 return os.path.abspath(outfile)
229 229
230 230 def optional_header(self):
231 231 """
232 232 Optional header to insert at the top of the converted notebook
233 233
234 234 Returns a list
235 235 """
236 236 return []
237 237
238 238 def optional_footer(self):
239 239 """
240 240 Optional footer to insert at the end of the converted notebook
241 241
242 242 Returns a list
243 243 """
244 244 return []
245 245
246 246 def _new_figure(self, data, fmt):
247 247 """Create a new figure file in the given format.
248 248
249 249 Returns a path relative to the input file.
250 250 """
251 251 figname = '%s_fig_%02i.%s' % (self.clean_name,
252 252 self.figures_counter, fmt)
253 253 self.figures_counter += 1
254 254 fullname = os.path.join(self.files_dir, figname)
255 255
256 256 # Binary files are base64-encoded, SVG is already XML
257 257 if fmt in ('png', 'jpg', 'pdf'):
258 258 data = data.decode('base64')
259 259 fopen = lambda fname: open(fname, 'wb')
260 260 else:
261 261 fopen = lambda fname: codecs.open(fname, 'wb',
262 262 self.default_encoding)
263 263
264 264 with fopen(fullname) as f:
265 265 f.write(data)
266 266
267 267 return fullname
268 268
269 269 def render_heading(self, cell):
270 270 """convert a heading cell
271 271
272 272 Returns list."""
273 273 raise NotImplementedError
274 274
275 275 def render_code(self, cell):
276 276 """Convert a code cell
277 277
278 278 Returns list."""
279 279 raise NotImplementedError
280 280
281 281 def render_markdown(self, cell):
282 282 """convert a markdown cell
283 283
284 284 Returns list."""
285 285 raise NotImplementedError
286 286
287 287 def _img_lines(self, img_file):
288 288 """Return list of lines to include an image file."""
289 289 # Note: subclasses may choose to implement format-specific _FMT_lines
290 290 # methods if they so choose (FMT in {png, svg, jpg, pdf}).
291 291 raise NotImplementedError
292 292
293 293 def render_display_data(self, output):
294 294 """convert display data from the output of a code cell
295 295
296 296 Returns list.
297 297 """
298 298 for fmt in self.display_data_priority:
299 299 if fmt in output:
300 300 break
301 301 else:
302 302 for fmt in output:
303 303 if fmt != 'output_type':
304 304 break
305 305 else:
306 306 raise RuntimeError('no display data')
307 307
308 308 # Is it an image?
309 309 if fmt in ['png', 'svg', 'jpg', 'pdf']:
310 310 img_file = self._new_figure(output[fmt], fmt)
311 311 # Subclasses can have format-specific render functions (e.g.,
312 312 # latex has to auto-convert all SVG to PDF first).
313 313 lines_fun = getattr(self, '_%s_lines' % fmt, None)
314 314 if not lines_fun:
315 315 lines_fun = self._img_lines
316 316 lines = lines_fun(img_file)
317 317 else:
318 318 lines_fun = self.dispatch_display_format(fmt)
319 319 lines = lines_fun(output)
320 320
321 321 return lines
322 322
323 323 def render_raw(self, cell):
324 324 """convert a cell with raw text
325 325
326 326 Returns list."""
327 327 raise NotImplementedError
328 328
329 329 def render_unknown(self, cell):
330 330 """Render cells of unkown type
331 331
332 332 Returns list."""
333 333 data = pprint.pformat(cell)
334 334 logging.warning('Unknown cell: %s' % cell.cell_type)
335 335 return self._unknown_lines(data)
336 336
337 337 def render_unknown_display(self, output, type):
338 338 """Render cells of unkown type
339 339
340 340 Returns list."""
341 341 data = pprint.pformat(output)
342 342 logging.warning('Unknown output: %s' % output.output_type)
343 343 return self._unknown_lines(data)
344 344
345 345 def render_stream(self, output):
346 346 """render the stream part of an output
347 347
348 348 Returns list.
349 349
350 350 Identical to render_display_format_text
351 351 """
352 352 return self.render_display_format_text(output)
353 353
354 354 def render_pyout(self, output):
355 355 """convert pyout part of a code cell
356 356
357 357 Returns list."""
358 358 raise NotImplementedError
359 359
360 360 def render_pyerr(self, output):
361 361 """convert pyerr part of a code cell
362 362
363 363 Returns list."""
364 364 raise NotImplementedError
365 365
366 366 def _unknown_lines(self, data):
367 367 """Return list of lines for an unknown cell.
368 368
369 369 Parameters
370 370 ----------
371 371 data : str
372 372 The content of the unknown data as a single string.
373 373 """
374 374 raise NotImplementedError
375 375
376 376 # These are the possible format types in an output node
377 377
378 378 def render_display_format_text(self, output):
379 379 """render the text part of an output
380 380
381 381 Returns list.
382 382 """
383 383 raise NotImplementedError
384 384
385 385 def render_display_format_html(self, output):
386 386 """render the html part of an output
387 387
388 388 Returns list.
389 389 """
390 390 raise NotImplementedError
391 391
392 392 def render_display_format_latex(self, output):
393 393 """render the latex part of an output
394 394
395 395 Returns list.
396 396 """
397 397 raise NotImplementedError
398 398
399 399 def render_display_format_json(self, output):
400 400 """render the json part of an output
401 401
402 402 Returns list.
403 403 """
404 404 raise NotImplementedError
405 405
406 406 def render_display_format_javascript(self, output):
407 407 """render the javascript part of an output
408 408
409 409 Returns list.
410 410 """
411 411 raise NotImplementedError
@@ -1,46 +1,46 b''
1 1 """Notebook export in Blogger-aware HTML.
2 2
3 3 This file contains `ConverterBloggerHTML`, a subclass of `ConverterHTML` that
4 4 provides output suitable for easy pasting into a blog hosted on the Blogger
5 5 platform. See the class docstring for more information.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2012, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Stdlib imports
20 20 import io
21 21
22 22 # Our own imports
23 from converters.html import ConverterHTML
23 from .html import ConverterHTML
24 24
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Classes declarations
28 28 #-----------------------------------------------------------------------------
29 29
30 30 class ConverterBloggerHTML(ConverterHTML):
31 31 """Convert a notebook to html suitable for easy pasting into Blogger.
32 32
33 33 It generates an html file that has *only* the pure HTML contents, and a
34 34 separate file with `_header` appended to the name with all header contents.
35 35 Typically, the header file only needs to be used once when setting up a
36 36 blog, as the CSS for all posts is stored in a single location in Blogger.
37 37 """
38 38
39 39 def optional_header(self):
40 40 with io.open(self.outbase + '_header.html', 'w',
41 41 encoding=self.default_encoding) as f:
42 42 f.write('\n'.join(self.header_body()))
43 43 return []
44 44
45 45 def optional_footer(self):
46 46 return []
@@ -1,218 +1,218 b''
1 1 """Implements conversion to ordinary HTML output.
2 2
3 3 This file implements a class that handles rendering IPython notebooks as
4 4 HTML, suitable for posting to the web.
5 5
6 6 Converters for more specific HTML generation needs (suitable for posting to
7 7 a particular web service) can usefully subclass `ConverterHTML` and override
8 8 certain methods. For output tuned to the Blogger blogging platform, see the
9 9 `ConverterBloggerHTML` class.
10 10 """
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (c) 2012, the IPython Development Team.
13 13 #
14 14 # Distributed under the terms of the Modified BSD License.
15 15 #
16 16 # The full license is in the file COPYING.txt, distributed with this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from __future__ import absolute_import
20 20
21 21 # Stdlib imports
22 22 import io
23 23 import os
24 24
25 25 # Third-party imports
26 26 from markdown import markdown
27 27
28 28 # IPython imports
29 29 from IPython.utils import path
30 30
31 31 # Our own imports
32 from converters.base import Converter
33 from converters.utils import text_cell, output_container
34 from converters.utils import highlight, coalesce_streams, ansi2html
32 from .base import Converter
33 from .utils import text_cell, output_container
34 from .utils import highlight, coalesce_streams, ansi2html
35 35
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Class declarations
39 39 #-----------------------------------------------------------------------------
40 40
41 41 class ConverterHTML(Converter):
42 42 #-------------------------------------------------------------------------
43 43 # Class-level attributes determining the behaviour of the class but
44 44 # probably not varying from instance to instance.
45 45 #-------------------------------------------------------------------------
46 46 extension = 'html'
47 47 blank_symbol = ' '
48 48
49 49 def in_tag(self, tag, src, attrs=None):
50 50 """Return a list of elements bracketed by the given tag"""
51 51 attr_s = '' if attrs is None else \
52 52 ' '.join("%s=%s" % (attr, value)
53 53 for attr, value in attrs.iteritems())
54 54 return ['<%s %s>' % (tag, attr_s), src, '</%s>' % tag]
55 55
56 56 def _ansi_colored(self, text):
57 57 return ['<pre>%s</pre>' % ansi2html(text)]
58 58
59 59 def _stylesheet(self, fname):
60 60 with io.open(fname, encoding='utf-8') as f:
61 61 s = f.read()
62 62 return self.in_tag('style', s, dict(type='"text/css"'))
63 63
64 64 def _out_prompt(self, output):
65 65 if output.output_type == 'pyout':
66 66 content = 'Out[%s]:' % self._get_prompt_number(output)
67 67 else:
68 68 content = ''
69 69 return ['<div class="prompt output_prompt">%s</div>' % content]
70 70
71 71 def header_body(self):
72 72 """Return the body of the header as a list of strings."""
73 73
74 74 from pygments.formatters import HtmlFormatter
75 75
76 76 header = []
77 77 static = os.path.join(path.get_ipython_package_dir(),
78 78 'frontend', 'html', 'notebook', 'static',
79 79 )
80 80 here = os.path.split(os.path.realpath(__file__))[0]
81 81 css = os.path.join(static, 'css')
82 82 for sheet in [
83 83 # do we need jquery and prettify?
84 84 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
85 85 # 'jquery-ui.min.css'),
86 86 # os.path.join(static, 'prettify', 'prettify.css'),
87 87 os.path.join(css, 'boilerplate.css'),
88 88 os.path.join(css, 'fbm.css'),
89 89 os.path.join(css, 'notebook.css'),
90 90 os.path.join(css, 'renderedhtml.css'),
91 91 # our overrides:
92 92 os.path.join(here, '..', 'css', 'static_html.css'),
93 93 ]:
94 94 header.extend(self._stylesheet(sheet))
95 95
96 96 # pygments css
97 97 pygments_css = HtmlFormatter().get_style_defs('.highlight')
98 98 header.extend(['<meta charset="UTF-8">'])
99 99 header.extend(self.in_tag('style', pygments_css,
100 100 dict(type='"text/css"')))
101 101
102 102 # TODO: this should be allowed to use local mathjax:
103 103 header.extend(self.in_tag('script', '', {'type': '"text/javascript"',
104 104 'src': '"https://c328740.ssl.cf1.rackcdn.com/mathjax/'
105 105 'latest/MathJax.js?config=TeX-AMS_HTML"',
106 106 }))
107 107 with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
108 108 encoding='utf-8') as f:
109 109 header.extend(self.in_tag('script', f.read(),
110 110 {'type': '"text/javascript"'}))
111 111 return header
112 112
113 113 def optional_header(self):
114 114 return ['<html>', '<head>'] + self.header_body() + \
115 115 ['</head>', '<body>']
116 116
117 117 def optional_footer(self):
118 118 return ['</body>', '</html>']
119 119
120 120 @text_cell
121 121 def render_heading(self, cell):
122 122 marker = cell.level
123 123 return [u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
124 124
125 125 def render_code(self, cell):
126 126 if not cell.input:
127 127 return []
128 128
129 129 lines = ['<div class="cell border-box-sizing code_cell vbox">']
130 130
131 131 lines.append('<div class="input hbox">')
132 132 n = self._get_prompt_number(cell)
133 133 lines.append(
134 134 '<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n
135 135 )
136 136 lines.append('<div class="input_area box-flex1">')
137 137 lines.append(highlight(cell.input) if self.highlight_source
138 138 else cell.input)
139 139 lines.append('</div>') # input_area
140 140 lines.append('</div>') # input
141 141
142 142 if cell.outputs:
143 143 lines.append('<div class="vbox output_wrapper">')
144 144 lines.append('<div class="output vbox">')
145 145
146 146 for output in coalesce_streams(cell.outputs):
147 147 conv_fn = self.dispatch(output.output_type)
148 148 lines.extend(conv_fn(output))
149 149
150 150 lines.append('</div>') # output
151 151 lines.append('</div>') # output_wrapper
152 152
153 153 lines.append('</div>') # cell
154 154
155 155 return lines
156 156
157 157 @text_cell
158 158 def render_markdown(self, cell):
159 159 return [markdown(cell.source)]
160 160
161 161 def render_raw(self, cell):
162 162 if self.raw_as_verbatim:
163 163 return self.in_tag('pre', cell.source)
164 164 else:
165 165 return [cell.source]
166 166
167 167 @output_container
168 168 def render_pyout(self, output):
169 169 for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
170 170 if fmt in output:
171 171 conv_fn = self.dispatch_display_format(fmt)
172 172 return conv_fn(output)
173 173 return []
174 174
175 175 render_display_data = render_pyout
176 176
177 177 @output_container
178 178 def render_stream(self, output):
179 179 return self._ansi_colored(output.text)
180 180
181 181 @output_container
182 182 def render_pyerr(self, output):
183 183 # Note: a traceback is a *list* of frames.
184 184 # lines = []
185 185
186 186 # stb =
187 187 return self._ansi_colored('\n'.join(output.traceback))
188 188
189 189 def _img_lines(self, img_file):
190 190 return ['<img src="%s">' % img_file, '</img>']
191 191
192 192 def _unknown_lines(self, data):
193 193 return ['<h2>Warning:: Unknown cell</h2>'] + self.in_tag('pre', data)
194 194
195 195 def render_display_format_png(self, output):
196 196 return ['<img src="data:image/png;base64,%s"></img>' % output.png]
197 197
198 198 def render_display_format_svg(self, output):
199 199 return [output.svg]
200 200
201 201 def render_display_format_jpeg(self, output):
202 202 return ['<img src="data:image/jpeg;base64,%s"></img>' % output.jpeg]
203 203
204 204 def render_display_format_text(self, output):
205 205 return self._ansi_colored(output.text)
206 206
207 207 def render_display_format_html(self, output):
208 208 return [output.html]
209 209
210 210 def render_display_format_latex(self, output):
211 211 return [output.latex]
212 212
213 213 def render_display_format_json(self, output):
214 214 # html ignores json
215 215 return []
216 216
217 217 def render_display_format_javascript(self, output):
218 218 return [output.javascript]
@@ -1,231 +1,231 b''
1 1 """Notebook export to LaTeX.
2 2
3 3 This file implements a converter class for rendering IPython notebooks as
4 4 LaTeX, suitable for rendering by pdflatex.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012, the IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Stdlib imports
19 19 import os
20 20 import subprocess
21 21 import sys
22 22
23 23 # Our own imports
24 from converters.base import Converter
25 from converters.utils import markdown2latex, remove_ansi
24 from .base import Converter
25 from .utils import markdown2latex, remove_ansi
26 26
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Globals and constants
30 30 #-----------------------------------------------------------------------------
31 31
32 32 # XXX: This is a hack that needs to be addressed in a more principled fashion.
33 33 inkscape = 'inkscape'
34 34 if sys.platform == 'darwin':
35 35 inkscape = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
36 36 if not os.path.exists(inkscape):
37 37 inkscape = None
38 38
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Class declarations
42 42 #-----------------------------------------------------------------------------
43 43
44 44 class ConverterLaTeX(Converter):
45 45 """Converts a notebook to a .tex file suitable for pdflatex.
46 46
47 47 Note: this converter *needs*:
48 48
49 49 - `pandoc`: for all conversion of markdown cells. If your notebook only
50 50 has Raw cells, pandoc will not be needed.
51 51
52 52 - `inkscape`: if your notebook has SVG figures. These need to be
53 53 converted to PDF before inclusion in the TeX file, as LaTeX doesn't
54 54 understand SVG natively.
55 55
56 56 You will in general obtain much better final PDF results if you configure
57 57 the matplotlib backend to create SVG output with
58 58
59 59 %config InlineBackend.figure_format = 'svg'
60 60
61 61 (or set the equivalent flag at startup or in your configuration profile).
62 62 """
63 63 #-------------------------------------------------------------------------
64 64 # Class-level attributes determining the behaviour of the class but
65 65 # probably not varying from instance to instance.
66 66 #-------------------------------------------------------------------------
67 67 extension = 'tex'
68 68 # LaTeX specific class configuration.
69 69 inkscape = inkscape
70 70 documentclass = 'article'
71 71 documentclass_options = '11pt,english'
72 72 equation_env = 'equation*'
73 73 heading_map = {1: r'\section',
74 74 2: r'\subsection',
75 75 3: r'\subsubsection',
76 76 4: r'\paragraph',
77 77 5: r'\subparagraph',
78 78 6: r'\subparagraph'}
79 79 user_preamble = None
80 80 display_data_priority = ['latex', 'pdf', 'svg', 'png', 'jpg', 'text']
81 81
82 82 def in_env(self, environment, lines):
83 83 """Return list of environment lines for input lines
84 84
85 85 Parameters
86 86 ----------
87 87 env : string
88 88 Name of the environment to bracket with begin/end.
89 89
90 90 lines: """
91 91 out = [ur'\begin{%s}' % environment]
92 92 if isinstance(lines, basestring):
93 93 out.append(lines)
94 94 else: # list
95 95 out.extend(lines)
96 96 out.append(ur'\end{%s}' % environment)
97 97 return out
98 98
99 99 def convert(self, *args, **kwargs):
100 100 # The main body is done by the logic in the parent class, and that's
101 101 # all we need if preamble support has been turned off.
102 102 body = super(ConverterLaTeX, self).convert(*args, **kwargs)
103 103 if not self.with_preamble:
104 104 return body
105 105 # But if preamble is on, then we need to construct a proper, standalone
106 106 # tex file.
107 107
108 108 # Tag the document at the top and set latex class
109 109 final = [r'%% This file was auto-generated by IPython.',
110 110 r'%% Conversion from the original notebook file:',
111 111 r'%% {0}'.format(self.infile),
112 112 r'%%',
113 113 r'\documentclass[%s]{%s}' % (self.documentclass_options,
114 114 self.documentclass),
115 115 '',
116 116 ]
117 117 # Load our own preamble, which is stored next to the main file. We
118 118 # need to be careful in case the script entry point is a symlink
119 119 myfile = os.path.realpath(__file__)
120 120 preamble = '../preamble.tex'
121 121 with open(os.path.join(os.path.dirname(myfile), preamble)) as f:
122 122 final.append(f.read())
123 123
124 124 # Load any additional user-supplied preamble
125 125 if self.user_preamble:
126 126 final.extend(['', '%% Adding user preamble from file:',
127 127 '%% {0}'.format(self.user_preamble), ''])
128 128 with open(self.user_preamble) as f:
129 129 final.append(f.read())
130 130
131 131 # Include document body
132 132 final.extend([r'\begin{document}', '',
133 133 body,
134 134 r'\end{document}', ''])
135 135 # Return value must be a string
136 136 return '\n'.join(final)
137 137
138 138 def render_heading(self, cell):
139 139 marker = self.heading_map[cell.level]
140 140 return ['%s{%s}' % (marker, cell.source)]
141 141
142 142 def render_code(self, cell):
143 143 if not cell.input:
144 144 return []
145 145
146 146 # Cell codes first carry input code, we use lstlisting for that
147 147 lines = [ur'\begin{codecell}']
148 148
149 149 if 'source' not in self.exclude_cells:
150 150 lines.extend(self.in_env('codeinput',
151 151 self.in_env('lstlisting', cell.input)))
152 152 else:
153 153 # Empty output is still needed for LaTeX formatting
154 154 lines.extend(self.in_env('codeinput', ''))
155 155
156 156 outlines = []
157 157 if 'output' not in self.exclude_cells:
158 158 for output in cell.outputs:
159 159 conv_fn = self.dispatch(output.output_type)
160 160 outlines.extend(conv_fn(output))
161 161
162 162 # And then output of many possible types; use a frame for all of it.
163 163 if outlines:
164 164 lines.extend(self.in_env('codeoutput', outlines))
165 165
166 166 lines.append(ur'\end{codecell}')
167 167
168 168 return lines
169 169
170 170 def _img_lines(self, img_file):
171 171 rel_img_position = os.path.relpath(img_file, self.infile_dir)
172 172 return self.in_env('center',
173 173 [r'\includegraphics[width=0.7\textwidth]{%s}' % rel_img_position,
174 174 r'\par'])
175 175
176 176 def _svg_lines(self, img_file):
177 177 base_file = os.path.splitext(img_file)[0]
178 178 pdf_file = base_file + '.pdf'
179 179 subprocess.check_call([self.inkscape, '--export-pdf=%s' % pdf_file,
180 180 img_file])
181 181 return self._img_lines(pdf_file)
182 182
183 183 def render_markdown(self, cell):
184 184 return [markdown2latex(cell.source)]
185 185
186 186 def render_pyout(self, output):
187 187 lines = []
188 188
189 189 # output is a dictionary like object with type as a key
190 190 if 'latex' in output:
191 191 lines.extend(self.in_env(self.equation_env,
192 192 output.latex.lstrip('$$').rstrip('$$')))
193 193 #use text only if no latex representation is available
194 194 elif 'text' in output:
195 195 lines.extend(self.in_env('verbatim', output.text))
196 196
197 197 return lines
198 198
199 199 def render_pyerr(self, output):
200 200 # Note: a traceback is a *list* of frames.
201 201 return self.in_env('traceback',
202 202 self.in_env('verbatim',
203 203 remove_ansi('\n'.join(output.traceback))))
204 204
205 205 def render_raw(self, cell):
206 206 if self.raw_as_verbatim:
207 207 return self.in_env('verbatim', cell.source)
208 208 else:
209 209 return [cell.source]
210 210
211 211 def _unknown_lines(self, data):
212 212 return [r'{\vspace{5mm}\bf WARNING:: unknown cell:}'] + \
213 213 self.in_env('verbatim', data)
214 214
215 215 def render_display_format_text(self, output):
216 216 return self.in_env('verbatim', output.text.strip())
217 217
218 218 def render_display_format_html(self, output):
219 219 return []
220 220
221 221 def render_display_format_latex(self, output):
222 222 return self.in_env(self.equation_env,
223 223 output.latex.lstrip('$$').rstrip('$$'))
224 224
225 225 def render_display_format_json(self, output):
226 226 # latex ignores json
227 227 return []
228 228
229 229 def render_display_format_javascript(self, output):
230 230 # latex ignores javascript
231 231 return []
@@ -1,128 +1,128 b''
1 1 """Converter implementing Markdown export.
2 2
3 3 Implements a Converter that allows IPython notebooks to reasonably rendered
4 4 as a Markdown document.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012, the IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Our own imports
19 from converters.base import Converter
20 from converters.utils import highlight, remove_ansi
19 from .base import Converter
20 from .utils import highlight, remove_ansi
21 21 from IPython.utils.text import indent
22 22
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Class declarations
26 26 #-----------------------------------------------------------------------------
27 27 class ConverterMarkdown(Converter):
28 28 #-------------------------------------------------------------------------
29 29 # Class-level attributes determining the behaviour of the class but
30 30 # probably not varying from instance to instance.
31 31 #-------------------------------------------------------------------------
32 32 extension = 'md'
33 33 #-------------------------------------------------------------------------
34 34 # Instance-level attributes that are set in the constructor for this
35 35 # class.
36 36 #-------------------------------------------------------------------------
37 37 # show_prompts controls the display of In[} and Out[] prompts for code
38 38 # cells.
39 39 show_prompts = False
40 40 # If inline_prompt is False, display prompts on a separate line.
41 41 inline_prompt = False
42 42
43 43 def __init__(self, infile, highlight_source=True, show_prompts=False,
44 44 inline_prompt=False, **kw):
45 45 super(ConverterMarkdown, self).__init__(infile, **kw)
46 46 self.highlight_source = highlight_source
47 47 self.show_prompts = show_prompts
48 48 self.inline_prompt = inline_prompt
49 49
50 50 def render_heading(self, cell):
51 51 return ['{0} {1}'.format('#' * cell.level, cell.source), '']
52 52
53 53 def render_code(self, cell):
54 54 if not cell.input:
55 55 return []
56 56 lines = []
57 57 n = self._get_prompt_number(cell)
58 58 if self.show_prompts:
59 59 if not self.inline_prompt:
60 60 lines.extend(['*In[%s]:*' % n, ''])
61 61 else:
62 62 prompt = 'In[%s]: ' % n
63 63 input_lines = cell.input.split('\n')
64 64 src = (prompt + input_lines[0] + '\n' +
65 65 indent('\n'.join(input_lines[1:]), nspaces=len(prompt)))
66 66 else:
67 67 src = cell.input
68 68 src = highlight(src) if self.highlight_source else indent(src)
69 69 lines.extend([src, ''])
70 70 if cell.outputs and self.show_prompts and not self.inline_prompt:
71 71 lines.extend(['*Out[%s]:*' % n, ''])
72 72 for output in cell.outputs:
73 73 conv_fn = self.dispatch(output.output_type)
74 74 lines.extend(conv_fn(output))
75 75
76 76 #lines.append('----')
77 77 lines.append('')
78 78 return lines
79 79
80 80 def render_markdown(self, cell):
81 81 return [cell.source, '']
82 82
83 83 def render_raw(self, cell):
84 84 if self.raw_as_verbatim:
85 85 return [indent(cell.source), '']
86 86 else:
87 87 return [cell.source, '']
88 88
89 89 def render_pyout(self, output):
90 90 lines = []
91 91
92 92 ## if 'text' in output:
93 93 ## lines.extend(['*Out[%s]:*' % self._get_prompt_number(cell), ''])
94 94
95 95 # output is a dictionary like object with type as a key
96 96 if 'latex' in output:
97 97 pass
98 98
99 99 if 'text' in output:
100 100 lines.extend(['<pre>', indent(output.text), '</pre>'])
101 101
102 102 lines.append('')
103 103 return lines
104 104
105 105 def render_pyerr(self, output):
106 106 # Note: a traceback is a *list* of frames.
107 107 return [indent(remove_ansi('\n'.join(output.traceback))), '']
108 108
109 109 def _img_lines(self, img_file):
110 110 return ['', '![](%s)' % img_file, '']
111 111
112 112 def render_display_format_text(self, output):
113 113 return [indent(output.text)]
114 114
115 115 def _unknown_lines(self, data):
116 116 return ['Warning: Unknown cell', data]
117 117
118 118 def render_display_format_html(self, output):
119 119 return [output.html]
120 120
121 121 def render_display_format_latex(self, output):
122 122 return ['LaTeX::', indent(output.latex)]
123 123
124 124 def render_display_format_json(self, output):
125 125 return ['JSON:', indent(output.json)]
126 126
127 127 def render_display_format_javascript(self, output):
128 128 return ['JavaScript:', indent(output.javascript)]
@@ -1,107 +1,107 b''
1 1 """Base class for doing notebook-to-notebook transformations.
2 2
3 3 This implements a converter class that turns an IPython notebook into another
4 4 IPython notebook, mainly so that it can be subclassed to perform more useful
5 5 and sophisticated transformations.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2011, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Stdlib imports
20 20 import json
21 21 import os
22 22 from shutil import rmtree
23 23
24 24 # Our own imports
25 from converters.base import Converter
26 from converters.utils import cell_to_lines
25 from .base import Converter
26 from .utils import cell_to_lines
27 27
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Class declarations
31 31 #-----------------------------------------------------------------------------
32 32 class ConverterNotebook(Converter):
33 33 """
34 34 A converter that is essentially a null-op.
35 35 This exists so it can be subclassed
36 36 for custom handlers of .ipynb files
37 37 that create new .ipynb files.
38 38
39 39 What distinguishes this from JSONWriter is that
40 40 subclasses can specify what to do with each type of cell.
41 41
42 42 Writes out a notebook file.
43 43
44 44 """
45 45 extension = 'ipynb'
46 46
47 47 def __init__(self, infile, outbase, **kw):
48 48 Converter.__init__(self, infile, **kw)
49 49 self.outbase = outbase
50 50 rmtree(self.files_dir)
51 51
52 52 def convert(self):
53 53 return unicode(json.dumps(json.loads(Converter.convert(self, ',')),
54 54 indent=1, sort_keys=True))
55 55
56 56 def optional_header(self):
57 57 s = \
58 58 """{
59 59 "metadata": {
60 60 "name": "%(name)s"
61 61 },
62 62 "nbformat": 3,
63 63 "worksheets": [
64 64 {
65 65 "cells": [""" % {'name': os.path.basename(self.outbase)}
66 66 return s.split('\n')
67 67
68 68 def optional_footer(self):
69 69 s = \
70 70 """]
71 71 }
72 72 ]
73 73 }"""
74 74 return s.split('\n')
75 75
76 76 def render_heading(self, cell):
77 77 return cell_to_lines(cell)
78 78
79 79 def render_code(self, cell):
80 80 return cell_to_lines(cell)
81 81
82 82 def render_markdown(self, cell):
83 83 return cell_to_lines(cell)
84 84
85 85 def render_raw(self, cell):
86 86 return cell_to_lines(cell)
87 87
88 88 def render_pyout(self, output):
89 89 return cell_to_lines(output)
90 90
91 91 def render_pyerr(self, output):
92 92 return cell_to_lines(output)
93 93
94 94 def render_display_format_text(self, output):
95 95 return [output.text]
96 96
97 97 def render_display_format_html(self, output):
98 98 return [output.html]
99 99
100 100 def render_display_format_latex(self, output):
101 101 return [output.latex]
102 102
103 103 def render_display_format_json(self, output):
104 104 return [output.json]
105 105
106 106 def render_display_format_javascript(self, output):
107 107 return [output.javascript]
@@ -1,130 +1,130 b''
1 1 """Notebook export to .py source code files.
2 2
3 3 Since Python export is provided in the notebook itself (provided by classes
4 4 in `IPython.nbformat`), this class serves mainly as a base class for other
5 5 converters that may wish to implement cell-type-specific behaviors.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2012, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # IPython imports
20 20 from IPython.utils.text import indent
21 21
22 22 # Our own imports
23 from converters.base import Converter
24 from converters.utils import remove_ansi
23 from .base import Converter
24 from .utils import remove_ansi
25 25
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Class declarations
29 29 #-----------------------------------------------------------------------------
30 30 class ConverterPy(Converter):
31 31 """
32 32 A converter that takes a notebook and converts it to a .py file.
33 33
34 34 What distinguishes this from PyWriter and PyReader in IPython.nbformat is
35 35 that subclasses can specify what to do with each type of cell.
36 36 Additionally, unlike PyWriter, this does not preserve the '# <markdown>'
37 37 opening and closing comments style comments in favor of a cleaner looking
38 38 python program.
39 39
40 40 Note:
41 41 Even though this produces a .py file, it is not guaranteed to be valid
42 42 python file, since the notebook may be using magics and even cell
43 43 magics.
44 44 """
45 45 extension = 'py'
46 46
47 47 def __init__(self, infile, highlight_source=False, show_prompts=True,
48 48 show_output=True, **kw):
49 49 # Note that highlight_source is meaningless here, so even if it
50 50 # is passed as True we ignore it and propagate False to the
51 51 # superclass.
52 52 super(ConverterPy, self).__init__(infile,
53 53 highlight_source=False, **kw)
54 54 self.show_prompts = show_prompts
55 55 self.show_output = show_output
56 56
57 57 @staticmethod
58 58 def comment(input):
59 59 "returns every line in input as commented out"
60 60 return "# " + input.replace("\n", "\n# ")
61 61
62 62 def render_heading(self, cell):
63 63 return ['#{0} {1}'.format('#' * cell.level, cell.source), '']
64 64
65 65 def render_code(self, cell):
66 66 n = self._get_prompt_number(cell)
67 67 if not cell.input:
68 68 return []
69 69 lines = []
70 70 if self.show_prompts:
71 71 lines.extend(['# In[%s]:' % n])
72 72 src = cell.input
73 73 lines.extend([src, ''])
74 74 if self.show_output:
75 75 if cell.outputs:
76 76 lines.extend(['# Out[%s]:' % n])
77 77 for output in cell.outputs:
78 78 conv_fn = self.dispatch(output.output_type)
79 79 lines.extend(conv_fn(output))
80 80 return lines
81 81
82 82 def render_markdown(self, cell):
83 83 return [self.comment(cell.source), '']
84 84
85 85 def render_raw(self, cell):
86 86 if self.raw_as_verbatim:
87 87 return [self.comment(indent(cell.source)), '']
88 88 else:
89 89 return [self.comment(cell.source), '']
90 90
91 91 def render_pyout(self, output):
92 92 lines = []
93 93
94 94 ## if 'text' in output:
95 95 ## lines.extend(['*Out[%s]:*' % self._get_prompt_number(cell), ''])
96 96
97 97 # output is a dictionary like object with type as a key
98 98 if 'latex' in output:
99 99 pass
100 100
101 101 if 'text' in output:
102 102 lines.extend([self.comment(indent(output.text)), ''])
103 103
104 104 lines.append('')
105 105 return lines
106 106
107 107 def render_pyerr(self, output):
108 108 # Note: a traceback is a *list* of frames.
109 109 return [indent(remove_ansi('\n'.join(output.traceback))), '']
110 110
111 111 def _img_lines(self, img_file):
112 112 return [self.comment('image file: %s' % img_file), '']
113 113
114 114 def render_display_format_text(self, output):
115 115 return [self.comment(indent(output.text))]
116 116
117 117 def _unknown_lines(self, data):
118 118 return [self.comment('Warning: Unknown cell' + str(data))]
119 119
120 120 def render_display_format_html(self, output):
121 121 return [self.comment(output.html)]
122 122
123 123 def render_display_format_latex(self, output):
124 124 return []
125 125
126 126 def render_display_format_json(self, output):
127 127 return []
128 128
129 129 def render_display_format_javascript(self, output):
130 130 return []
@@ -1,100 +1,100 b''
1 1 """Notebook export to reStructuredText (rST).
2 2
3 3 This file provides a converter class for rendering IPython notebooks as valid
4 4 reStructuredText, suitable for inclusion in e.g. Sphinx documentation.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012, the IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # IPython imports
19 19 from IPython.utils.text import indent
20 20
21 21 # Our own imports
22 from converters.base import Converter
23 from converters.utils import markdown2rst, rst_directive, remove_ansi
22 from .base import Converter
23 from .utils import markdown2rst, rst_directive, remove_ansi
24 24
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Class declarations
28 28 #-----------------------------------------------------------------------------
29 29 class ConverterRST(Converter):
30 30 #-------------------------------------------------------------------------
31 31 # Class-level attributes determining the behaviour of the class but
32 32 # probably not varying from instance to instance.
33 33 #-------------------------------------------------------------------------
34 34 extension = 'rst'
35 35 heading_level = {1: '=', 2: '-', 3: '`', 4: '\'', 5: '.', 6: '~'}
36 36
37 37 def render_heading(self, cell):
38 38 marker = self.heading_level[cell.level]
39 39 return ['{0}\n{1}\n'.format(cell.source, marker * len(cell.source))]
40 40
41 41 def render_code(self, cell):
42 42 # Note: cell has type 'IPython.nbformat.v3.nbbase.NotebookNode'
43 43 if not cell.input:
44 44 return []
45 45
46 46 lines = ['In[%s]:' % self._get_prompt_number(cell), '']
47 47 lines.extend(rst_directive('.. code:: python', cell.input))
48 48
49 49 for output in cell.outputs:
50 50 conv_fn = self.dispatch(output.output_type)
51 51 lines.extend(conv_fn(output))
52 52
53 53 return lines
54 54
55 55 def render_markdown(self, cell):
56 56 #return [cell.source]
57 57 return [markdown2rst(cell.source)]
58 58
59 59 def render_raw(self, cell):
60 60 if self.raw_as_verbatim:
61 61 return ['::', '', indent(cell.source), '']
62 62 else:
63 63 return [cell.source]
64 64
65 65 def render_pyout(self, output):
66 66 lines = ['Out[%s]:' % self._get_prompt_number(output), '']
67 67
68 68 # output is a dictionary like object with type as a key
69 69 if 'latex' in output:
70 70 lines.extend(rst_directive('.. math::', output.latex))
71 71
72 72 if 'text' in output:
73 73 lines.extend(rst_directive('.. parsed-literal::', output.text))
74 74
75 75 return lines
76 76
77 77 def render_pyerr(self, output):
78 78 # Note: a traceback is a *list* of frames.
79 79 return ['::', '', indent(remove_ansi('\n'.join(output.traceback))), '']
80 80
81 81 def _img_lines(self, img_file):
82 82 return ['.. image:: %s' % img_file, '']
83 83
84 84 def render_display_format_text(self, output):
85 85 return rst_directive('.. parsed-literal::', output.text)
86 86
87 87 def _unknown_lines(self, data):
88 88 return rst_directive('.. warning:: Unknown cell') + [data]
89 89
90 90 def render_display_format_html(self, output):
91 91 return rst_directive('.. raw:: html', output.html)
92 92
93 93 def render_display_format_latex(self, output):
94 94 return rst_directive('.. math::', output.latex)
95 95
96 96 def render_display_format_json(self, output):
97 97 return rst_directive('.. raw:: json', output.json)
98 98
99 99 def render_display_format_javascript(self, output):
100 100 return rst_directive('.. raw:: javascript', output.javascript)
General Comments 0
You need to be logged in to leave comments. Login now