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