##// END OF EJS Templates
Replace ad-hoc/broken code with safe method to extract the prompt_number of a cell....
Maximilian Albert -
Show More
@@ -1,323 +1,328 b''
1 from __future__ import print_function, absolute_import
1 from __future__ import print_function, absolute_import
2 from converters.utils import remove_fake_files_url
2 from converters.utils import remove_fake_files_url
3
3
4 # Stdlib
4 # Stdlib
5 import codecs
5 import codecs
6 import io
6 import io
7 import logging
7 import logging
8 import os
8 import os
9 import pprint
9 import pprint
10 from types import FunctionType
10 from types import FunctionType
11
11
12 # From IPython
12 # From IPython
13 from IPython.nbformat import current as nbformat
13 from IPython.nbformat import current as nbformat
14
14
15 # local
15 # local
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Class declarations
18 # Class declarations
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 class ConversionException(Exception):
21 class ConversionException(Exception):
22 pass
22 pass
23
23
24 class DocStringInheritor(type):
24 class DocStringInheritor(type):
25 """
25 """
26 This metaclass will walk the list of bases until the desired
26 This metaclass will walk the list of bases until the desired
27 superclass method is found AND if that method has a docstring and only
27 superclass method is found AND if that method has a docstring and only
28 THEN does it attach the superdocstring to the derived class method.
28 THEN does it attach the superdocstring to the derived class method.
29
29
30 Please use carefully, I just did the metaclass thing by following
30 Please use carefully, I just did the metaclass thing by following
31 Michael Foord's Metaclass tutorial
31 Michael Foord's Metaclass tutorial
32 (http://www.voidspace.org.uk/python/articles/metaclasses.shtml), I may
32 (http://www.voidspace.org.uk/python/articles/metaclasses.shtml), I may
33 have missed a step or two.
33 have missed a step or two.
34
34
35 source:
35 source:
36 http://groups.google.com/group/comp.lang.python/msg/26f7b4fcb4d66c95
36 http://groups.google.com/group/comp.lang.python/msg/26f7b4fcb4d66c95
37 by Paul McGuire
37 by Paul McGuire
38 """
38 """
39 def __new__(meta, classname, bases, classDict):
39 def __new__(meta, classname, bases, classDict):
40 newClassDict = {}
40 newClassDict = {}
41 for attributeName, attribute in classDict.items():
41 for attributeName, attribute in classDict.items():
42 if type(attribute) == FunctionType:
42 if type(attribute) == FunctionType:
43 # look through bases for matching function by name
43 # look through bases for matching function by name
44 for baseclass in bases:
44 for baseclass in bases:
45 if hasattr(baseclass, attributeName):
45 if hasattr(baseclass, attributeName):
46 basefn = getattr(baseclass, attributeName)
46 basefn = getattr(baseclass, attributeName)
47 if basefn.__doc__:
47 if basefn.__doc__:
48 attribute.__doc__ = basefn.__doc__
48 attribute.__doc__ = basefn.__doc__
49 break
49 break
50 newClassDict[attributeName] = attribute
50 newClassDict[attributeName] = attribute
51 return type.__new__(meta, classname, bases, newClassDict)
51 return type.__new__(meta, classname, bases, newClassDict)
52
52
53 class Converter(object):
53 class Converter(object):
54 __metaclass__ = DocStringInheritor
54 __metaclass__ = DocStringInheritor
55 default_encoding = 'utf-8'
55 default_encoding = 'utf-8'
56 extension = str()
56 extension = str()
57 figures_counter = 0
57 figures_counter = 0
58 infile = str()
58 infile = str()
59 infile_dir = str()
59 infile_dir = str()
60 infile_root = str()
60 infile_root = str()
61 files_dir = str()
61 files_dir = str()
62 with_preamble = True
62 with_preamble = True
63 user_preamble = None
63 user_preamble = None
64 output = unicode()
64 output = unicode()
65 raw_as_verbatim = False
65 raw_as_verbatim = False
66 blank_symbol = " "
66
67
67 def __init__(self, infile):
68 def __init__(self, infile):
68 self.infile = infile
69 self.infile = infile
69 self.infile_dir, infile_root = os.path.split(infile)
70 self.infile_dir, infile_root = os.path.split(infile)
70 infile_root = os.path.splitext(infile_root)[0]
71 infile_root = os.path.splitext(infile_root)[0]
71 files_dir = os.path.join(self.infile_dir, infile_root + '_files')
72 files_dir = os.path.join(self.infile_dir, infile_root + '_files')
72 if not os.path.isdir(files_dir):
73 if not os.path.isdir(files_dir):
73 os.mkdir(files_dir)
74 os.mkdir(files_dir)
74 self.infile_root = infile_root
75 self.infile_root = infile_root
75 self.files_dir = files_dir
76 self.files_dir = files_dir
76 self.outbase = os.path.join(self.infile_dir, infile_root)
77 self.outbase = os.path.join(self.infile_dir, infile_root)
77
78
78 def __del__(self):
79 def __del__(self):
79 if os.path.isdir(self.files_dir) and not os.listdir(self.files_dir):
80 if os.path.isdir(self.files_dir) and not os.listdir(self.files_dir):
80 os.rmdir(self.files_dir)
81 os.rmdir(self.files_dir)
81
82
83 def _get_prompt_number(self, cell):
84 return cell.prompt_number if hasattr(cell, 'prompt_number') \
85 else self.blank_symbol
86
82 def dispatch(self, cell_type):
87 def dispatch(self, cell_type):
83 """return cell_type dependent render method, for example render_code
88 """return cell_type dependent render method, for example render_code
84 """
89 """
85 return getattr(self, 'render_' + cell_type, self.render_unknown)
90 return getattr(self, 'render_' + cell_type, self.render_unknown)
86
91
87 def dispatch_display_format(self, format):
92 def dispatch_display_format(self, format):
88 """return output_type dependent render method, for example render_output_text
93 """return output_type dependent render method, for example render_output_text
89 """
94 """
90 return getattr(self, 'render_display_format_' + format, self.render_unknown_display)
95 return getattr(self, 'render_display_format_' + format, self.render_unknown_display)
91
96
92 def convert(self, cell_separator='\n'):
97 def convert(self, cell_separator='\n'):
93 """
98 """
94 Generic method to converts notebook to a string representation.
99 Generic method to converts notebook to a string representation.
95
100
96 This is accomplished by dispatching on the cell_type, so subclasses of
101 This is accomplished by dispatching on the cell_type, so subclasses of
97 Convereter class do not need to re-implement this method, but just
102 Convereter class do not need to re-implement this method, but just
98 need implementation for the methods that will be dispatched.
103 need implementation for the methods that will be dispatched.
99
104
100 Parameters
105 Parameters
101 ----------
106 ----------
102 cell_separator : string
107 cell_separator : string
103 Character or string to join cells with. Default is "\n"
108 Character or string to join cells with. Default is "\n"
104
109
105 Returns
110 Returns
106 -------
111 -------
107 out : string
112 out : string
108 """
113 """
109 lines = []
114 lines = []
110 lines.extend(self.optional_header())
115 lines.extend(self.optional_header())
111 lines.extend(self.main_body(cell_separator))
116 lines.extend(self.main_body(cell_separator))
112 lines.extend(self.optional_footer())
117 lines.extend(self.optional_footer())
113 return u'\n'.join(lines)
118 return u'\n'.join(lines)
114
119
115 def main_body(self, cell_separator='\n'):
120 def main_body(self, cell_separator='\n'):
116 converted_cells = []
121 converted_cells = []
117 for worksheet in self.nb.worksheets:
122 for worksheet in self.nb.worksheets:
118 for cell in worksheet.cells:
123 for cell in worksheet.cells:
119 #print(cell.cell_type) # dbg
124 #print(cell.cell_type) # dbg
120 conv_fn = self.dispatch(cell.cell_type)
125 conv_fn = self.dispatch(cell.cell_type)
121 if cell.cell_type in ('markdown', 'raw'):
126 if cell.cell_type in ('markdown', 'raw'):
122 remove_fake_files_url(cell)
127 remove_fake_files_url(cell)
123 converted_cells.append('\n'.join(conv_fn(cell)))
128 converted_cells.append('\n'.join(conv_fn(cell)))
124 cell_lines = cell_separator.join(converted_cells).split('\n')
129 cell_lines = cell_separator.join(converted_cells).split('\n')
125 return cell_lines
130 return cell_lines
126
131
127 def render(self):
132 def render(self):
128 "read, convert, and save self.infile"
133 "read, convert, and save self.infile"
129 if not hasattr(self, 'nb'):
134 if not hasattr(self, 'nb'):
130 self.read()
135 self.read()
131 self.output = self.convert()
136 self.output = self.convert()
132 assert(type(self.output) == unicode)
137 assert(type(self.output) == unicode)
133 return self.save()
138 return self.save()
134
139
135 def read(self):
140 def read(self):
136 "read and parse notebook into NotebookNode called self.nb"
141 "read and parse notebook into NotebookNode called self.nb"
137 with open(self.infile) as f:
142 with open(self.infile) as f:
138 self.nb = nbformat.read(f, 'json')
143 self.nb = nbformat.read(f, 'json')
139
144
140 def save(self, outfile=None, encoding=None):
145 def save(self, outfile=None, encoding=None):
141 "read and parse notebook into self.nb"
146 "read and parse notebook into self.nb"
142 if outfile is None:
147 if outfile is None:
143 outfile = self.outbase + '.' + self.extension
148 outfile = self.outbase + '.' + self.extension
144 if encoding is None:
149 if encoding is None:
145 encoding = self.default_encoding
150 encoding = self.default_encoding
146 with io.open(outfile, 'w', encoding=encoding) as f:
151 with io.open(outfile, 'w', encoding=encoding) as f:
147 f.write(self.output)
152 f.write(self.output)
148 return os.path.abspath(outfile)
153 return os.path.abspath(outfile)
149
154
150 def optional_header(self):
155 def optional_header(self):
151 """
156 """
152 Optional header to insert at the top of the converted notebook
157 Optional header to insert at the top of the converted notebook
153
158
154 Returns a list
159 Returns a list
155 """
160 """
156 return []
161 return []
157
162
158 def optional_footer(self):
163 def optional_footer(self):
159 """
164 """
160 Optional footer to insert at the end of the converted notebook
165 Optional footer to insert at the end of the converted notebook
161
166
162 Returns a list
167 Returns a list
163 """
168 """
164 return []
169 return []
165
170
166 def _new_figure(self, data, fmt):
171 def _new_figure(self, data, fmt):
167 """Create a new figure file in the given format.
172 """Create a new figure file in the given format.
168
173
169 Returns a path relative to the input file.
174 Returns a path relative to the input file.
170 """
175 """
171 figname = '%s_fig_%02i.%s' % (self.infile_root,
176 figname = '%s_fig_%02i.%s' % (self.infile_root,
172 self.figures_counter, fmt)
177 self.figures_counter, fmt)
173 self.figures_counter += 1
178 self.figures_counter += 1
174 fullname = os.path.join(self.files_dir, figname)
179 fullname = os.path.join(self.files_dir, figname)
175
180
176 # Binary files are base64-encoded, SVG is already XML
181 # Binary files are base64-encoded, SVG is already XML
177 if fmt in ('png', 'jpg', 'pdf'):
182 if fmt in ('png', 'jpg', 'pdf'):
178 data = data.decode('base64')
183 data = data.decode('base64')
179 fopen = lambda fname: open(fname, 'wb')
184 fopen = lambda fname: open(fname, 'wb')
180 else:
185 else:
181 fopen = lambda fname: codecs.open(fname, 'wb', self.default_encoding)
186 fopen = lambda fname: codecs.open(fname, 'wb', self.default_encoding)
182
187
183 with fopen(fullname) as f:
188 with fopen(fullname) as f:
184 f.write(data)
189 f.write(data)
185
190
186 return fullname
191 return fullname
187
192
188 def render_heading(self, cell):
193 def render_heading(self, cell):
189 """convert a heading cell
194 """convert a heading cell
190
195
191 Returns list."""
196 Returns list."""
192 raise NotImplementedError
197 raise NotImplementedError
193
198
194 def render_code(self, cell):
199 def render_code(self, cell):
195 """Convert a code cell
200 """Convert a code cell
196
201
197 Returns list."""
202 Returns list."""
198 raise NotImplementedError
203 raise NotImplementedError
199
204
200 def render_markdown(self, cell):
205 def render_markdown(self, cell):
201 """convert a markdown cell
206 """convert a markdown cell
202
207
203 Returns list."""
208 Returns list."""
204 raise NotImplementedError
209 raise NotImplementedError
205
210
206 def _img_lines(self, img_file):
211 def _img_lines(self, img_file):
207 """Return list of lines to include an image file."""
212 """Return list of lines to include an image file."""
208 # Note: subclasses may choose to implement format-specific _FMT_lines
213 # Note: subclasses may choose to implement format-specific _FMT_lines
209 # methods if they so choose (FMT in {png, svg, jpg, pdf}).
214 # methods if they so choose (FMT in {png, svg, jpg, pdf}).
210 raise NotImplementedError
215 raise NotImplementedError
211
216
212 def render_display_data(self, output):
217 def render_display_data(self, output):
213 """convert display data from the output of a code cell
218 """convert display data from the output of a code cell
214
219
215 Returns list.
220 Returns list.
216 """
221 """
217 lines = []
222 lines = []
218
223
219 for fmt in output.keys():
224 for fmt in output.keys():
220 if fmt in ['png', 'svg', 'jpg', 'pdf']:
225 if fmt in ['png', 'svg', 'jpg', 'pdf']:
221 img_file = self._new_figure(output[fmt], fmt)
226 img_file = self._new_figure(output[fmt], fmt)
222 # Subclasses can have format-specific render functions (e.g.,
227 # Subclasses can have format-specific render functions (e.g.,
223 # latex has to auto-convert all SVG to PDF first).
228 # latex has to auto-convert all SVG to PDF first).
224 lines_fun = getattr(self, '_%s_lines' % fmt, None)
229 lines_fun = getattr(self, '_%s_lines' % fmt, None)
225 if not lines_fun:
230 if not lines_fun:
226 lines_fun = self._img_lines
231 lines_fun = self._img_lines
227 lines.extend(lines_fun(img_file))
232 lines.extend(lines_fun(img_file))
228 elif fmt != 'output_type':
233 elif fmt != 'output_type':
229 conv_fn = self.dispatch_display_format(fmt)
234 conv_fn = self.dispatch_display_format(fmt)
230 lines.extend(conv_fn(output))
235 lines.extend(conv_fn(output))
231 return lines
236 return lines
232
237
233 def render_raw(self, cell):
238 def render_raw(self, cell):
234 """convert a cell with raw text
239 """convert a cell with raw text
235
240
236 Returns list."""
241 Returns list."""
237 raise NotImplementedError
242 raise NotImplementedError
238
243
239 def render_unknown(self, cell):
244 def render_unknown(self, cell):
240 """Render cells of unkown type
245 """Render cells of unkown type
241
246
242 Returns list."""
247 Returns list."""
243 data = pprint.pformat(cell)
248 data = pprint.pformat(cell)
244 logging.warning('Unknown cell: %s' % cell.cell_type)
249 logging.warning('Unknown cell: %s' % cell.cell_type)
245 return self._unknown_lines(data)
250 return self._unknown_lines(data)
246
251
247 def render_unknown_display(self, output, type):
252 def render_unknown_display(self, output, type):
248 """Render cells of unkown type
253 """Render cells of unkown type
249
254
250 Returns list."""
255 Returns list."""
251 data = pprint.pformat(output)
256 data = pprint.pformat(output)
252 logging.warning('Unknown output: %s' % output.output_type)
257 logging.warning('Unknown output: %s' % output.output_type)
253 return self._unknown_lines(data)
258 return self._unknown_lines(data)
254
259
255 def render_stream(self, output):
260 def render_stream(self, output):
256 """render the stream part of an output
261 """render the stream part of an output
257
262
258 Returns list.
263 Returns list.
259
264
260 Identical to render_display_format_text
265 Identical to render_display_format_text
261 """
266 """
262 return self.render_display_format_text(output)
267 return self.render_display_format_text(output)
263
268
264 def render_pyout(self, output):
269 def render_pyout(self, output):
265 """convert pyout part of a code cell
270 """convert pyout part of a code cell
266
271
267 Returns list."""
272 Returns list."""
268 raise NotImplementedError
273 raise NotImplementedError
269
274
270
275
271 def render_pyerr(self, output):
276 def render_pyerr(self, output):
272 """convert pyerr part of a code cell
277 """convert pyerr part of a code cell
273
278
274 Returns list."""
279 Returns list."""
275 raise NotImplementedError
280 raise NotImplementedError
276
281
277 def _unknown_lines(self, data):
282 def _unknown_lines(self, data):
278 """Return list of lines for an unknown cell.
283 """Return list of lines for an unknown cell.
279
284
280 Parameters
285 Parameters
281 ----------
286 ----------
282 data : str
287 data : str
283 The content of the unknown data as a single string.
288 The content of the unknown data as a single string.
284 """
289 """
285 raise NotImplementedError
290 raise NotImplementedError
286
291
287 # These are the possible format types in an output node
292 # These are the possible format types in an output node
288
293
289 def render_display_format_text(self, output):
294 def render_display_format_text(self, output):
290 """render the text part of an output
295 """render the text part of an output
291
296
292 Returns list.
297 Returns list.
293 """
298 """
294 raise NotImplementedError
299 raise NotImplementedError
295
300
296 def render_display_format_html(self, output):
301 def render_display_format_html(self, output):
297 """render the html part of an output
302 """render the html part of an output
298
303
299 Returns list.
304 Returns list.
300 """
305 """
301 raise NotImplementedError
306 raise NotImplementedError
302
307
303 def render_display_format_latex(self, output):
308 def render_display_format_latex(self, output):
304 """render the latex part of an output
309 """render the latex part of an output
305
310
306 Returns list.
311 Returns list.
307 """
312 """
308 raise NotImplementedError
313 raise NotImplementedError
309
314
310 def render_display_format_json(self, output):
315 def render_display_format_json(self, output):
311 """render the json part of an output
316 """render the json part of an output
312
317
313 Returns list.
318 Returns list.
314 """
319 """
315 raise NotImplementedError
320 raise NotImplementedError
316
321
317 def render_display_format_javascript(self, output):
322 def render_display_format_javascript(self, output):
318 """render the javascript part of an output
323 """render the javascript part of an output
319
324
320 Returns list.
325 Returns list.
321 """
326 """
322 raise NotImplementedError
327 raise NotImplementedError
323
328
@@ -1,183 +1,183 b''
1 from __future__ import absolute_import
1 from __future__ import absolute_import
2
2
3 from converters.base import Converter
3 from converters.base import Converter
4 from converters.utils import text_cell, output_container
4 from converters.utils import text_cell, output_container
5 from converters.utils import highlight, coalesce_streams, ansi2html
5 from converters.utils import highlight, coalesce_streams, ansi2html
6
6
7 from IPython.utils import path
7 from IPython.utils import path
8 from markdown import markdown
8 from markdown import markdown
9 import os
9 import os
10 import io
10 import io
11
11
12 class ConverterHTML(Converter):
12 class ConverterHTML(Converter):
13 extension = 'html'
13 extension = 'html'
14 blank_symbol = ' '
14
15
15 def in_tag(self, tag, src, attrs=None):
16 def in_tag(self, tag, src, attrs=None):
16 """Return a list of elements bracketed by the given tag"""
17 """Return a list of elements bracketed by the given tag"""
17 attr_s = '' if attrs is None else \
18 attr_s = '' if attrs is None else \
18 ' '.join( "%s=%s" % (attr, value)
19 ' '.join( "%s=%s" % (attr, value)
19 for attr, value in attrs.iteritems() )
20 for attr, value in attrs.iteritems() )
20 return ['<%s %s>' % (tag, attr_s), src, '</%s>' % tag]
21 return ['<%s %s>' % (tag, attr_s), src, '</%s>' % tag]
21
22
22 def _ansi_colored(self, text):
23 def _ansi_colored(self, text):
23 return ['<pre>%s</pre>' % ansi2html(text)]
24 return ['<pre>%s</pre>' % ansi2html(text)]
24
25
25 def _stylesheet(self, fname):
26 def _stylesheet(self, fname):
26 with io.open(fname, encoding='utf-8') as f:
27 with io.open(fname, encoding='utf-8') as f:
27 s = f.read()
28 s = f.read()
28 return self.in_tag('style', s, dict(type='"text/css"'))
29 return self.in_tag('style', s, dict(type='"text/css"'))
29
30
30 def _out_prompt(self, output):
31 def _out_prompt(self, output):
31 if output.output_type == 'pyout':
32 if output.output_type == 'pyout':
32 n = output.prompt_number if output.prompt_number is not None else '&nbsp;'
33 content = 'Out[%s]:' % self._get_prompt_number(output)
33 content = 'Out[%s]:' % n
34 else:
34 else:
35 content = ''
35 content = ''
36 return ['<div class="prompt output_prompt">%s</div>' % content]
36 return ['<div class="prompt output_prompt">%s</div>' % content]
37
37
38 def header_body(self):
38 def header_body(self):
39 """Return the body of the header as a list of strings."""
39 """Return the body of the header as a list of strings."""
40
40
41 from pygments.formatters import HtmlFormatter
41 from pygments.formatters import HtmlFormatter
42
42
43 header = []
43 header = []
44 static = os.path.join(path.get_ipython_package_dir(),
44 static = os.path.join(path.get_ipython_package_dir(),
45 'frontend', 'html', 'notebook', 'static',
45 'frontend', 'html', 'notebook', 'static',
46 )
46 )
47 here = os.path.split(os.path.realpath(__file__))[0]
47 here = os.path.split(os.path.realpath(__file__))[0]
48 css = os.path.join(static, 'css')
48 css = os.path.join(static, 'css')
49 for sheet in [
49 for sheet in [
50 # do we need jquery and prettify?
50 # do we need jquery and prettify?
51 # os.path.join(static, 'jquery', 'css', 'themes', 'base', 'jquery-ui.min.css'),
51 # os.path.join(static, 'jquery', 'css', 'themes', 'base', 'jquery-ui.min.css'),
52 # os.path.join(static, 'prettify', 'prettify.css'),
52 # os.path.join(static, 'prettify', 'prettify.css'),
53 os.path.join(css, 'boilerplate.css'),
53 os.path.join(css, 'boilerplate.css'),
54 os.path.join(css, 'fbm.css'),
54 os.path.join(css, 'fbm.css'),
55 os.path.join(css, 'notebook.css'),
55 os.path.join(css, 'notebook.css'),
56 os.path.join(css, 'renderedhtml.css'),
56 os.path.join(css, 'renderedhtml.css'),
57 # our overrides:
57 # our overrides:
58 os.path.join(here, '..','css', 'static_html.css'),
58 os.path.join(here, '..','css', 'static_html.css'),
59 ]:
59 ]:
60 header.extend(self._stylesheet(sheet))
60 header.extend(self._stylesheet(sheet))
61
61
62 # pygments css
62 # pygments css
63 pygments_css = HtmlFormatter().get_style_defs('.highlight')
63 pygments_css = HtmlFormatter().get_style_defs('.highlight')
64 header.extend(['<meta charset="UTF-8">'])
64 header.extend(['<meta charset="UTF-8">'])
65 header.extend(self.in_tag('style', pygments_css, dict(type='"text/css"')))
65 header.extend(self.in_tag('style', pygments_css, dict(type='"text/css"')))
66
66
67 # TODO: this should be allowed to use local mathjax:
67 # TODO: this should be allowed to use local mathjax:
68 header.extend(self.in_tag('script', '', {'type':'"text/javascript"',
68 header.extend(self.in_tag('script', '', {'type':'"text/javascript"',
69 'src': '"https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"',
69 'src': '"https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"',
70 }))
70 }))
71 with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
71 with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
72 encoding='utf-8') as f:
72 encoding='utf-8') as f:
73 header.extend(self.in_tag('script', f.read(),
73 header.extend(self.in_tag('script', f.read(),
74 {'type': '"text/javascript"'}))
74 {'type': '"text/javascript"'}))
75 return header
75 return header
76
76
77 def optional_header(self):
77 def optional_header(self):
78 return ['<html>', '<head>'] + self.header_body() + \
78 return ['<html>', '<head>'] + self.header_body() + \
79 ['</head>', '<body>']
79 ['</head>', '<body>']
80
80
81 def optional_footer(self):
81 def optional_footer(self):
82 return ['</body>', '</html>']
82 return ['</body>', '</html>']
83
83
84 @text_cell
84 @text_cell
85 def render_heading(self, cell):
85 def render_heading(self, cell):
86 marker = cell.level
86 marker = cell.level
87 return [u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
87 return [u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
88
88
89 def render_code(self, cell):
89 def render_code(self, cell):
90 if not cell.input:
90 if not cell.input:
91 return []
91 return []
92
92
93 lines = ['<div class="cell border-box-sizing code_cell vbox">']
93 lines = ['<div class="cell border-box-sizing code_cell vbox">']
94
94
95 lines.append('<div class="input hbox">')
95 lines.append('<div class="input hbox">')
96 n = cell.prompt_number if getattr(cell, 'prompt_number', None) is not None else '&nbsp;'
96 n = self._get_prompt_number(cell)
97 lines.append('<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n)
97 lines.append('<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n)
98 lines.append('<div class="input_area box-flex1">')
98 lines.append('<div class="input_area box-flex1">')
99 lines.append(highlight(cell.input))
99 lines.append(highlight(cell.input))
100 lines.append('</div>') # input_area
100 lines.append('</div>') # input_area
101 lines.append('</div>') # input
101 lines.append('</div>') # input
102
102
103 if cell.outputs:
103 if cell.outputs:
104 lines.append('<div class="vbox output_wrapper">')
104 lines.append('<div class="vbox output_wrapper">')
105 lines.append('<div class="output vbox">')
105 lines.append('<div class="output vbox">')
106
106
107 for output in coalesce_streams(cell.outputs):
107 for output in coalesce_streams(cell.outputs):
108 conv_fn = self.dispatch(output.output_type)
108 conv_fn = self.dispatch(output.output_type)
109 lines.extend(conv_fn(output))
109 lines.extend(conv_fn(output))
110
110
111 lines.append('</div>') # output
111 lines.append('</div>') # output
112 lines.append('</div>') # output_wrapper
112 lines.append('</div>') # output_wrapper
113
113
114 lines.append('</div>') # cell
114 lines.append('</div>') # cell
115
115
116 return lines
116 return lines
117
117
118 @text_cell
118 @text_cell
119 def render_markdown(self, cell):
119 def render_markdown(self, cell):
120 return [markdown(cell.source)]
120 return [markdown(cell.source)]
121
121
122 def render_raw(self, cell):
122 def render_raw(self, cell):
123 if self.raw_as_verbatim:
123 if self.raw_as_verbatim:
124 return self.in_tag('pre', cell.source)
124 return self.in_tag('pre', cell.source)
125 else:
125 else:
126 return [cell.source]
126 return [cell.source]
127
127
128 @output_container
128 @output_container
129 def render_pyout(self, output):
129 def render_pyout(self, output):
130 for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
130 for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
131 if fmt in output:
131 if fmt in output:
132 conv_fn = self.dispatch_display_format(fmt)
132 conv_fn = self.dispatch_display_format(fmt)
133 return conv_fn(output)
133 return conv_fn(output)
134 return []
134 return []
135
135
136 render_display_data = render_pyout
136 render_display_data = render_pyout
137
137
138 @output_container
138 @output_container
139 def render_stream(self, output):
139 def render_stream(self, output):
140 return self._ansi_colored(output.text)
140 return self._ansi_colored(output.text)
141
141
142
142
143 @output_container
143 @output_container
144 def render_pyerr(self, output):
144 def render_pyerr(self, output):
145 # Note: a traceback is a *list* of frames.
145 # Note: a traceback is a *list* of frames.
146 # lines = []
146 # lines = []
147
147
148 # stb =
148 # stb =
149 return self._ansi_colored('\n'.join(output.traceback))
149 return self._ansi_colored('\n'.join(output.traceback))
150
150
151 def _img_lines(self, img_file):
151 def _img_lines(self, img_file):
152 return ['<img src="%s">' % img_file, '</img>']
152 return ['<img src="%s">' % img_file, '</img>']
153
153
154 def _unknown_lines(self, data):
154 def _unknown_lines(self, data):
155 return ['<h2>Warning:: Unknown cell</h2>'] + self.in_tag('pre', data)
155 return ['<h2>Warning:: Unknown cell</h2>'] + self.in_tag('pre', data)
156
156
157
157
158 def render_display_format_png(self, output):
158 def render_display_format_png(self, output):
159 return ['<img src="data:image/png;base64,%s"></img>' % output.png]
159 return ['<img src="data:image/png;base64,%s"></img>' % output.png]
160
160
161 def render_display_format_svg(self, output):
161 def render_display_format_svg(self, output):
162 return [output.svg]
162 return [output.svg]
163
163
164 def render_display_format_jpeg(self, output):
164 def render_display_format_jpeg(self, output):
165 return ['<img src="data:image/jpeg;base64,%s"></img>' % output.jpeg]
165 return ['<img src="data:image/jpeg;base64,%s"></img>' % output.jpeg]
166
166
167 def render_display_format_text(self, output):
167 def render_display_format_text(self, output):
168 return self._ansi_colored(output.text)
168 return self._ansi_colored(output.text)
169
169
170 def render_display_format_html(self, output):
170 def render_display_format_html(self, output):
171 return [output.html]
171 return [output.html]
172
172
173 def render_display_format_latex(self, output):
173 def render_display_format_latex(self, output):
174 return [output.latex]
174 return [output.latex]
175
175
176 def render_display_format_json(self, output):
176 def render_display_format_json(self, output):
177 # html ignores json
177 # html ignores json
178 return []
178 return []
179
179
180
180
181 def render_display_format_javascript(self, output):
181 def render_display_format_javascript(self, output):
182 return [output.javascript]
182 return [output.javascript]
183
183
@@ -1,90 +1,91 b''
1 from converters.base import Converter
1 from converters.base import Converter
2 from converters.utils import highlight, remove_ansi
2 from converters.utils import highlight, remove_ansi
3 from IPython.utils.text import indent
3 from IPython.utils.text import indent
4
4
5 class ConverterMarkdown(Converter):
5 class ConverterMarkdown(Converter):
6 extension = 'md'
6 extension = 'md'
7
7
8 def __init__(self, infile, highlight_source=True, show_prompts=False,
8 def __init__(self, infile, highlight_source=True, show_prompts=False,
9 inline_prompt=False):
9 inline_prompt=False):
10 super(ConverterMarkdown, self).__init__(infile)
10 super(ConverterMarkdown, self).__init__(infile)
11 self.highlight_source = highlight_source
11 self.highlight_source = highlight_source
12 self.show_prompts = show_prompts
12 self.show_prompts = show_prompts
13 self.inline_prompt = inline_prompt
13 self.inline_prompt = inline_prompt
14
14
15 def render_heading(self, cell):
15 def render_heading(self, cell):
16 return ['{0} {1}'.format('#'*cell.level, cell.source), '']
16 return ['{0} {1}'.format('#'*cell.level, cell.source), '']
17
17
18 def render_code(self, cell):
18 def render_code(self, cell):
19 if not cell.input:
19 if not cell.input:
20 return []
20 return []
21 lines = []
21 lines = []
22 n = self._get_prompt_number(cell)
22 if self.show_prompts and not self.inline_prompt:
23 if self.show_prompts and not self.inline_prompt:
23 lines.extend(['*In[%s]:*' % cell.prompt_number, ''])
24 lines.extend(['*In[%s]:*' % n, ''])
24 if self.show_prompts and self.inline_prompt:
25 if self.show_prompts and self.inline_prompt:
25 prompt = 'In[%s]: ' % cell.prompt_number
26 prompt = 'In[%s]: ' % n
26 input_lines = cell.input.split('\n')
27 input_lines = cell.input.split('\n')
27 src = prompt + input_lines[0] + '\n' + indent('\n'.join(input_lines[1:]), nspaces=len(prompt))
28 src = prompt + input_lines[0] + '\n' + indent('\n'.join(input_lines[1:]), nspaces=len(prompt))
28 else:
29 else:
29 src = cell.input
30 src = cell.input
30 src = highlight(src) if self.highlight_source else indent(src)
31 src = highlight(src) if self.highlight_source else indent(src)
31 lines.extend([src, ''])
32 lines.extend([src, ''])
32 if cell.outputs and self.show_prompts and not self.inline_prompt:
33 if cell.outputs and self.show_prompts and not self.inline_prompt:
33 lines.extend(['*Out[%s]:*' % cell.prompt_number, ''])
34 lines.extend(['*Out[%s]:*' % n, ''])
34 for output in cell.outputs:
35 for output in cell.outputs:
35 conv_fn = self.dispatch(output.output_type)
36 conv_fn = self.dispatch(output.output_type)
36 lines.extend(conv_fn(output))
37 lines.extend(conv_fn(output))
37
38
38 #lines.append('----')
39 #lines.append('----')
39 lines.append('')
40 lines.append('')
40 return lines
41 return lines
41
42
42 def render_markdown(self, cell):
43 def render_markdown(self, cell):
43 return [cell.source, '']
44 return [cell.source, '']
44
45
45 def render_raw(self, cell):
46 def render_raw(self, cell):
46 if self.raw_as_verbatim:
47 if self.raw_as_verbatim:
47 return [indent(cell.source), '']
48 return [indent(cell.source), '']
48 else:
49 else:
49 return [cell.source, '']
50 return [cell.source, '']
50
51
51 def render_pyout(self, output):
52 def render_pyout(self, output):
52 lines = []
53 lines = []
53
54
54 ## if 'text' in output:
55 ## if 'text' in output:
55 ## lines.extend(['*Out[%s]:*' % output.prompt_number, ''])
56 ## lines.extend(['*Out[%s]:*' % self._get_prompt_number(cell), ''])
56
57
57 # output is a dictionary like object with type as a key
58 # output is a dictionary like object with type as a key
58 if 'latex' in output:
59 if 'latex' in output:
59 pass
60 pass
60
61
61 if 'text' in output:
62 if 'text' in output:
62 lines.extend(['<pre>', indent(output.text), '</pre>'])
63 lines.extend(['<pre>', indent(output.text), '</pre>'])
63
64
64 lines.append('')
65 lines.append('')
65 return lines
66 return lines
66
67
67 def render_pyerr(self, output):
68 def render_pyerr(self, output):
68 # Note: a traceback is a *list* of frames.
69 # Note: a traceback is a *list* of frames.
69 return [indent(remove_ansi('\n'.join(output.traceback))), '']
70 return [indent(remove_ansi('\n'.join(output.traceback))), '']
70
71
71 def _img_lines(self, img_file):
72 def _img_lines(self, img_file):
72 return ['', '![](%s)' % img_file, '']
73 return ['', '![](%s)' % img_file, '']
73
74
74 def render_display_format_text(self, output):
75 def render_display_format_text(self, output):
75 return [indent(output.text)]
76 return [indent(output.text)]
76
77
77 def _unknown_lines(self, data):
78 def _unknown_lines(self, data):
78 return ['Warning: Unknown cell', data]
79 return ['Warning: Unknown cell', data]
79
80
80 def render_display_format_html(self, output):
81 def render_display_format_html(self, output):
81 return [output.html]
82 return [output.html]
82
83
83 def render_display_format_latex(self, output):
84 def render_display_format_latex(self, output):
84 return ['LaTeX::', indent(output.latex)]
85 return ['LaTeX::', indent(output.latex)]
85
86
86 def render_display_format_json(self, output):
87 def render_display_format_json(self, output):
87 return ['JSON:', indent(output.json)]
88 return ['JSON:', indent(output.json)]
88
89
89 def render_display_format_javascript(self, output):
90 def render_display_format_javascript(self, output):
90 return ['JavaScript:', indent(output.javascript)]
91 return ['JavaScript:', indent(output.javascript)]
@@ -1,104 +1,100 b''
1 from converters.base import Converter
1 from converters.base import Converter
2 from IPython.utils.text import indent
2 from IPython.utils.text import indent
3 from converters.utils import remove_ansi
3 from converters.utils import remove_ansi
4
4
5 class ConverterPy(Converter):
5 class ConverterPy(Converter):
6 """
6 """
7 A converter that takes a notebook and converts it to a .py file.
7 A converter that takes a notebook and converts it to a .py file.
8
8
9 What distinguishes this from PyWriter and PyReader in IPython.nbformat is
9 What distinguishes this from PyWriter and PyReader in IPython.nbformat is
10 that subclasses can specify what to do with each type of cell.
10 that subclasses can specify what to do with each type of cell.
11 Additionally, unlike PyWriter, this does not preserve the '# <markdown>'
11 Additionally, unlike PyWriter, this does not preserve the '# <markdown>'
12 opening and closing comments style comments in favor of a cleaner looking
12 opening and closing comments style comments in favor of a cleaner looking
13 python program.
13 python program.
14
14
15 Note:
15 Note:
16 Even though this produces a .py file, it is not guaranteed to be valid
16 Even though this produces a .py file, it is not guaranteed to be valid
17 python file, since the notebook may be using magics and even cell
17 python file, since the notebook may be using magics and even cell
18 magics.
18 magics.
19 """
19 """
20 extension = 'py'
20 extension = 'py'
21
21
22 def __init__(self, infile, show_prompts=True, show_output=True):
22 def __init__(self, infile, show_prompts=True, show_output=True):
23 super(ConverterPy, self).__init__(infile)
23 super(ConverterPy, self).__init__(infile)
24 self.show_prompts = show_prompts
24 self.show_prompts = show_prompts
25 self.show_output = show_output
25 self.show_output = show_output
26
26
27 @staticmethod
27 @staticmethod
28 def comment(input):
28 def comment(input):
29 "returns every line in input as commented out"
29 "returns every line in input as commented out"
30 return "# "+input.replace("\n", "\n# ")
30 return "# "+input.replace("\n", "\n# ")
31
31
32 def render_heading(self, cell):
32 def render_heading(self, cell):
33 return ['#{0} {1}'.format('#'*cell.level, cell.source), '']
33 return ['#{0} {1}'.format('#'*cell.level, cell.source), '']
34
34
35 def render_code(self, cell):
35 def render_code(self, cell):
36 try:
36 n = self._get_prompt_number(cell)
37 prompt_number = cell.prompt_number
38 except AttributeError:
39 prompt_number = " "
40
41 if not cell.input:
37 if not cell.input:
42 return []
38 return []
43 lines = []
39 lines = []
44 if self.show_prompts:
40 if self.show_prompts:
45 lines.extend(['# In[%s]:' % prompt_number])
41 lines.extend(['# In[%s]:' % n])
46 src = cell.input
42 src = cell.input
47 lines.extend([src, ''])
43 lines.extend([src, ''])
48 if self.show_output:
44 if self.show_output:
49 if cell.outputs :
45 if cell.outputs :
50 lines.extend(['# Out[%s]:' % prompt_number])
46 lines.extend(['# Out[%s]:' % n])
51 for output in cell.outputs:
47 for output in cell.outputs:
52 conv_fn = self.dispatch(output.output_type)
48 conv_fn = self.dispatch(output.output_type)
53 lines.extend(conv_fn(output))
49 lines.extend(conv_fn(output))
54 return lines
50 return lines
55
51
56 def render_markdown(self, cell):
52 def render_markdown(self, cell):
57 return [self.comment(cell.source), '']
53 return [self.comment(cell.source), '']
58
54
59 def render_raw(self, cell):
55 def render_raw(self, cell):
60 if self.raw_as_verbatim:
56 if self.raw_as_verbatim:
61 return [self.comment(indent(cell.source)), '']
57 return [self.comment(indent(cell.source)), '']
62 else:
58 else:
63 return [self.comment(cell.source), '']
59 return [self.comment(cell.source), '']
64
60
65 def render_pyout(self, output):
61 def render_pyout(self, output):
66 lines = []
62 lines = []
67
63
68 ## if 'text' in output:
64 ## if 'text' in output:
69 ## lines.extend(['*Out[%s]:*' % output.prompt_number, ''])
65 ## lines.extend(['*Out[%s]:*' % self._get_prompt_number(cell), ''])
70
66
71 # output is a dictionary like object with type as a key
67 # output is a dictionary like object with type as a key
72 if 'latex' in output:
68 if 'latex' in output:
73 pass
69 pass
74
70
75 if 'text' in output:
71 if 'text' in output:
76 lines.extend([self.comment(indent(output.text)), ''])
72 lines.extend([self.comment(indent(output.text)), ''])
77
73
78 lines.append('')
74 lines.append('')
79 return lines
75 return lines
80
76
81 def render_pyerr(self, output):
77 def render_pyerr(self, output):
82 # Note: a traceback is a *list* of frames.
78 # Note: a traceback is a *list* of frames.
83 return [indent(remove_ansi('\n'.join(output.traceback))), '']
79 return [indent(remove_ansi('\n'.join(output.traceback))), '']
84
80
85 def _img_lines(self, img_file):
81 def _img_lines(self, img_file):
86 return [ self.comment('image file: %s' % img_file), '']
82 return [ self.comment('image file: %s' % img_file), '']
87
83
88 def render_display_format_text(self, output):
84 def render_display_format_text(self, output):
89 return [self.comment(indent(output.text))]
85 return [self.comment(indent(output.text))]
90
86
91 def _unknown_lines(self, data):
87 def _unknown_lines(self, data):
92 return [self.comment('Warning: Unknown cell'+ str(data))]
88 return [self.comment('Warning: Unknown cell'+ str(data))]
93
89
94 def render_display_format_html(self, output):
90 def render_display_format_html(self, output):
95 return [self.comment(output.html)]
91 return [self.comment(output.html)]
96
92
97 def render_display_format_latex(self, output):
93 def render_display_format_latex(self, output):
98 return []
94 return []
99
95
100 def render_display_format_json(self, output):
96 def render_display_format_json(self, output):
101 return []
97 return []
102
98
103 def render_display_format_javascript(self, output):
99 def render_display_format_javascript(self, output):
104 return []
100 return []
@@ -1,79 +1,74 b''
1 from converters.base import Converter
1 from converters.base import Converter
2 from converters.utils import markdown2rst, rst_directive, remove_ansi
2 from converters.utils import markdown2rst, rst_directive, remove_ansi
3 from IPython.utils.text import indent
3 from IPython.utils.text import indent
4
4
5 class ConverterRST(Converter):
5 class ConverterRST(Converter):
6 extension = 'rst'
6 extension = 'rst'
7 heading_level = {1: '=', 2: '-', 3: '`', 4: '\'', 5: '.', 6: '~'}
7 heading_level = {1: '=', 2: '-', 3: '`', 4: '\'', 5: '.', 6: '~'}
8
8
9 def render_heading(self, cell):
9 def render_heading(self, cell):
10 marker = self.heading_level[cell.level]
10 marker = self.heading_level[cell.level]
11 return ['{0}\n{1}\n'.format(cell.source, marker * len(cell.source))]
11 return ['{0}\n{1}\n'.format(cell.source, marker * len(cell.source))]
12
12
13 def render_code(self, cell):
13 def render_code(self, cell):
14 # Note: cell has type 'IPython.nbformat.v3.nbbase.NotebookNode'
14 # Note: cell has type 'IPython.nbformat.v3.nbbase.NotebookNode'
15 if not cell.input:
15 if not cell.input:
16 return []
16 return []
17
17
18 try:
18 lines = ['In[%s]:' % self._get_prompt_number(cell), '']
19 prompt_number = cell.prompt_number
20 except AttributeError:
21 prompt_number = " "
22
23 lines = ['In[%s]:' % prompt_number, '']
24 lines.extend(rst_directive('.. code:: python', cell.input))
19 lines.extend(rst_directive('.. code:: python', cell.input))
25
20
26 for output in cell.outputs:
21 for output in cell.outputs:
27 conv_fn = self.dispatch(output.output_type)
22 conv_fn = self.dispatch(output.output_type)
28 lines.extend(conv_fn(output))
23 lines.extend(conv_fn(output))
29
24
30 return lines
25 return lines
31
26
32 def render_markdown(self, cell):
27 def render_markdown(self, cell):
33 #return [cell.source]
28 #return [cell.source]
34 return [markdown2rst(cell.source)]
29 return [markdown2rst(cell.source)]
35
30
36 def render_raw(self, cell):
31 def render_raw(self, cell):
37 if self.raw_as_verbatim:
32 if self.raw_as_verbatim:
38 return ['::', '', indent(cell.source), '']
33 return ['::', '', indent(cell.source), '']
39 else:
34 else:
40 return [cell.source]
35 return [cell.source]
41
36
42 def render_pyout(self, output):
37 def render_pyout(self, output):
43 lines = ['Out[%s]:' % output.prompt_number, '']
38 lines = ['Out[%s]:' % self._get_prompt_number(output), '']
44
39
45 # output is a dictionary like object with type as a key
40 # output is a dictionary like object with type as a key
46 if 'latex' in output:
41 if 'latex' in output:
47 lines.extend(rst_directive('.. math::', output.latex))
42 lines.extend(rst_directive('.. math::', output.latex))
48
43
49 if 'text' in output:
44 if 'text' in output:
50 lines.extend(rst_directive('.. parsed-literal::', output.text))
45 lines.extend(rst_directive('.. parsed-literal::', output.text))
51
46
52 return lines
47 return lines
53
48
54 def render_pyerr(self, output):
49 def render_pyerr(self, output):
55 # Note: a traceback is a *list* of frames.
50 # Note: a traceback is a *list* of frames.
56 return ['::', '', indent(remove_ansi('\n'.join(output.traceback))), '']
51 return ['::', '', indent(remove_ansi('\n'.join(output.traceback))), '']
57
52
58 def _img_lines(self, img_file):
53 def _img_lines(self, img_file):
59 return ['.. image:: %s' % img_file, '']
54 return ['.. image:: %s' % img_file, '']
60
55
61 def render_display_format_text(self, output):
56 def render_display_format_text(self, output):
62 return rst_directive('.. parsed-literal::', output.text)
57 return rst_directive('.. parsed-literal::', output.text)
63
58
64 def _unknown_lines(self, data):
59 def _unknown_lines(self, data):
65 return rst_directive('.. warning:: Unknown cell') + [data]
60 return rst_directive('.. warning:: Unknown cell') + [data]
66
61
67 def render_display_format_html(self, output):
62 def render_display_format_html(self, output):
68 return rst_directive('.. raw:: html', output.html)
63 return rst_directive('.. raw:: html', output.html)
69
64
70 def render_display_format_latex(self, output):
65 def render_display_format_latex(self, output):
71 return rst_directive('.. math::', output.latex)
66 return rst_directive('.. math::', output.latex)
72
67
73 def render_display_format_json(self, output):
68 def render_display_format_json(self, output):
74 return rst_directive('.. raw:: json', output.json)
69 return rst_directive('.. raw:: json', output.json)
75
70
76
71
77 def render_display_format_javascript(self, output):
72 def render_display_format_javascript(self, output):
78 return rst_directive('.. raw:: javascript', output.javascript)
73 return rst_directive('.. raw:: javascript', output.javascript)
79
74
General Comments 0
You need to be logged in to leave comments. Login now