##// END OF EJS Templates
PEP8-ify rest of the repository.
David Warde-Farley -
Show More
@@ -1,183 +1,188 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
12 class ConverterHTML(Converter):
13 class ConverterHTML(Converter):
13 extension = 'html'
14 extension = 'html'
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 n = (output.prompt_number if output.prompt_number is not None
34 else '&nbsp;')
33 content = 'Out[%s]:' % n
35 content = 'Out[%s]:' % n
34 else:
36 else:
35 content = ''
37 content = ''
36 return ['<div class="prompt output_prompt">%s</div>' % content]
38 return ['<div class="prompt output_prompt">%s</div>' % content]
37
39
38 def header_body(self):
40 def header_body(self):
39 """Return the body of the header as a list of strings."""
41 """Return the body of the header as a list of strings."""
40
42
41 from pygments.formatters import HtmlFormatter
43 from pygments.formatters import HtmlFormatter
42
44
43 header = []
45 header = []
44 static = os.path.join(path.get_ipython_package_dir(),
46 static = os.path.join(path.get_ipython_package_dir(),
45 'frontend', 'html', 'notebook', 'static',
47 'frontend', 'html', 'notebook', 'static',
46 )
48 )
47 here = os.path.split(os.path.realpath(__file__))[0]
49 here = os.path.split(os.path.realpath(__file__))[0]
48 css = os.path.join(static, 'css')
50 css = os.path.join(static, 'css')
49 for sheet in [
51 for sheet in [
50 # do we need jquery and prettify?
52 # do we need jquery and prettify?
51 # os.path.join(static, 'jquery', 'css', 'themes', 'base', 'jquery-ui.min.css'),
53 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
54 # 'jquery-ui.min.css'),
52 # os.path.join(static, 'prettify', 'prettify.css'),
55 # os.path.join(static, 'prettify', 'prettify.css'),
53 os.path.join(css, 'boilerplate.css'),
56 os.path.join(css, 'boilerplate.css'),
54 os.path.join(css, 'fbm.css'),
57 os.path.join(css, 'fbm.css'),
55 os.path.join(css, 'notebook.css'),
58 os.path.join(css, 'notebook.css'),
56 os.path.join(css, 'renderedhtml.css'),
59 os.path.join(css, 'renderedhtml.css'),
57 # our overrides:
60 # our overrides:
58 os.path.join(here, '..','css', 'static_html.css'),
61 os.path.join(here, '..', 'css', 'static_html.css'),
59 ]:
62 ]:
60 header.extend(self._stylesheet(sheet))
63 header.extend(self._stylesheet(sheet))
61
64
62 # pygments css
65 # pygments css
63 pygments_css = HtmlFormatter().get_style_defs('.highlight')
66 pygments_css = HtmlFormatter().get_style_defs('.highlight')
64 header.extend(['<meta charset="UTF-8">'])
67 header.extend(['<meta charset="UTF-8">'])
65 header.extend(self.in_tag('style', pygments_css, dict(type='"text/css"')))
68 header.extend(self.in_tag('style', pygments_css,
66
69 dict(type='"text/css"')))
70
67 # TODO: this should be allowed to use local mathjax:
71 # TODO: this should be allowed to use local mathjax:
68 header.extend(self.in_tag('script', '', {'type':'"text/javascript"',
72 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"',
73 'src': '"https://c328740.ssl.cf1.rackcdn.com/mathjax/'
74 'latest/MathJax.js?config=TeX-AMS_HTML"',
70 }))
75 }))
71 with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
76 with io.open(os.path.join(here, '..', 'js', 'initmathjax.js'),
72 encoding='utf-8') as f:
77 encoding='utf-8') as f:
73 header.extend(self.in_tag('script', f.read(),
78 header.extend(self.in_tag('script', f.read(),
74 {'type': '"text/javascript"'}))
79 {'type': '"text/javascript"'}))
75 return header
80 return header
76
81
77 def optional_header(self):
82 def optional_header(self):
78 return ['<html>', '<head>'] + self.header_body() + \
83 return ['<html>', '<head>'] + self.header_body() + \
79 ['</head>', '<body>']
84 ['</head>', '<body>']
80
85
81 def optional_footer(self):
86 def optional_footer(self):
82 return ['</body>', '</html>']
87 return ['</body>', '</html>']
83
88
84 @text_cell
89 @text_cell
85 def render_heading(self, cell):
90 def render_heading(self, cell):
86 marker = cell.level
91 marker = cell.level
87 return [u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
92 return [u'<h{1}>\n {0}\n</h{1}>'.format(cell.source, marker)]
88
93
89 def render_code(self, cell):
94 def render_code(self, cell):
90 if not cell.input:
95 if not cell.input:
91 return []
96 return []
92
97
93 lines = ['<div class="cell border-box-sizing code_cell vbox">']
98 lines = ['<div class="cell border-box-sizing code_cell vbox">']
94
99
95 lines.append('<div class="input hbox">')
100 lines.append('<div class="input hbox">')
96 n = cell.prompt_number if getattr(cell, 'prompt_number', None) is not None else '&nbsp;'
101 n = (cell.prompt_number
97 lines.append('<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n)
102 if getattr(cell, 'prompt_number', None) is not None
103 else '&nbsp;')
104 lines.append(
105 '<div class="prompt input_prompt">In&nbsp;[%s]:</div>' % n
106 )
98 lines.append('<div class="input_area box-flex1">')
107 lines.append('<div class="input_area box-flex1">')
99 lines.append(highlight(cell.input))
108 lines.append(highlight(cell.input))
100 lines.append('</div>') # input_area
109 lines.append('</div>') # input_area
101 lines.append('</div>') # input
110 lines.append('</div>') # input
102
111
103 if cell.outputs:
112 if cell.outputs:
104 lines.append('<div class="vbox output_wrapper">')
113 lines.append('<div class="vbox output_wrapper">')
105 lines.append('<div class="output vbox">')
114 lines.append('<div class="output vbox">')
106
115
107 for output in coalesce_streams(cell.outputs):
116 for output in coalesce_streams(cell.outputs):
108 conv_fn = self.dispatch(output.output_type)
117 conv_fn = self.dispatch(output.output_type)
109 lines.extend(conv_fn(output))
118 lines.extend(conv_fn(output))
110
119
111 lines.append('</div>') # output
120 lines.append('</div>') # output
112 lines.append('</div>') # output_wrapper
121 lines.append('</div>') # output_wrapper
113
122
114 lines.append('</div>') # cell
123 lines.append('</div>') # cell
115
124
116 return lines
125 return lines
117
126
118 @text_cell
127 @text_cell
119 def render_markdown(self, cell):
128 def render_markdown(self, cell):
120 return [markdown(cell.source)]
129 return [markdown(cell.source)]
121
130
122 def render_raw(self, cell):
131 def render_raw(self, cell):
123 if self.raw_as_verbatim:
132 if self.raw_as_verbatim:
124 return self.in_tag('pre', cell.source)
133 return self.in_tag('pre', cell.source)
125 else:
134 else:
126 return [cell.source]
135 return [cell.source]
127
136
128 @output_container
137 @output_container
129 def render_pyout(self, output):
138 def render_pyout(self, output):
130 for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
139 for fmt in ['html', 'latex', 'png', 'jpeg', 'svg', 'text']:
131 if fmt in output:
140 if fmt in output:
132 conv_fn = self.dispatch_display_format(fmt)
141 conv_fn = self.dispatch_display_format(fmt)
133 return conv_fn(output)
142 return conv_fn(output)
134 return []
143 return []
135
144
136 render_display_data = render_pyout
145 render_display_data = render_pyout
137
146
138 @output_container
147 @output_container
139 def render_stream(self, output):
148 def render_stream(self, output):
140 return self._ansi_colored(output.text)
149 return self._ansi_colored(output.text)
141
142
150
143 @output_container
151 @output_container
144 def render_pyerr(self, output):
152 def render_pyerr(self, output):
145 # Note: a traceback is a *list* of frames.
153 # Note: a traceback is a *list* of frames.
146 # lines = []
154 # lines = []
147
155
148 # stb =
156 # stb =
149 return self._ansi_colored('\n'.join(output.traceback))
157 return self._ansi_colored('\n'.join(output.traceback))
150
158
151 def _img_lines(self, img_file):
159 def _img_lines(self, img_file):
152 return ['<img src="%s">' % img_file, '</img>']
160 return ['<img src="%s">' % img_file, '</img>']
153
161
154 def _unknown_lines(self, data):
162 def _unknown_lines(self, data):
155 return ['<h2>Warning:: Unknown cell</h2>'] + self.in_tag('pre', data)
163 return ['<h2>Warning:: Unknown cell</h2>'] + self.in_tag('pre', data)
156
164
157
158 def render_display_format_png(self, output):
165 def render_display_format_png(self, output):
159 return ['<img src="data:image/png;base64,%s"></img>' % output.png]
166 return ['<img src="data:image/png;base64,%s"></img>' % output.png]
160
167
161 def render_display_format_svg(self, output):
168 def render_display_format_svg(self, output):
162 return [output.svg]
169 return [output.svg]
163
170
164 def render_display_format_jpeg(self, output):
171 def render_display_format_jpeg(self, output):
165 return ['<img src="data:image/jpeg;base64,%s"></img>' % output.jpeg]
172 return ['<img src="data:image/jpeg;base64,%s"></img>' % output.jpeg]
166
173
167 def render_display_format_text(self, output):
174 def render_display_format_text(self, output):
168 return self._ansi_colored(output.text)
175 return self._ansi_colored(output.text)
169
176
170 def render_display_format_html(self, output):
177 def render_display_format_html(self, output):
171 return [output.html]
178 return [output.html]
172
179
173 def render_display_format_latex(self, output):
180 def render_display_format_latex(self, output):
174 return [output.latex]
181 return [output.latex]
175
182
176 def render_display_format_json(self, output):
183 def render_display_format_json(self, output):
177 # html ignores json
184 # html ignores json
178 return []
185 return []
179
186
180
181 def render_display_format_javascript(self, output):
187 def render_display_format_javascript(self, output):
182 return [output.javascript]
188 return [output.javascript]
183
@@ -1,192 +1,191 b''
1 from converters.base import Converter
1 from converters.base import Converter
2 from converters.utils import markdown2latex, remove_ansi
2 from converters.utils import markdown2latex, remove_ansi
3 import os, sys
3 import os
4 import subprocess
4 import subprocess
5
5 import sys
6
6
7 inkscape = 'inkscape'
7 inkscape = 'inkscape'
8 if sys.platform == 'darwin':
8 if sys.platform == 'darwin':
9 inkscape = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
9 inkscape = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
10 if not os.path.exists(inkscape):
10 if not os.path.exists(inkscape):
11 inkscape = None
11 inkscape = None
12
12
13
13 class ConverterLaTeX(Converter):
14 class ConverterLaTeX(Converter):
14 """Converts a notebook to a .tex file suitable for pdflatex.
15 """Converts a notebook to a .tex file suitable for pdflatex.
15
16
16 Note: this converter *needs*:
17 Note: this converter *needs*:
17
18
18 - `pandoc`: for all conversion of markdown cells. If your notebook only
19 - `pandoc`: for all conversion of markdown cells. If your notebook only
19 has Raw cells, pandoc will not be needed.
20 has Raw cells, pandoc will not be needed.
20
21
21 - `inkscape`: if your notebook has SVG figures. These need to be
22 - `inkscape`: if your notebook has SVG figures. These need to be
22 converted to PDF before inclusion in the TeX file, as LaTeX doesn't
23 converted to PDF before inclusion in the TeX file, as LaTeX doesn't
23 understand SVG natively.
24 understand SVG natively.
24
25
25 You will in general obtain much better final PDF results if you configure
26 You will in general obtain much better final PDF results if you configure
26 the matplotlib backend to create SVG output with
27 the matplotlib backend to create SVG output with
27
28
28 %config InlineBackend.figure_format = 'svg'
29 %config InlineBackend.figure_format = 'svg'
29
30
30 (or set the equivalent flag at startup or in your configuration profile).
31 (or set the equivalent flag at startup or in your configuration profile).
31 """
32 """
32 inkscape = inkscape
33 inkscape = inkscape
33 extension = 'tex'
34 extension = 'tex'
34 documentclass = 'article'
35 documentclass = 'article'
35 documentclass_options = '11pt,english'
36 documentclass_options = '11pt,english'
36 heading_map = {1: r'\section',
37 heading_map = {1: r'\section',
37 2: r'\subsection',
38 2: r'\subsection',
38 3: r'\subsubsection',
39 3: r'\subsubsection',
39 4: r'\paragraph',
40 4: r'\paragraph',
40 5: r'\subparagraph',
41 5: r'\subparagraph',
41 6: r'\subparagraph'}
42 6: r'\subparagraph'}
42
43
43 def in_env(self, environment, lines):
44 def in_env(self, environment, lines):
44 """Return list of environment lines for input lines
45 """Return list of environment lines for input lines
45
46
46 Parameters
47 Parameters
47 ----------
48 ----------
48 env : string
49 env : string
49 Name of the environment to bracket with begin/end.
50 Name of the environment to bracket with begin/end.
50
51
51 lines: """
52 lines: """
52 out = [ur'\begin{%s}' % environment]
53 out = [ur'\begin{%s}' % environment]
53 if isinstance(lines, basestring):
54 if isinstance(lines, basestring):
54 out.append(lines)
55 out.append(lines)
55 else: # list
56 else: # list
56 out.extend(lines)
57 out.extend(lines)
57 out.append(ur'\end{%s}' % environment)
58 out.append(ur'\end{%s}' % environment)
58 return out
59 return out
59
60
60 def convert(self, *kwargs):
61 def convert(self, *args, **kwargs):
61 # The main body is done by the logic in the parent class, and that's
62 # The main body is done by the logic in the parent class, and that's
62 # all we need if preamble support has been turned off.
63 # all we need if preamble support has been turned off.
63 body = super(ConverterLaTeX, self).convert(*kwargs)
64 body = super(ConverterLaTeX, self).convert(*args, **kwargs)
64 if not self.with_preamble:
65 if not self.with_preamble:
65 return body
66 return body
66 # But if preamble is on, then we need to construct a proper, standalone
67 # But if preamble is on, then we need to construct a proper, standalone
67 # tex file.
68 # tex file.
68
69
69 # Tag the document at the top and set latex class
70 # Tag the document at the top and set latex class
70 final = [ r'%% This file was auto-generated by IPython, do NOT edit',
71 final = [r'%% This file was auto-generated by IPython, do NOT edit',
71 r'%% Conversion from the original notebook file:',
72 r'%% Conversion from the original notebook file:',
72 r'%% {0}'.format(self.infile),
73 r'%% {0}'.format(self.infile),
73 r'%%',
74 r'%%',
74 r'\documentclass[%s]{%s}' % (self.documentclass_options,
75 r'\documentclass[%s]{%s}' % (self.documentclass_options,
75 self.documentclass),
76 self.documentclass),
76 '',
77 '',
77 ]
78 ]
78 # Load our own preamble, which is stored next to the main file. We
79 # Load our own preamble, which is stored next to the main file. We
79 # need to be careful in case the script entry point is a symlink
80 # need to be careful in case the script entry point is a symlink
80 myfile = os.path.realpath(__file__)
81 myfile = os.path.realpath(__file__)
81 with open(os.path.join(os.path.dirname(myfile), '../preamble.tex')) as f:
82 preamble = '../preamble.tex'
83 with open(os.path.join(os.path.dirname(myfile), preamble)) as f:
82 final.append(f.read())
84 final.append(f.read())
83
85
84 # Load any additional user-supplied preamble
86 # Load any additional user-supplied preamble
85 if self.user_preamble:
87 if self.user_preamble:
86 final.extend(['', '%% Adding user preamble from file:',
88 final.extend(['', '%% Adding user preamble from file:',
87 '%% {0}'.format(self.user_preamble), ''])
89 '%% {0}'.format(self.user_preamble), ''])
88 with open(self.user_preamble) as f:
90 with open(self.user_preamble) as f:
89 final.append(f.read())
91 final.append(f.read())
90
92
91 # Include document body
93 # Include document body
92 final.extend([ r'\begin{document}', '',
94 final.extend([r'\begin{document}', '',
93 body,
95 body,
94 r'\end{document}', ''])
96 r'\end{document}', ''])
95 # Retun value must be a string
97 # Retun value must be a string
96 return '\n'.join(final)
98 return '\n'.join(final)
97
99
98 def render_heading(self, cell):
100 def render_heading(self, cell):
99 marker = self.heading_map[cell.level]
101 marker = self.heading_map[cell.level]
100 return ['%s{%s}' % (marker, cell.source) ]
102 return ['%s{%s}' % (marker, cell.source)]
101
103
102 def render_code(self, cell):
104 def render_code(self, cell):
103 if not cell.input:
105 if not cell.input:
104 return []
106 return []
105
107
106 # Cell codes first carry input code, we use lstlisting for that
108 # Cell codes first carry input code, we use lstlisting for that
107 lines = [ur'\begin{codecell}']
109 lines = [ur'\begin{codecell}']
108
110
109 lines.extend(self.in_env('codeinput',
111 lines.extend(self.in_env('codeinput',
110 self.in_env('lstlisting', cell.input)))
112 self.in_env('lstlisting', cell.input)))
111
113
112 outlines = []
114 outlines = []
113 for output in cell.outputs:
115 for output in cell.outputs:
114 conv_fn = self.dispatch(output.output_type)
116 conv_fn = self.dispatch(output.output_type)
115 outlines.extend(conv_fn(output))
117 outlines.extend(conv_fn(output))
116
118
117 # And then output of many possible types; use a frame for all of it.
119 # And then output of many possible types; use a frame for all of it.
118 if outlines:
120 if outlines:
119 lines.extend(self.in_env('codeoutput', outlines))
121 lines.extend(self.in_env('codeoutput', outlines))
120
122
121 lines.append(ur'\end{codecell}')
123 lines.append(ur'\end{codecell}')
122
124
123 return lines
125 return lines
124
126
125
126 def _img_lines(self, img_file):
127 def _img_lines(self, img_file):
127 return self.in_env('center',
128 return self.in_env('center',
128 [r'\includegraphics[width=6in]{%s}' % img_file, r'\par'])
129 [r'\includegraphics[width=6in]{%s}' % img_file, r'\par'])
129
130
130 def _svg_lines(self, img_file):
131 def _svg_lines(self, img_file):
131 base_file = os.path.splitext(img_file)[0]
132 base_file = os.path.splitext(img_file)[0]
132 pdf_file = base_file + '.pdf'
133 pdf_file = base_file + '.pdf'
133 subprocess.check_call([ self.inkscape, '--export-pdf=%s' % pdf_file,
134 subprocess.check_call([self.inkscape, '--export-pdf=%s' % pdf_file,
134 img_file])
135 img_file])
135 return self._img_lines(pdf_file)
136 return self._img_lines(pdf_file)
136
137
137 def render_markdown(self, cell):
138 def render_markdown(self, cell):
138 return [markdown2latex(cell.source)]
139 return [markdown2latex(cell.source)]
139
140
140 def render_pyout(self, output):
141 def render_pyout(self, output):
141 lines = []
142 lines = []
142
143
143 # output is a dictionary like object with type as a key
144 # output is a dictionary like object with type as a key
144 if 'latex' in output:
145 if 'latex' in output:
145 lines.extend(output.latex)
146 lines.extend(output.latex)
146
147
147 if 'text' in output:
148 if 'text' in output:
148 lines.extend(self.in_env('verbatim', output.text))
149 lines.extend(self.in_env('verbatim', output.text))
149
150
150 return lines
151 return lines
151
152
152 def render_pyerr(self, output):
153 def render_pyerr(self, output):
153 # Note: a traceback is a *list* of frames.
154 # Note: a traceback is a *list* of frames.
154 return self.in_env('traceback',
155 return self.in_env('traceback',
155 self.in_env('verbatim',
156 self.in_env('verbatim',
156 remove_ansi('\n'.join(output.traceback))))
157 remove_ansi('\n'.join(output.traceback))))
157
158
158 def render_raw(self, cell):
159 def render_raw(self, cell):
159 if self.raw_as_verbatim:
160 if self.raw_as_verbatim:
160 return self.in_env('verbatim', cell.source)
161 return self.in_env('verbatim', cell.source)
161 else:
162 else:
162 return [cell.source]
163 return [cell.source]
163
164
164 def _unknown_lines(self, data):
165 def _unknown_lines(self, data):
165 return [r'{\vspace{5mm}\bf WARNING:: unknown cell:}'] + \
166 return [r'{\vspace{5mm}\bf WARNING:: unknown cell:}'] + \
166 self.in_env('verbatim', data)
167 self.in_env('verbatim', data)
167
168
168
169 def render_display_format_text(self, output):
169 def render_display_format_text(self, output):
170 lines = []
170 lines = []
171
171
172 if 'text' in output:
172 if 'text' in output:
173 lines.extend(self.in_env('verbatim', output.text.strip()))
173 lines.extend(self.in_env('verbatim', output.text.strip()))
174
174
175 return lines
175 return lines
176
176
177 def render_display_format_html(self, output):
177 def render_display_format_html(self, output):
178 return []
178 return []
179
179
180 def render_display_format_latex(self, output):
180 def render_display_format_latex(self, output):
181 if type(output.latex) == type([]):
181 if type(output.latex) == type([]):
182 return output.latex
182 return output.latex
183 return [output.latex]
183 return [output.latex]
184
184
185 def render_display_format_json(self, output):
185 def render_display_format_json(self, output):
186 # latex ignores json
186 # latex ignores json
187 return []
187 return []
188
188
189
190 def render_display_format_javascript(self, output):
189 def render_display_format_javascript(self, output):
191 # latex ignores javascript
190 # latex ignores javascript
192 return []
191 return []
@@ -1,23 +1,24 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Imports
2 # Imports
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4
4
5 from pygments.lexers import PythonLexer, BashLexer
5 from pygments.lexers import PythonLexer, BashLexer
6 from pygments.lexer import bygroups, using
6 from pygments.lexer import bygroups, using
7 from pygments.token import Keyword, Operator, Text
7 from pygments.token import Keyword, Operator, Text
8
8
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Classes
11 # Classes
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 class IPythonLexer(PythonLexer):
14 class IPythonLexer(PythonLexer):
15 name = 'IPython'
15 name = 'IPython'
16 aliases = ['ip', 'ipython']
16 aliases = ['ip', 'ipython']
17 filenames = ['*.ipy']
17 filenames = ['*.ipy']
18 tokens = PythonLexer.tokens.copy()
18 tokens = PythonLexer.tokens.copy()
19 tokens['root'] = [
19 tokens['root'] = [
20 (r'(\%+)(\w+)\s+(\.*)(\n)', bygroups(Operator, Keyword, using(BashLexer), Text)),
20 (r'(\%+)(\w+)\s+(\.*)(\n)', bygroups(Operator, Keyword,
21 using(BashLexer), Text)),
21 (r'(\%+)(\w+)\b', bygroups(Operator, Keyword)),
22 (r'(\%+)(\w+)\b', bygroups(Operator, Keyword)),
22 (r'^(!)(.+)(\n)', bygroups(Operator, using(BashLexer), Text)),
23 (r'^(!)(.+)(\n)', bygroups(Operator, using(BashLexer), Text)),
23 ] + tokens['root']
24 ] + tokens['root']
@@ -1,90 +1,92 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
5 class ConverterMarkdown(Converter):
6 class ConverterMarkdown(Converter):
6 extension = 'md'
7 extension = 'md'
7
8
8 def __init__(self, infile, highlight_source=True, show_prompts=False,
9 def __init__(self, infile, highlight_source=True, show_prompts=False,
9 inline_prompt=False):
10 inline_prompt=False):
10 super(ConverterMarkdown, self).__init__(infile)
11 super(ConverterMarkdown, self).__init__(infile)
11 self.highlight_source = highlight_source
12 self.highlight_source = highlight_source
12 self.show_prompts = show_prompts
13 self.show_prompts = show_prompts
13 self.inline_prompt = inline_prompt
14 self.inline_prompt = inline_prompt
14
15
15 def render_heading(self, cell):
16 def render_heading(self, cell):
16 return ['{0} {1}'.format('#'*cell.level, cell.source), '']
17 return ['{0} {1}'.format('#' * cell.level, cell.source), '']
17
18
18 def render_code(self, cell):
19 def render_code(self, cell):
19 if not cell.input:
20 if not cell.input:
20 return []
21 return []
21 lines = []
22 lines = []
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]:*' % cell.prompt_number, ''])
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]: ' % cell.prompt_number
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' +
29 indent('\n'.join(input_lines[1:]), nspaces=len(prompt)))
28 else:
30 else:
29 src = cell.input
31 src = cell.input
30 src = highlight(src) if self.highlight_source else indent(src)
32 src = highlight(src) if self.highlight_source else indent(src)
31 lines.extend([src, ''])
33 lines.extend([src, ''])
32 if cell.outputs and self.show_prompts and not self.inline_prompt:
34 if cell.outputs and self.show_prompts and not self.inline_prompt:
33 lines.extend(['*Out[%s]:*' % cell.prompt_number, ''])
35 lines.extend(['*Out[%s]:*' % cell.prompt_number, ''])
34 for output in cell.outputs:
36 for output in cell.outputs:
35 conv_fn = self.dispatch(output.output_type)
37 conv_fn = self.dispatch(output.output_type)
36 lines.extend(conv_fn(output))
38 lines.extend(conv_fn(output))
37
39
38 #lines.append('----')
40 #lines.append('----')
39 lines.append('')
41 lines.append('')
40 return lines
42 return lines
41
43
42 def render_markdown(self, cell):
44 def render_markdown(self, cell):
43 return [cell.source, '']
45 return [cell.source, '']
44
46
45 def render_raw(self, cell):
47 def render_raw(self, cell):
46 if self.raw_as_verbatim:
48 if self.raw_as_verbatim:
47 return [indent(cell.source), '']
49 return [indent(cell.source), '']
48 else:
50 else:
49 return [cell.source, '']
51 return [cell.source, '']
50
52
51 def render_pyout(self, output):
53 def render_pyout(self, output):
52 lines = []
54 lines = []
53
55
54 ## if 'text' in output:
56 ## if 'text' in output:
55 ## lines.extend(['*Out[%s]:*' % output.prompt_number, ''])
57 ## lines.extend(['*Out[%s]:*' % output.prompt_number, ''])
56
58
57 # output is a dictionary like object with type as a key
59 # output is a dictionary like object with type as a key
58 if 'latex' in output:
60 if 'latex' in output:
59 pass
61 pass
60
62
61 if 'text' in output:
63 if 'text' in output:
62 lines.extend(['<pre>', indent(output.text), '</pre>'])
64 lines.extend(['<pre>', indent(output.text), '</pre>'])
63
65
64 lines.append('')
66 lines.append('')
65 return lines
67 return lines
66
68
67 def render_pyerr(self, output):
69 def render_pyerr(self, output):
68 # Note: a traceback is a *list* of frames.
70 # Note: a traceback is a *list* of frames.
69 return [indent(remove_ansi('\n'.join(output.traceback))), '']
71 return [indent(remove_ansi('\n'.join(output.traceback))), '']
70
72
71 def _img_lines(self, img_file):
73 def _img_lines(self, img_file):
72 return ['', '![](%s)' % img_file, '']
74 return ['', '![](%s)' % img_file, '']
73
75
74 def render_display_format_text(self, output):
76 def render_display_format_text(self, output):
75 return [indent(output.text)]
77 return [indent(output.text)]
76
78
77 def _unknown_lines(self, data):
79 def _unknown_lines(self, data):
78 return ['Warning: Unknown cell', data]
80 return ['Warning: Unknown cell', data]
79
81
80 def render_display_format_html(self, output):
82 def render_display_format_html(self, output):
81 return [output.html]
83 return [output.html]
82
84
83 def render_display_format_latex(self, output):
85 def render_display_format_latex(self, output):
84 return ['LaTeX::', indent(output.latex)]
86 return ['LaTeX::', indent(output.latex)]
85
87
86 def render_display_format_json(self, output):
88 def render_display_format_json(self, output):
87 return ['JSON:', indent(output.json)]
89 return ['JSON:', indent(output.json)]
88
90
89 def render_display_format_javascript(self, output):
91 def render_display_format_javascript(self, output):
90 return ['JavaScript:', indent(output.javascript)]
92 return ['JavaScript:', indent(output.javascript)]
@@ -1,83 +1,83 b''
1 import os
1 import os
2 from converters.base import Converter
2 from converters.base import Converter
3 from converters.utils import cell_to_lines
3 from converters.utils import cell_to_lines
4 from shutil import rmtree
4 from shutil import rmtree
5 import json
5 import json
6
6
7
7 class ConverterNotebook(Converter):
8 class ConverterNotebook(Converter):
8 """
9 """
9 A converter that is essentially a null-op.
10 A converter that is essentially a null-op.
10 This exists so it can be subclassed
11 This exists so it can be subclassed
11 for custom handlers of .ipynb files
12 for custom handlers of .ipynb files
12 that create new .ipynb files.
13 that create new .ipynb files.
13
14
14 What distinguishes this from JSONWriter is that
15 What distinguishes this from JSONWriter is that
15 subclasses can specify what to do with each type of cell.
16 subclasses can specify what to do with each type of cell.
16
17
17 Writes out a notebook file.
18 Writes out a notebook file.
18
19
19 """
20 """
20 extension = 'ipynb'
21 extension = 'ipynb'
21
22
22 def __init__(self, infile, outbase):
23 def __init__(self, infile, outbase):
23 Converter.__init__(self, infile)
24 Converter.__init__(self, infile)
24 self.outbase = outbase
25 self.outbase = outbase
25 rmtree(self.files_dir)
26 rmtree(self.files_dir)
26
27
27 def convert(self):
28 def convert(self):
28 return unicode(json.dumps(json.loads(Converter.convert(self, ',')), indent=1, sort_keys=True))
29 return unicode(json.dumps(json.loads(Converter.convert(self, ',')),
30 indent=1, sort_keys=True))
29
31
30 def optional_header(self):
32 def optional_header(self):
31 s = \
33 s = \
32 """{
34 """{
33 "metadata": {
35 "metadata": {
34 "name": "%(name)s"
36 "name": "%(name)s"
35 },
37 },
36 "nbformat": 3,
38 "nbformat": 3,
37 "worksheets": [
39 "worksheets": [
38 {
40 {
39 "cells": [""" % {'name': os.path.basename(self.outbase)}
41 "cells": [""" % {'name': os.path.basename(self.outbase)}
40
41 return s.split('\n')
42 return s.split('\n')
42
43
43 def optional_footer(self):
44 def optional_footer(self):
44 s = \
45 s = \
45 """]
46 """]
46 }
47 }
47 ]
48 ]
48 }"""
49 }"""
49 return s.split('\n')
50 return s.split('\n')
50
51
51 def render_heading(self, cell):
52 def render_heading(self, cell):
52 return cell_to_lines(cell)
53 return cell_to_lines(cell)
53
54
54 def render_code(self, cell):
55 def render_code(self, cell):
55 return cell_to_lines(cell)
56 return cell_to_lines(cell)
56
57
57 def render_markdown(self, cell):
58 def render_markdown(self, cell):
58 return cell_to_lines(cell)
59 return cell_to_lines(cell)
59
60
60 def render_raw(self, cell):
61 def render_raw(self, cell):
61 return cell_to_lines(cell)
62 return cell_to_lines(cell)
62
63
63 def render_pyout(self, output):
64 def render_pyout(self, output):
64 return cell_to_lines(output)
65 return cell_to_lines(output)
65
66
66 def render_pyerr(self, output):
67 def render_pyerr(self, output):
67 return cell_to_lines(output)
68 return cell_to_lines(output)
68
69
69 def render_display_format_text(self, output):
70 def render_display_format_text(self, output):
70 return [output.text]
71 return [output.text]
71
72
72 def render_display_format_html(self, output):
73 def render_display_format_html(self, output):
73 return [output.html]
74 return [output.html]
74
75
75 def render_display_format_latex(self, output):
76 def render_display_format_latex(self, output):
76 return [output.latex]
77 return [output.latex]
77
78
78 def render_display_format_json(self, output):
79 def render_display_format_json(self, output):
79 return [output.json]
80 return [output.json]
80
81
81
82 def render_display_format_javascript(self, output):
82 def render_display_format_javascript(self, output):
83 return [output.javascript]
83 return [output.javascript]
@@ -1,99 +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
5 class ConverterPy(Converter):
6 class ConverterPy(Converter):
6 """
7 """
7 A converter that takes a notebook and converts it to a .py file.
8 A converter that takes a notebook and converts it to a .py file.
8
9
9 What distinguishes this from PyWriter and PyReader in IPython.nbformat is
10 What distinguishes this from PyWriter and PyReader in IPython.nbformat is
10 that subclasses can specify what to do with each type of cell.
11 that subclasses can specify what to do with each type of cell.
11 Additionally, unlike PyWriter, this does not preserve the '# <markdown>'
12 Additionally, unlike PyWriter, this does not preserve the '# <markdown>'
12 opening and closing comments style comments in favor of a cleaner looking
13 opening and closing comments style comments in favor of a cleaner looking
13 python program.
14 python program.
14
15
15 Note:
16 Note:
16 Even though this produces a .py file, it is not guaranteed to be valid
17 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
18 python file, since the notebook may be using magics and even cell
18 magics.
19 magics.
19 """
20 """
20 extension = 'py'
21 extension = 'py'
21
22
22 def __init__(self, infile, show_prompts=True, show_output=True):
23 def __init__(self, infile, show_prompts=True, show_output=True):
23 super(ConverterPy, self).__init__(infile)
24 super(ConverterPy, self).__init__(infile)
24 self.show_prompts = show_prompts
25 self.show_prompts = show_prompts
25 self.show_output = show_output
26 self.show_output = show_output
26
27
27 @staticmethod
28 @staticmethod
28 def comment(input):
29 def comment(input):
29 "returns every line in input as commented out"
30 "returns every line in input as commented out"
30 return "# "+input.replace("\n", "\n# ")
31 return "# " + input.replace("\n", "\n# ")
31
32
32 def render_heading(self, cell):
33 def render_heading(self, cell):
33 return ['#{0} {1}'.format('#'*cell.level, cell.source), '']
34 return ['#{0} {1}'.format('#' * cell.level, cell.source), '']
34
35
35 def render_code(self, cell):
36 def render_code(self, cell):
36 if not cell.input:
37 if not cell.input:
37 return []
38 return []
38 lines = []
39 lines = []
39 if self.show_prompts:
40 if self.show_prompts:
40 lines.extend(['# In[%s]:' % cell.prompt_number])
41 lines.extend(['# In[%s]:' % cell.prompt_number])
41 src = cell.input
42 src = cell.input
42 lines.extend([src, ''])
43 lines.extend([src, ''])
43 if self.show_output:
44 if self.show_output:
44 if cell.outputs :
45 if cell.outputs:
45 lines.extend(['# Out[%s]:' % cell.prompt_number])
46 lines.extend(['# Out[%s]:' % cell.prompt_number])
46 for output in cell.outputs:
47 for output in cell.outputs:
47 conv_fn = self.dispatch(output.output_type)
48 conv_fn = self.dispatch(output.output_type)
48 lines.extend(conv_fn(output))
49 lines.extend(conv_fn(output))
49 return lines
50 return lines
50
51
51 def render_markdown(self, cell):
52 def render_markdown(self, cell):
52 return [self.comment(cell.source), '']
53 return [self.comment(cell.source), '']
53
54
54 def render_raw(self, cell):
55 def render_raw(self, cell):
55 if self.raw_as_verbatim:
56 if self.raw_as_verbatim:
56 return [self.comment(indent(cell.source)), '']
57 return [self.comment(indent(cell.source)), '']
57 else:
58 else:
58 return [self.comment(cell.source), '']
59 return [self.comment(cell.source), '']
59
60
60 def render_pyout(self, output):
61 def render_pyout(self, output):
61 lines = []
62 lines = []
62
63
63 ## if 'text' in output:
64 ## if 'text' in output:
64 ## lines.extend(['*Out[%s]:*' % output.prompt_number, ''])
65 ## lines.extend(['*Out[%s]:*' % output.prompt_number, ''])
65
66
66 # output is a dictionary like object with type as a key
67 # output is a dictionary like object with type as a key
67 if 'latex' in output:
68 if 'latex' in output:
68 pass
69 pass
69
70
70 if 'text' in output:
71 if 'text' in output:
71 lines.extend([self.comment(indent(output.text)), ''])
72 lines.extend([self.comment(indent(output.text)), ''])
72
73
73 lines.append('')
74 lines.append('')
74 return lines
75 return lines
75
76
76 def render_pyerr(self, output):
77 def render_pyerr(self, output):
77 # Note: a traceback is a *list* of frames.
78 # Note: a traceback is a *list* of frames.
78 return [indent(remove_ansi('\n'.join(output.traceback))), '']
79 return [indent(remove_ansi('\n'.join(output.traceback))), '']
79
80
80 def _img_lines(self, img_file):
81 def _img_lines(self, img_file):
81 return [ self.comment('image file: %s' % img_file), '']
82 return [self.comment('image file: %s' % img_file), '']
82
83
83 def render_display_format_text(self, output):
84 def render_display_format_text(self, output):
84 return [self.comment(indent(output.text))]
85 return [self.comment(indent(output.text))]
85
86
86 def _unknown_lines(self, data):
87 def _unknown_lines(self, data):
87 return [self.comment('Warning: Unknown cell'+ str(data))]
88 return [self.comment('Warning: Unknown cell' + str(data))]
88
89
89 def render_display_format_html(self, output):
90 def render_display_format_html(self, output):
90 return [self.comment(output.html)]
91 return [self.comment(output.html)]
91
92
92 def render_display_format_latex(self, output):
93 def render_display_format_latex(self, output):
93 return []
94 return []
94
95
95 def render_display_format_json(self, output):
96 def render_display_format_json(self, output):
96 return []
97 return []
97
98
98 def render_display_format_javascript(self, output):
99 def render_display_format_javascript(self, output):
99 return []
100 return []
@@ -1,27 +1,27 b''
1 """
1 """
2 This module gives a simple example of a custom notebook converter that only
2 This module gives a simple example of a custom notebook converter that only
3 captures display data and deletes the cell inputs.
3 captures display data and deletes the cell inputs.
4 """
4 """
5
5
6 import copy
6 import copy
7 import nbconvert as nb
7 import nbconvert as nb
8
8
9
9 class CustomNotebookConverter(nb.ConverterNotebook):
10 class CustomNotebookConverter(nb.ConverterNotebook):
10
11
11 def render_code(self, cell):
12 def render_code(self, cell):
12
13
13 captured_outputs = ['text', 'html', 'svg', 'latex', 'javascript']
14 captured_outputs = ['text', 'html', 'svg', 'latex', 'javascript']
14
15
15 cell = copy.deepcopy(cell)
16 cell = copy.deepcopy(cell)
16 cell['input'] = ''
17 cell['input'] = ''
17
18
18 for output in cell.outputs:
19 for output in cell.outputs:
19 if output.output_type != 'display_data':
20 if output.output_type != 'display_data':
20 cell.outputs.remove(output)
21 cell.outputs.remove(output)
21 return nb.ConverterNotebook.render_code(self, cell)
22 return nb.ConverterNotebook.render_code(self, cell)
22
23
23 if __name__ == '__main__':
24 if __name__ == '__main__':
24 infile = 'tests/test_display.ipynb'
25 infile = 'tests/test_display.ipynb'
25 converter = CustomNotebookConverter(infile, 'test_only_display')
26 converter = CustomNotebookConverter(infile, 'test_only_display')
26 converter.render()
27 converter.render()
27
@@ -1,88 +1,97 b''
1 # dollarmath.py by Akihiro Uchida *public domain*
1 # dollarmath.py by Akihiro Uchida *public domain*
2 # the original one is written by Paul Kienzle
2 # the original one is written by Paul Kienzle
3 # and published as public domain in [sphinx-dev]: $math$ extension
3 # and published as public domain in [sphinx-dev]: $math$ extension
4 r"""
4 r"""
5 Allow $math$ markup in text and docstrings, ignoring \$.
5 Allow $math$ markup in text and docstrings, ignoring \$.
6
6
7 The $math$ markup should be separated from the surrounding text by spaces.
7 The $math$ markup should be separated from the surrounding text by spaces.
8 To embed markup within a word, place backslash-space before and after.
8 To embed markup within a word, place backslash-space before and after.
9 For convenience, the final $ can be followed by punctuation
9 For convenience, the final $ can be followed by punctuation
10 (period, comma or semicolon).
10 (period, comma or semicolon).
11 """
11 """
12
12
13 import re
13 import re
14
14
15 dollar_pat = r"(?:^|(?<=\s))[$]([^\n]*?)(?<![\\])[$](?:$|(?=\s|[.,;\\]))"
15 dollar_pat = r"(?:^|(?<=\s))[$]([^\n]*?)(?<![\\])[$](?:$|(?=\s|[.,;\\]))"
16 _dollar = re.compile(dollar_pat)
16 _dollar = re.compile(dollar_pat)
17 _notdollar = re.compile(r"\\[$]")
17 _notdollar = re.compile(r"\\[$]")
18
18
19
19 def replace_dollar(content):
20 def replace_dollar(content):
20 content = _dollar.sub(r":math:`\1`", content)
21 content = _dollar.sub(r":math:`\1`", content)
21 content = _notdollar.sub("$", content)
22 content = _notdollar.sub("$", content)
22 return content
23 return content
23
24
25
24 def rewrite_rst(app, docname, source):
26 def rewrite_rst(app, docname, source):
25 source[0] = replace_dollar(source[0])
27 source[0] = replace_dollar(source[0])
26
28
29
27 def rewrite_autodoc(app, what, name, obj, options, lines):
30 def rewrite_autodoc(app, what, name, obj, options, lines):
28 lines[:] = [replace_dollar(L) for L in lines]
31 lines[:] = [replace_dollar(L) for L in lines]
29
32
33
30 def setup(app):
34 def setup(app):
31 app.connect('source-read', rewrite_rst)
35 app.connect('source-read', rewrite_rst)
32 if 'autodoc-process-docstring' in app._events:
36 if 'autodoc-process-docstring' in app._events:
33 app.connect('autodoc-process-docstring', rewrite_autodoc)
37 app.connect('autodoc-process-docstring', rewrite_autodoc)
34
38
39
35 def test_expr(expr, expect):
40 def test_expr(expr, expect):
36 result = replace_dollar(expr)
41 result = replace_dollar(expr)
37 print 'A math expression: %s' % expr
42 print 'A math expression: %s' % expr
38 print 'A expected output: %s' % expect
43 print 'A expected output: %s' % expect
39 if result == expect:
44 if result == expect:
40 print 'OK: A result match expected one'
45 print 'OK: A result match expected one'
41 else:
46 else:
42 print 'NG: A result %s does not match expected one!' % result
47 print 'NG: A result %s does not match expected one!' % result
43
48
49
44 def test_dollar():
50 def test_dollar():
45 samples = {
51 samples = {
46 u"no dollar": u"no dollar",
52 u"no dollar": u"no dollar",
47 u"$only$": u":math:`only`",
53 u"$only$": u":math:`only`",
48 u"$first$ is good": u":math:`first` is good",
54 u"$first$ is good": u":math:`first` is good",
49 u"so is $last$": u"so is :math:`last`",
55 u"so is $last$": u"so is :math:`last`",
50 u"and $mid$ too": u"and :math:`mid` too",
56 u"and $mid$ too": u"and :math:`mid` too",
51 u"$first$, $mid$, $last$": u":math:`first`, :math:`mid`, :math:`last`",
57 u"$first$, $mid$, $last$": u":math:`first`, :math:`mid`, :math:`last`",
52 u"dollar\$ escape": u"dollar$ escape",
58 u"dollar\$ escape": u"dollar$ escape",
53 u"dollar \$escape\$ too": u"dollar $escape$ too",
59 u"dollar \$escape\$ too": u"dollar $escape$ too",
54 u"emb\ $ed$\ ed": u"emb\ :math:`ed`\ ed",
60 u"emb\ $ed$\ ed": u"emb\ :math:`ed`\ ed",
55 u"$first$a": u"$first$a",
61 u"$first$a": u"$first$a",
56 u"a$last$": u"a$last$",
62 u"a$last$": u"a$last$",
57 u"a $mid$dle a": u"a $mid$dle a",
63 u"a $mid$dle a": u"a $mid$dle a",
58 }
64 }
59 for expr, expect in samples.items():
65 for expr, expect in samples.items():
60 test_expr(expr, expect)
66 test_expr(expr, expect)
61
67
68
62 if __name__ == "__main__":
69 if __name__ == "__main__":
63 import sys, locale, codecs
70 import sys
71 import locale
72 import codecs
64 encoding = locale.getpreferredencoding()
73 encoding = locale.getpreferredencoding()
65 sys.stdout = codecs.getwriter(encoding)(sys.stdout)
74 sys.stdout = codecs.getwriter(encoding)(sys.stdout)
66 sys.stdin = codecs.getreader(encoding)(sys.stdin)
75 sys.stdin = codecs.getreader(encoding)(sys.stdin)
67
76
68 import optparse
77 import optparse
69 parser = optparse.OptionParser(usage='usage: %prog [options]')
78 parser = optparse.OptionParser(usage='usage: %prog [options]')
70 parser.add_option("-i", "--input", dest="expr", type="string",
79 parser.add_option("-i", "--input", dest="expr", type="string",
71 help="input $math$ expression to test")
80 help="input $math$ expression to test")
72 parser.add_option("-o", "--output", dest="expect", type="string",
81 parser.add_option("-o", "--output", dest="expect", type="string",
73 help="output result you expect")
82 help="output result you expect")
74
83
75 opts, args = parser.parse_args()
84 opts, args = parser.parse_args()
76 if opts.expr:
85 if opts.expr:
77 expression = unicode(opts.expr, encoding)
86 expression = unicode(opts.expr, encoding)
78 if opts.expect:
87 if opts.expect:
79 expected = unicode(opts.expect, encoding)
88 expected = unicode(opts.expect, encoding)
80 test_expr(expression, expected)
89 test_expr(expression, expected)
81 else:
90 else:
82 print replace_dollar(expression)
91 print replace_dollar(expression)
83 else:
92 else:
84 if opts.expect:
93 if opts.expect:
85 parser.print_help()
94 parser.print_help()
86 parser.error("output option requires input expression")
95 parser.error("output option requires input expression")
87 else:
96 else:
88 test_dollar()
97 test_dollar()
@@ -1,78 +1,79 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Convert IPython notebooks to other formats, such as ReST, and HTML.
2 """Convert IPython notebooks to other formats, such as ReST, and HTML.
3
3
4 Example:
4 Example:
5 ./nbconvert.py --format rst file.ipynb
5 ./nbconvert.py --format rst file.ipynb
6
6
7 Produces 'file.rst', along with auto-generated figure files
7 Produces 'file.rst', along with auto-generated figure files
8 called nb_figure_NN.png.
8 called nb_figure_NN.png.
9 """
9 """
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # From IPython
15 # From IPython
16 from IPython.external import argparse
16 from IPython.external import argparse
17
17
18 # local
18 # local
19 from converters.html import ConverterHTML
19 from converters.html import ConverterHTML
20 from converters.markdown import ConverterMarkdown
20 from converters.markdown import ConverterMarkdown
21 from converters.bloggerhtml import ConverterBloggerHTML
21 from converters.bloggerhtml import ConverterBloggerHTML
22 from converters.rst import ConverterRST
22 from converters.rst import ConverterRST
23 from converters.latex import ConverterLaTeX
23 from converters.latex import ConverterLaTeX
24 from converters.python import ConverterPy
24 from converters.python import ConverterPy
25
25
26
26
27 # When adding a new format, make sure to add it to the `converters`
27 # When adding a new format, make sure to add it to the `converters`
28 # dictionary below. This is used to create the list of known formats,
28 # dictionary below. This is used to create the list of known formats,
29 # which gets printed in case an unknown format is encounteres, as well
29 # which gets printed in case an unknown format is encounteres, as well
30 # as in the help
30 # as in the help
31
31
32 converters = {
32 converters = {
33 'rst': ConverterRST,
33 'rst': ConverterRST,
34 'markdown': ConverterMarkdown,
34 'markdown': ConverterMarkdown,
35 'html': ConverterHTML,
35 'html': ConverterHTML,
36 'blogger-html': ConverterBloggerHTML,
36 'blogger-html': ConverterBloggerHTML,
37 'latex': ConverterLaTeX,
37 'latex': ConverterLaTeX,
38 'py': ConverterPy,
38 'py': ConverterPy,
39 }
39 }
40
40
41 default_format = 'rst'
41 default_format = 'rst'
42
42
43 # Extract the list of known formats and mark the first format as the default.
43 # Extract the list of known formats and mark the first format as the default.
44 known_formats = ', '.join([key + " (default)" if key == default_format else key
44 known_formats = ', '.join([key + " (default)" if key == default_format else key
45 for key in converters])
45 for key in converters])
46
46
47
47
48
48
49 def main(infile, format='rst'):
49 def main(infile, format='rst'):
50 """Convert a notebook to html in one step"""
50 """Convert a notebook to html in one step"""
51
51
52 try:
52 try:
53 ConverterClass = converters[format]
53 ConverterClass = converters[format]
54 except KeyError:
54 except KeyError:
55 raise SystemExit("Unknown format '%s', " % format +
55 raise SystemExit("Unknown format '%s', " % format +
56 "known formats are: " + known_formats)
56 "known formats are: " + known_formats)
57
57
58 converter = ConverterClass(infile)
58 converter = ConverterClass(infile)
59 converter.render()
59 converter.render()
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Script main
62 # Script main
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 if __name__ == '__main__':
65 if __name__ == '__main__':
66 parser = argparse.ArgumentParser(description=__doc__,
66 parser = argparse.ArgumentParser(description=__doc__,
67 formatter_class=argparse.RawTextHelpFormatter)
67 formatter_class=argparse.RawTextHelpFormatter)
68 # TODO: consider passing file like object around, rather than filenames
68 # TODO: consider passing file like object around, rather than filenames
69 # would allow us to process stdin, or even http streams
69 # would allow us to process stdin, or even http streams
70 #parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
70 #parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
71 # default=sys.stdin)
71
72
72 #Require a filename as a positional argument
73 #Require a filename as a positional argument
73 parser.add_argument('infile', nargs=1)
74 parser.add_argument('infile', nargs=1)
74 parser.add_argument('-f', '--format', default='rst',
75 parser.add_argument('-f', '--format', default='rst',
75 help='Output format. Supported formats: \n' +
76 help='Output format. Supported formats: \n' +
76 known_formats)
77 known_formats)
77 args = parser.parse_args()
78 args = parser.parse_args()
78 main(infile=args.infile[0], format=args.format)
79 main(infile=args.infile[0], format=args.format)
@@ -1,124 +1,123 b''
1 """
1 """
2 Simple ipython notebook document tree Writer.
2 Simple ipython notebook document tree Writer.
3
3
4 """
4 """
5
5
6 __docformat__ = 'reStructuredText'
6 __docformat__ = 'reStructuredText'
7
7
8
8
9 import sys
9 import sys
10 import os
10 import os
11 import os.path
11 import os.path
12 import time
12 import time
13 import re
13 import re
14 import urllib
14 import urllib
15 import docutils
15 import docutils
16 from docutils import frontend, nodes, utils, writers, languages, io
16 from docutils import frontend, nodes, utils, writers, languages, io
17 from docutils.error_reporting import SafeString
17 from docutils.error_reporting import SafeString
18 from docutils.transforms import writer_aux
18 from docutils.transforms import writer_aux
19 from docutils.math import unichar2tex, pick_math_environment
19 from docutils.math import unichar2tex, pick_math_environment
20 from docutils.math.latex2mathml import parse_latex_math
20 from docutils.math.latex2mathml import parse_latex_math
21 from docutils.math.math2html import math2html
21 from docutils.math.math2html import math2html
22 from IPython.nbformat import current as nbformat
22 from IPython.nbformat import current as nbformat
23
23
24
24
25 class Writer(writers.Writer):
25 class Writer(writers.Writer):
26
26
27 supported = ('ipynb')
27 supported = ('ipynb')
28 """Formats this writer supports."""
28 """Formats this writer supports."""
29
29
30 visitor_attributes = ()
30 visitor_attributes = ()
31
31
32 def get_transforms(self):
32 def get_transforms(self):
33 return writers.Writer.get_transforms(self) + [writer_aux.Admonitions]
33 return writers.Writer.get_transforms(self) + [writer_aux.Admonitions]
34
34
35 def __init__(self):
35 def __init__(self):
36 writers.Writer.__init__(self)
36 writers.Writer.__init__(self)
37 self.translator_class = IPYNBTranslator
37 self.translator_class = IPYNBTranslator
38
38
39 def translate(self):
39 def translate(self):
40 self.visitor = visitor = self.translator_class(self.document)
40 self.visitor = visitor = self.translator_class(self.document)
41 self.document.walkabout(visitor)
41 self.document.walkabout(visitor)
42 for attr in self.visitor_attributes:
42 for attr in self.visitor_attributes:
43 setattr(self, attr, getattr(visitor, attr))
43 setattr(self, attr, getattr(visitor, attr))
44 self.output = '{0}'.format(nbformat.writes(visitor.nb, 'ipynb'))
44 self.output = '{0}'.format(nbformat.writes(visitor.nb, 'ipynb'))
45
45
46
46
47 class IPYNBTranslator(nodes.GenericNodeVisitor):
47 class IPYNBTranslator(nodes.GenericNodeVisitor):
48
48
49 """
49 """
50 """
50 """
51
51
52 def __init__(self, document):
52 def __init__(self, document):
53 nodes.NodeVisitor.__init__(self, document)
53 nodes.NodeVisitor.__init__(self, document)
54 self.settings = settings = document.settings
54 self.settings = settings = document.settings
55 lcode = settings.language_code
55 lcode = settings.language_code
56 self.language = languages.get_language(lcode, document.reporter)
56 self.language = languages.get_language(lcode, document.reporter)
57 # A heterogenous stack used in conjunction with the tree traversal.
57 # A heterogenous stack used in conjunction with the tree traversal.
58 # Make sure that the pops correspond to the pushes:
58 # Make sure that the pops correspond to the pushes:
59 self.context = []
59 self.context = []
60 self.body = []
60 self.body = []
61 self.section_level = 0
61 self.section_level = 0
62 ws = nbformat.new_worksheet()
62 ws = nbformat.new_worksheet()
63 self.nb = nbformat.new_notebook(worksheets=[ws])
63 self.nb = nbformat.new_notebook(worksheets=[ws])
64
64
65 def astext(self):
65 def astext(self):
66 return '{0}'.format(nbformat.writes(self.nb, 'ipynb'))
66 return '{0}'.format(nbformat.writes(self.nb, 'ipynb'))
67
67
68 def is_ref_error_paragraph(self, p):
68 def is_ref_error_paragraph(self, p):
69 return p == "Unknown interpreted text role \"ref\"."
69 return p == "Unknown interpreted text role \"ref\"."
70
70
71 def add_cell(self, cell):
71 def add_cell(self, cell):
72 self.nb.worksheets[0].cells.append(cell)
72 self.nb.worksheets[0].cells.append(cell)
73
73
74 def visit_literal_block(self, node):
74 def visit_literal_block(self, node):
75 raw_text = node.astext()
75 raw_text = node.astext()
76 #only include lines that begin with >>>
76 #only include lines that begin with >>>
77 #we want the example code and not the example output
77 #we want the example code and not the example output
78 processed_text = '\n'.join([line.split('>>>')[1][1:]
78 processed_text = '\n'.join([line.split('>>>')[1][1:]
79 for line in raw_text.split('\n')
79 for line in raw_text.split('\n')
80 if line.startswith('>>>')])
80 if line.startswith('>>>')])
81 c = nbformat.new_code_cell(input=processed_text)
81 c = nbformat.new_code_cell(input=processed_text)
82 self.add_cell(c)
82 self.add_cell(c)
83
83
84 def visit_paragraph(self, node):
84 def visit_paragraph(self, node):
85 text = node.astext()
85 text = node.astext()
86 # For every ref directive a paragraph contains
86 # For every ref directive a paragraph contains
87 # docutils will generate a paragraph complaining
87 # docutils will generate a paragraph complaining
88 # "Unknown interpreted text role \"ref\"."
88 # "Unknown interpreted text role \"ref\"."
89 # this is because ref is a sphinx directive
89 # this is because ref is a sphinx directive
90 # that does not exist in docutils
90 # that does not exist in docutils
91 # looking for a better way to handle this
91 # looking for a better way to handle this
92 # for now filtering such pargraphs from the output
92 # for now filtering such pargraphs from the output
93
93
94 if not self.is_ref_error_paragraph(text):
94 if not self.is_ref_error_paragraph(text):
95 p = nbformat.new_text_cell('markdown', source=text)
95 p = nbformat.new_text_cell('markdown', source=text)
96 self.add_cell(p)
96 self.add_cell(p)
97
97
98
99 def visit_section(self, node):
98 def visit_section(self, node):
100 self.section_level += 1
99 self.section_level += 1
101 self.default_visit(node)
100 self.default_visit(node)
102
101
103 def depart_section(self, node):
102 def depart_section(self, node):
104 self.section_level -= 1
103 self.section_level -= 1
105 self.default_departure(node)
104 self.default_departure(node)
106
105
107 def visit_title(self, node):
106 def visit_title(self, node):
108 #make sure we have a valid heading level between 1 and 6
107 #make sure we have a valid heading level between 1 and 6
109 heading_level = min(self.section_level, 5) + 1
108 heading_level = min(self.section_level, 5) + 1
110 h = nbformat.new_heading_cell(source=node.astext(),
109 h = nbformat.new_heading_cell(source=node.astext(),
111 level=heading_level)
110 level=heading_level)
112 self.add_cell(h)
111 self.add_cell(h)
113
112
114 def default_visit(self, node):
113 def default_visit(self, node):
115 node_class = node.__class__.__name__
114 node_class = node.__class__.__name__
116 #print '*default_visit', node_class
115 #print '*default_visit', node_class
117 #if node_class in ['reference','paragraph','literal_block','title']:
116 #if node_class in ['reference','paragraph','literal_block','title']:
118 if node_class in []:
117 if node_class in []:
119 print '*default_visit', node_class
118 print '*default_visit', node_class
120 print node.astext()
119 print node.astext()
121
120
122 def default_departure(self, node):
121 def default_departure(self, node):
123 #print '*default depart', node.__class__.__name__
122 #print '*default depart', node.__class__.__name__
124 pass
123 pass
@@ -1,35 +1,33 b''
1 from nbconvert import ConverterNotebook
1 from nbconvert import ConverterNotebook
2 import nose.tools as nt
2 import nose.tools as nt
3 import os
3 import os
4 import json
4 import json
5 import shutil
5 import shutil
6 import tempfile
6 import tempfile
7
7
8
8
9 # name = os.path.join(os.path.dirname(os.path.abspath(__file__), test.ipynb')
9 # name = os.path.join(os.path.dirname(os.path.abspath(__file__), test.ipynb')
10 outbase1 = 'newtest1'
10 outbase1 = 'newtest1'
11 outbase2 = 'test' # will output to ./test.ipynb
11 outbase2 = 'test' # will output to ./test.ipynb
12
12
13
13
14 def test_roundtrip():
14 def test_roundtrip():
15 directory = tempfile.mkdtemp()
15 directory = tempfile.mkdtemp()
16 out1 = os.path.join(directory, outbase1)
16 out1 = os.path.join(directory, outbase1)
17 out2 = os.path.join(directory, outbase2)
17 out2 = os.path.join(directory, outbase2)
18 fname = os.path.join(os.path.dirname(os.path.abspath(__file__)),
18 fname = os.path.join(os.path.dirname(os.path.abspath(__file__)),
19 'test.ipynb')
19 'test.ipynb')
20 converter = ConverterNotebook(fname, out1)
20 converter = ConverterNotebook(fname, out1)
21 converter.render()
21 converter.render()
22
23 converter2 = ConverterNotebook(out1 + '.ipynb', out2)
22 converter2 = ConverterNotebook(out1 + '.ipynb', out2)
24 converter2.render()
23 converter2.render()
25
24
26 with open(out1 + '.ipynb', 'rb') as f:
25 with open(out1 + '.ipynb', 'rb') as f:
27 s1 = f.read()
26 s1 = f.read()
28 with open(out2 + '.ipynb', 'rb') as f:
27 with open(out2 + '.ipynb', 'rb') as f:
29 s2 = f.read()
28 s2 = f.read()
30
29
31 nt.assert_true(s1.replace(outbase1, outbase2) == s2)
30 nt.assert_true(s1.replace(outbase1, outbase2) == s2)
32 shutil.rmtree(directory)
31 shutil.rmtree(directory)
33
34 s0 = json.dumps(json.load(file(fname)), indent=1, sort_keys=True)
32 s0 = json.dumps(json.load(file(fname)), indent=1, sort_keys=True)
35 nt.assert_true(s0 == s2)
33 nt.assert_true(s0 == s2)
@@ -1,47 +1,47 b''
1 import io
1 import io
2 import nose.tools as nt
2 import nose.tools as nt
3 from nbconvert import (
3 from nose.tools import nottest
4 from converts import (
4 ConverterLaTeX, ConverterMarkdown, ConverterPy, ConverterHTML
5 ConverterLaTeX, ConverterMarkdown, ConverterPy, ConverterHTML
5 )
6 )
6 from nose.tools import nottest
7
7
8
8
9 def test_evens():
9 def test_evens():
10 ######
10 ######
11 # for now, we don't need to really run inkscape to extract svg
11 # for now, we don't need to really run inkscape to extract svg
12 # from file, on unix, for test, we monkeypathc it to 'true'
12 # from file, on unix, for test, we monkeypathc it to 'true'
13 # which does not fail as doing anything.
13 # which does not fail as doing anything.
14 ####
14 ####
15 ConverterLaTeX.inkscape = 'true'
15 ConverterLaTeX.inkscape = 'true'
16
16
17 # commenting rst for now as travis build
17 # commenting rst for now as travis build
18 # fail because of pandoc version.
18 # fail because of pandoc version.
19 converters = [
19 converters = [
20 #(ConverterRST,'rst'),
20 #(ConverterRST, 'rst'),
21 (ConverterMarkdown, 'md'),
21 (ConverterMarkdown, 'md'),
22 (ConverterLaTeX, 'tex'),
22 (ConverterLaTeX, 'tex'),
23 (ConverterPy, 'py'),
23 (ConverterPy, 'py'),
24 (ConverterHTML, 'html')
24 (ConverterHTML, 'html')
25 ]
25 ]
26 reflist = [
26 reflist = [
27 'tests/ipynbref/IntroNumPy.orig'
27 'tests/ipynbref/IntroNumPy.orig'
28 ]
28 ]
29 for root in reflist:
29 for root in reflist:
30 for conv, ext in converters:
30 for conv, ext in converters:
31 yield test_conversion, conv, root + '.ipynb', root + '.' + ext
31 yield test_conversion, conv, root + '.ipynb', root + '.' + ext
32
32
33
33
34 @nottest
34 @nottest
35 def compfiles(stra, strb):
35 def compfiles(stra, strb):
36 nt.assert_equal(map(unicode.strip, stra.split('\n')),
36 nt.assert_equal(map(unicode.strip, stra.split('\n')),
37 map(unicode.strip, strb.split('\n')))
37 map(unicode.strip, strb.split('\n')))
38
38
39
39
40 @nottest
40 @nottest
41 def test_conversion(ConverterClass, ipynb, ref_file):
41 def test_conversion(ConverterClass, ipynb, ref_file):
42 converter = ConverterClass(ipynb)
42 converter = ConverterClass(ipynb)
43 converter.read()
43 converter.read()
44 cv = converter.convert()
44 cv = converter.convert()
45 with io.open(ref_file) as ref:
45 with io.open(ref_file) as ref:
46 value = ref.read()
46 value = ref.read()
47 compfiles(cv, value)
47 compfiles(cv, value)
@@ -1,71 +1,71 b''
1 from nbconvert import ConverterRST, main
1 from nbconvert import ConverterRST, main
2 import nose.tools as nt
2 import nose.tools as nt
3
3
4 import os
4 import os
5 import glob
5 import glob
6 from IPython.nbformat import current as nbformat
6 from IPython.nbformat import current as nbformat
7
7
8 fname = 'tests/test.ipynb'
8 fname = 'tests/test.ipynb'
9 out_fname = 'tests/test.rst'
9 out_fname = 'tests/test.rst'
10
10
11
11
12 def clean_dir():
12 def clean_dir():
13 "Remove .rst files created during conversion"
13 "Remove .rst files created during conversion"
14 map(os.remove, glob.glob("./tests/*.rst"))
14 map(os.remove, glob.glob("./tests/*.rst"))
15 map(os.remove, glob.glob("./tests/*.png"))
15 map(os.remove, glob.glob("./tests/*.png"))
16 map(os.remove, glob.glob("./tests/*.html"))
16 map(os.remove, glob.glob("./tests/*.html"))
17 map(os.remove, glob.glob("./tests/test_files/*"))
17 map(os.remove, glob.glob("./tests/test_files/*"))
18
18
19
19
20 @nt.with_setup(clean_dir, clean_dir)
20 @nt.with_setup(clean_dir, clean_dir)
21 def test_simple():
21 def test_simple():
22 c = ConverterRST(fname)
22 c = ConverterRST(fname)
23 f = c.render()
23 f = c.render()
24 nt.assert_true(f.endswith('.rst'), 'changed file extension to rst')
24 nt.assert_true(f.endswith('.rst'), 'changed file extension to rst')
25
25
26
26
27 @nt.with_setup(clean_dir, clean_dir)
27 @nt.with_setup(clean_dir, clean_dir)
28 def test_main():
28 def test_main():
29 """
29 """
30 Test main entry point
30 Test main entry point
31 """
31 """
32 main(fname)
32 main(fname)
33 nt.assert_true(os.path.exists(out_fname))
33 nt.assert_true(os.path.exists(out_fname))
34
34
35
35
36 def test_render_heading():
36 def test_render_heading():
37 """ Unit test for cell type "heading" """
37 """ Unit test for cell type "heading" """
38 # Generate and test heading cells level 1-6
38 # Generate and test heading cells level 1-6
39 for level in xrange(1, 7):
39 for level in xrange(1, 7):
40 cell = {
40 cell = {
41 'cell_type': 'heading',
41 'cell_type': 'heading',
42 'level': level,
42 'level': level,
43 'source': ['Test for heading type H{0}'.format(level)]
43 'source': ['Test for heading type H{0}'.format(level)]
44 }
44 }
45 # Convert cell dictionaries to NotebookNode
45 # Convert cell dictionaries to NotebookNode
46 cell_nb = nbformat.NotebookNode(cell)
46 cell_nb = nbformat.NotebookNode(cell)
47 # Make sure "source" attribute is uniconde not list.
47 # Make sure "source" attribute is uniconde not list.
48 # For some reason, creating a NotebookNode manually like
48 # For some reason, creating a NotebookNode manually like
49 # this isn't converting source to a string like using
49 # this isn't converting source to a string like using
50 # the create-from-file routine.
50 # the create-from-file routine.
51 if type(cell_nb.source) is list:
51 if type(cell_nb.source) is list:
52 cell_nb.source = '\n'.join(cell_nb.source)
52 cell_nb.source = '\n'.join(cell_nb.source)
53 # Render to rst
53 # Render to rst
54 c = ConverterRST('')
54 c = ConverterRST('')
55 rst_list = c.render_heading(cell_nb)
55 rst_list = c.render_heading(cell_nb)
56 # render should return a list
56 # render should return a list
57 nt.assert_true(isinstance(rst_list, list))
57 nt.assert_true(isinstance(rst_list, list))
58 rst_str = "".join(rst_list)
58 rst_str = "".join(rst_list)
59 # Confirm rst content
59 # Confirm rst content
60 chk_str = "Test for heading type H{0}\n{1}\n".format(
60 chk_str = "Test for heading type H{0}\n{1}\n".format(
61 level, c.heading_level[level] * 24)
61 level, c.heading_level[level] * 24)
62 nt.assert_equal(rst_str, chk_str)
62 nt.assert_equal(rst_str, chk_str)
63
63
64
64
65 @nt.with_setup(clean_dir, clean_dir)
65 @nt.with_setup(clean_dir, clean_dir)
66 def test_main_html():
66 def test_main_html():
67 """
67 """
68 Test main entry point
68 Test main entry point
69 """
69 """
70 main(fname, format='html')
70 main(fname, format='html')
71 nt.assert_true(os.path.exists('tests/test.html'))
71 nt.assert_true(os.path.exists('tests/test.html'))
General Comments 0
You need to be logged in to leave comments. Login now