##// END OF EJS Templates
Start to organize template folder
Matthias BUSSONNIER -
Show More
@@ -1,281 +1,287
1 """Base classes for the notebook conversion pipeline.
1 """Base classes for the notebook conversion pipeline.
2
2
3 This module defines Converter, from which all objects designed to implement
3 This module defines Converter, from which all objects designed to implement
4 a conversion of IPython notebooks to some other format should inherit.
4 a conversion of IPython notebooks to some other format should inherit.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2012, the IPython Development Team.
7 # Copyright (c) 2012, the IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import print_function, absolute_import
18 from __future__ import print_function, absolute_import
19
19
20 # Stdlib imports
20 # Stdlib imports
21 import io
21 import io
22 import os
22 import os
23 import re
23 import re
24 from IPython.utils import path
24 from IPython.utils import path
25
25
26 from jinja2 import Environment, FileSystemLoader
26 from jinja2 import Environment, FileSystemLoader
27 env = Environment(
27 env = Environment(
28 loader=FileSystemLoader('./templates/'),
28 loader=FileSystemLoader([
29 './templates/',
30 './templates/skeleton/',
31 ]),
29 extensions=['jinja2.ext.loopcontrols']
32 extensions=['jinja2.ext.loopcontrols']
30 )
33 )
31
34
32 texenv = Environment(
35 texenv = Environment(
33 loader=FileSystemLoader('./templates/tex/'),
36 loader=FileSystemLoader([
37 './templates/tex/',
38 './templates/skeleton/tex/',
39 ]),
34 extensions=['jinja2.ext.loopcontrols']
40 extensions=['jinja2.ext.loopcontrols']
35 )
41 )
36
42
37 # IPython imports
43 # IPython imports
38 from IPython.nbformat import current as nbformat
44 from IPython.nbformat import current as nbformat
39 from IPython.config.configurable import Configurable
45 from IPython.config.configurable import Configurable
40 from IPython.utils.traitlets import ( Unicode, Any, List, Bool)
46 from IPython.utils.traitlets import ( Unicode, Any, List, Bool)
41
47
42 # Our own imports
48 # Our own imports
43 from IPython.utils.text import indent
49 from IPython.utils.text import indent
44 from .utils import remove_ansi
50 from .utils import remove_ansi
45 from markdown import markdown
51 from markdown import markdown
46 from .utils import highlight, ansi2html
52 from .utils import highlight, ansi2html
47 from .utils import markdown2latex
53 from .utils import markdown2latex
48 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
49 # Class declarations
55 # Class declarations
50 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
51 def rm_fake(strng):
57 def rm_fake(strng):
52 return strng.replace('/files/', '')
58 return strng.replace('/files/', '')
53
59
54 class ConversionException(Exception):
60 class ConversionException(Exception):
55 pass
61 pass
56
62
57
63
58 def python_comment(string):
64 def python_comment(string):
59 return '# '+'\n# '.join(string.split('\n'))
65 return '# '+'\n# '.join(string.split('\n'))
60
66
61
67
62
68
63 def header_body():
69 def header_body():
64 """Return the body of the header as a list of strings."""
70 """Return the body of the header as a list of strings."""
65
71
66 from pygments.formatters import HtmlFormatter
72 from pygments.formatters import HtmlFormatter
67
73
68 header = []
74 header = []
69 static = os.path.join(path.get_ipython_package_dir(),
75 static = os.path.join(path.get_ipython_package_dir(),
70 'frontend', 'html', 'notebook', 'static',
76 'frontend', 'html', 'notebook', 'static',
71 )
77 )
72 here = os.path.split(os.path.realpath(__file__))[0]
78 here = os.path.split(os.path.realpath(__file__))[0]
73 css = os.path.join(static, 'css')
79 css = os.path.join(static, 'css')
74 for sheet in [
80 for sheet in [
75 # do we need jquery and prettify?
81 # do we need jquery and prettify?
76 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
82 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
77 # 'jquery-ui.min.css'),
83 # 'jquery-ui.min.css'),
78 # os.path.join(static, 'prettify', 'prettify.css'),
84 # os.path.join(static, 'prettify', 'prettify.css'),
79 os.path.join(css, 'boilerplate.css'),
85 os.path.join(css, 'boilerplate.css'),
80 os.path.join(css, 'fbm.css'),
86 os.path.join(css, 'fbm.css'),
81 os.path.join(css, 'notebook.css'),
87 os.path.join(css, 'notebook.css'),
82 os.path.join(css, 'renderedhtml.css'),
88 os.path.join(css, 'renderedhtml.css'),
83 # our overrides:
89 # our overrides:
84 os.path.join(here, '..', 'css', 'static_html.css'),
90 os.path.join(here, '..', 'css', 'static_html.css'),
85 ]:
91 ]:
86
92
87 with io.open(sheet, encoding='utf-8') as f:
93 with io.open(sheet, encoding='utf-8') as f:
88 s = f.read()
94 s = f.read()
89 header.append(s)
95 header.append(s)
90
96
91 pygments_css = HtmlFormatter().get_style_defs('.highlight')
97 pygments_css = HtmlFormatter().get_style_defs('.highlight')
92 header.append(pygments_css)
98 header.append(pygments_css)
93 return header
99 return header
94
100
95 # todo, make the key part configurable.
101 # todo, make the key part configurable.
96 def _new_figure(data, fmt, count):
102 def _new_figure(data, fmt, count):
97 """Create a new figure file in the given format.
103 """Create a new figure file in the given format.
98
104
99 Returns a path relative to the input file.
105 Returns a path relative to the input file.
100 """
106 """
101 figname = '_fig_%02i.%s' % (count, fmt)
107 figname = '_fig_%02i.%s' % (count, fmt)
102
108
103 # Binary files are base64-encoded, SVG is already XML
109 # Binary files are base64-encoded, SVG is already XML
104 if fmt in ('png', 'jpg', 'pdf'):
110 if fmt in ('png', 'jpg', 'pdf'):
105 data = data.decode('base64')
111 data = data.decode('base64')
106
112
107 return figname,data
113 return figname,data
108
114
109
115
110
116
111
117
112 inlining = {}
118 inlining = {}
113 inlining['css'] = header_body()
119 inlining['css'] = header_body()
114
120
115 LATEX_SUBS = (
121 LATEX_SUBS = (
116 (re.compile(r'\\'), r'\\textbackslash'),
122 (re.compile(r'\\'), r'\\textbackslash'),
117 (re.compile(r'([{}_#%&$])'), r'\\\1'),
123 (re.compile(r'([{}_#%&$])'), r'\\\1'),
118 (re.compile(r'~'), r'\~{}'),
124 (re.compile(r'~'), r'\~{}'),
119 (re.compile(r'\^'), r'\^{}'),
125 (re.compile(r'\^'), r'\^{}'),
120 (re.compile(r'"'), r"''"),
126 (re.compile(r'"'), r"''"),
121 (re.compile(r'\.\.\.+'), r'\\ldots'),
127 (re.compile(r'\.\.\.+'), r'\\ldots'),
122 )
128 )
123
129
124 def escape_tex(value):
130 def escape_tex(value):
125 newval = value
131 newval = value
126 for pattern, replacement in LATEX_SUBS:
132 for pattern, replacement in LATEX_SUBS:
127 newval = pattern.sub(replacement, newval)
133 newval = pattern.sub(replacement, newval)
128 return newval
134 return newval
129
135
130 texenv.block_start_string = '((*'
136 texenv.block_start_string = '((*'
131 texenv.block_end_string = '*))'
137 texenv.block_end_string = '*))'
132 texenv.variable_start_string = '((('
138 texenv.variable_start_string = '((('
133 texenv.variable_end_string = ')))'
139 texenv.variable_end_string = ')))'
134 texenv.comment_start_string = '((='
140 texenv.comment_start_string = '((='
135 texenv.comment_end_string = '=))'
141 texenv.comment_end_string = '=))'
136 texenv.filters['escape_tex'] = escape_tex
142 texenv.filters['escape_tex'] = escape_tex
137
143
138 def cell_preprocessor(function):
144 def cell_preprocessor(function):
139 """ wrap a function to be executed on all cells of a notebook
145 """ wrap a function to be executed on all cells of a notebook
140
146
141 wrapped function parameters :
147 wrapped function parameters :
142 cell : the cell
148 cell : the cell
143 other : external resources
149 other : external resources
144 index : index of the cell
150 index : index of the cell
145 """
151 """
146 def wrappedfunc(nb,other):
152 def wrappedfunc(nb,other):
147 for worksheet in nb.worksheets :
153 for worksheet in nb.worksheets :
148 for index, cell in enumerate(worksheet.cells):
154 for index, cell in enumerate(worksheet.cells):
149 worksheet.cells[index],other= function(cell,other,index)
155 worksheet.cells[index],other= function(cell,other,index)
150 return nb,other
156 return nb,other
151 return wrappedfunc
157 return wrappedfunc
152
158
153
159
154
160
155 @cell_preprocessor
161 @cell_preprocessor
156 def haspyout_transformer(cell, other, count):
162 def haspyout_transformer(cell, other, count):
157 """
163 """
158 Add a haspyout flag to cell that have it
164 Add a haspyout flag to cell that have it
159
165
160 Easier for templating, where you can't know in advance
166 Easier for templating, where you can't know in advance
161 wether to write the out prompt
167 wether to write the out prompt
162
168
163 """
169 """
164 cell.type = cell.cell_type
170 cell.type = cell.cell_type
165 cell.haspyout = False
171 cell.haspyout = False
166 for out in cell.get('outputs', []):
172 for out in cell.get('outputs', []):
167 if out.output_type == 'pyout':
173 if out.output_type == 'pyout':
168 cell.haspyout = True
174 cell.haspyout = True
169 break
175 break
170 return cell,other
176 return cell,other
171
177
172
178
173 @cell_preprocessor
179 @cell_preprocessor
174 def extract_figure_transformer(cell,other,count):
180 def extract_figure_transformer(cell,other,count):
175 for i,out in enumerate(cell.get('outputs', [])):
181 for i,out in enumerate(cell.get('outputs', [])):
176 for type in ['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg']:
182 for type in ['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg']:
177 if out.hasattr(type):
183 if out.hasattr(type):
178 figname,data = _new_figure(out[type], type,count)
184 figname,data = _new_figure(out[type], type,count)
179 cell.outputs[i][type] = figname
185 cell.outputs[i][type] = figname
180 out['key_'+type] = figname
186 out['key_'+type] = figname
181 other[figname] = data
187 other[figname] = data
182 count = count+1
188 count = count+1
183 return cell,other
189 return cell,other
184
190
185
191
186 class ConverterTemplate(Configurable):
192 class ConverterTemplate(Configurable):
187 """ A Jinja2 base converter templates"""
193 """ A Jinja2 base converter templates"""
188
194
189 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
195 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
190 config=True,
196 config=True,
191 help= """
197 help= """
192 A list of ast.NodeTransformer subclass instances, which will be applied
198 A list of ast.NodeTransformer subclass instances, which will be applied
193 to user input before code is run.
199 to user input before code is run.
194 """
200 """
195 )
201 )
196
202
197 extract_figures = Bool(False,
203 extract_figures = Bool(False,
198 config=True,
204 config=True,
199 help= """
205 help= """
200 wether to remove figure data from ipynb and store them in auxiliary
206 wether to remove figure data from ipynb and store them in auxiliary
201 dictionnary
207 dictionnary
202 """
208 """
203 )
209 )
204 #-------------------------------------------------------------------------
210 #-------------------------------------------------------------------------
205 # Instance-level attributes that are set in the constructor for this
211 # Instance-level attributes that are set in the constructor for this
206 # class.
212 # class.
207 #-------------------------------------------------------------------------
213 #-------------------------------------------------------------------------
208 infile = Any()
214 infile = Any()
209
215
210
216
211 infile_dir = Unicode()
217 infile_dir = Unicode()
212
218
213 def filter_data_type(self,output):
219 def filter_data_type(self,output):
214 for fmt in self.display_data_priority:
220 for fmt in self.display_data_priority:
215 if fmt in output:
221 if fmt in output:
216 return [fmt]
222 return [fmt]
217
223
218 def __init__(self, tplfile='fullhtml', preprocessors=[], config=None,tex_environement=False, **kw):
224 def __init__(self, tplfile='fullhtml', preprocessors=[], config=None,tex_environement=False, **kw):
219 """
225 """
220 tplfile : jinja template file to process.
226 tplfile : jinja template file to process.
221
227
222 config: the Configurable confg object to pass around
228 config: the Configurable confg object to pass around
223
229
224 preprocessors: list of function to run on ipynb json data before conversion
230 preprocessors: list of function to run on ipynb json data before conversion
225 to extract/inline file,
231 to extract/inline file,
226
232
227 """
233 """
228 super(ConverterTemplate, self).__init__(config=config, **kw)
234 super(ConverterTemplate, self).__init__(config=config, **kw)
229 self.env = texenv if tex_environement else env
235 self.env = texenv if tex_environement else env
230 self.ext = '.tplx' if tex_environement else '.tpl'
236 self.ext = '.tplx' if tex_environement else '.tpl'
231 self.nb = None
237 self.nb = None
232 self.preprocessors = preprocessors
238 self.preprocessors = preprocessors
233 self.preprocessors.append(haspyout_transformer)
239 self.preprocessors.append(haspyout_transformer)
234 if self.extract_figures:
240 if self.extract_figures:
235 self.preprocessors.append(extract_figure_transformer)
241 self.preprocessors.append(extract_figure_transformer)
236
242
237 self.env.filters['filter_data_type'] = self.filter_data_type
243 self.env.filters['filter_data_type'] = self.filter_data_type
238 self.env.filters['pycomment'] = python_comment
244 self.env.filters['pycomment'] = python_comment
239 self.env.filters['indent'] = indent
245 self.env.filters['indent'] = indent
240 self.env.filters['rm_fake'] = rm_fake
246 self.env.filters['rm_fake'] = rm_fake
241 self.env.filters['rm_ansi'] = remove_ansi
247 self.env.filters['rm_ansi'] = remove_ansi
242 self.env.filters['markdown'] = markdown
248 self.env.filters['markdown'] = markdown
243 self.env.filters['highlight'] = highlight
249 self.env.filters['highlight'] = highlight
244 self.env.filters['ansi2html'] = ansi2html
250 self.env.filters['ansi2html'] = ansi2html
245 self.env.filters['markdown2latex'] = markdown2latex
251 self.env.filters['markdown2latex'] = markdown2latex
246
252
247 self.template = self.env.get_template(tplfile+self.ext)
253 self.template = self.env.get_template(tplfile+self.ext)
248
254
249
255
250
256
251 def process(self):
257 def process(self):
252 """
258 """
253 preprocess the notebook json for easier use with the templates.
259 preprocess the notebook json for easier use with the templates.
254 will call all the `preprocessor`s in order before returning it.
260 will call all the `preprocessor`s in order before returning it.
255 """
261 """
256 nb = self.nb
262 nb = self.nb
257
263
258 # dict of 'resources' that could be made by the preprocessors
264 # dict of 'resources' that could be made by the preprocessors
259 # like key/value data to extract files from ipynb like in latex conversion
265 # like key/value data to extract files from ipynb like in latex conversion
260 resources = {}
266 resources = {}
261
267
262 for preprocessor in self.preprocessors:
268 for preprocessor in self.preprocessors:
263 nb,resources = preprocessor(nb,resources)
269 nb,resources = preprocessor(nb,resources)
264
270
265 return nb, resources
271 return nb, resources
266
272
267 def convert(self):
273 def convert(self):
268 """ convert the ipynb file
274 """ convert the ipynb file
269
275
270 return both the converted ipynb file and a dict containing potential
276 return both the converted ipynb file and a dict containing potential
271 other resources
277 other resources
272 """
278 """
273 nb,resources = self.process()
279 nb,resources = self.process()
274 return self.template.render(nb=nb, inlining=inlining), resources
280 return self.template.render(nb=nb, inlining=inlining), resources
275
281
276
282
277 def read(self, filename):
283 def read(self, filename):
278 "read and parse notebook into NotebookNode called self.nb"
284 "read and parse notebook into NotebookNode called self.nb"
279 with io.open(filename) as f:
285 with io.open(filename) as f:
280 self.nb = nbformat.read(f, 'json')
286 self.nb = nbformat.read(f, 'json')
281
287
1 NO CONTENT: file renamed from templates/Makefile to templates/skeleton/Makefile
NO CONTENT: file renamed from templates/Makefile to templates/skeleton/Makefile
1 NO CONTENT: file renamed from templates/display_priority.tpl to templates/skeleton/display_priority.tpl
NO CONTENT: file renamed from templates/display_priority.tpl to templates/skeleton/display_priority.tpl
1 NO CONTENT: file renamed from templates/null.tpl to templates/skeleton/null.tpl
NO CONTENT: file renamed from templates/null.tpl to templates/skeleton/null.tpl
General Comments 0
You need to be logged in to leave comments. Login now