##// END OF EJS Templates
stateless converter
Matthias BUSSONNIER -
Show More
@@ -1,227 +1,237 b''
1 1 """Base classes for the notebook conversion pipeline.
2 2
3 3 This module defines Converter, from which all objects designed to implement
4 4 a conversion of IPython notebooks to some other format should inherit.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012, the IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import print_function, absolute_import
19 19 import converters.transformers as trans
20 20 from converters.jinja_filters import (python_comment, indent,
21 21 rm_fake, remove_ansi, markdown, highlight,
22 22 ansi2html, markdown2latex, escape_tex)
23 23
24 24
25 25
26 26 # Stdlib imports
27 27 import io
28 28 import os
29 29 from IPython.utils import path
30 30 from IPython.utils.traitlets import MetaHasTraits
31 31
32 32 from jinja2 import Environment, FileSystemLoader
33 33 env = Environment(
34 34 loader=FileSystemLoader([
35 35 './templates/',
36 36 './templates/skeleton/',
37 37 ]),
38 38 extensions=['jinja2.ext.loopcontrols']
39 39 )
40 40
41 41 texenv = Environment(
42 42 loader=FileSystemLoader([
43 43 './templates/tex/',
44 44 './templates/skeleton/tex/',
45 45 ]),
46 46 extensions=['jinja2.ext.loopcontrols']
47 47 )
48 48
49 49 # IPython imports
50 50 from IPython.nbformat import current as nbformat
51 51 from IPython.config.configurable import Configurable
52 52 from IPython.utils.traitlets import ( Unicode, Any, List, Bool)
53 53
54 54 #-----------------------------------------------------------------------------
55 55 # Class declarations
56 56 #-----------------------------------------------------------------------------
57 57 class ConversionException(Exception):
58 58 pass
59 59
60
60 #todo move this out
61 61 def header_body():
62 62 """Return the body of the header as a list of strings."""
63 63
64 64 from pygments.formatters import HtmlFormatter
65 65
66 66 header = []
67 67 static = os.path.join(path.get_ipython_package_dir(),
68 68 'frontend', 'html', 'notebook', 'static',
69 69 )
70 70 here = os.path.split(os.path.realpath(__file__))[0]
71 71 css = os.path.join(static, 'css')
72 72 for sheet in [
73 73 # do we need jquery and prettify?
74 74 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
75 75 # 'jquery-ui.min.css'),
76 76 # os.path.join(static, 'prettify', 'prettify.css'),
77 77 os.path.join(css, 'boilerplate.css'),
78 78 os.path.join(css, 'fbm.css'),
79 79 os.path.join(css, 'notebook.css'),
80 80 os.path.join(css, 'renderedhtml.css'),
81 81 # our overrides:
82 82 os.path.join(here, '..', 'css', 'static_html.css'),
83 83 ]:
84 84
85 85 with io.open(sheet, encoding='utf-8') as f:
86 86 s = f.read()
87 87 header.append(s)
88 88
89 89 pygments_css = HtmlFormatter().get_style_defs('.highlight')
90 90 header.append(pygments_css)
91 91 return header
92 92
93 93
94 94
95 95
96 96
97 97 inlining = {}
98 98 inlining['css'] = header_body()
99 99
100 100
101 101
102 102 texenv.block_start_string = '((*'
103 103 texenv.block_end_string = '*))'
104 104 texenv.variable_start_string = '((('
105 105 texenv.variable_end_string = ')))'
106 106 texenv.comment_start_string = '((='
107 107 texenv.comment_end_string = '=))'
108 108 texenv.filters['escape_tex'] = escape_tex
109 109
110 110
111 111 class ConverterTemplate(Configurable):
112 """ A Jinja2 base converter templates"""
112 """ A Jinja2 base converter templates
113
114 Preprocess the ipynb files, feed it throug jinja templates,
115 and spit an converted files and a data object with other data
116
117 shoudl be mostly configurable
118 """
113 119
114 120 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
115 121 config=True,
116 122 help= """
117 123 An ordered list of prefered output type, the first
118 124 encounterd will usually be used when converting discarding
119 125 the others.
120 126 """
121 127 )
122 128
123 pre_transformer_order = List(['haspyout_transformer', 'Foobar'],
129 pre_transformer_order = List(['haspyout_transformer'],
124 130 config=True,
125 131 help= """
126 132 An ordered list of pre transformer to apply to the ipynb
127 133 file befor running through templates
128 134 """
129 135 )
130 136
131 137 extract_figures = Bool(False,
132 138 config=True,
133 139 help= """
134 140 wether to remove figure data from ipynb and store them in auxiliary
135 141 dictionnary
136 142 """
137 143 )
138 144
139 145 tex_environement = Bool(False,
140 146 config=True,
141 147 help=""" is this a tex environment or not """)
142 148
143 149 template_file = Unicode('',
144 150 config=True,
145 help=""" whetever """ )
151 help=""" Name of the template file to use """ )
146 152 #-------------------------------------------------------------------------
147 153 # Instance-level attributes that are set in the constructor for this
148 154 # class.
149 155 #-------------------------------------------------------------------------
150 156 infile = Any()
151 157
152 158
153 159 infile_dir = Unicode()
154 160
161 #todo: move to filter
155 162 def filter_data_type(self, output):
163 """ return the first availlable format in priority """
156 164 for fmt in self.display_data_priority:
157 165 if fmt in output:
158 166 return [fmt]
159 167
160 def __init__(self, preprocessors=[], config=None, **kw):
168 preprocessors = []
169
170 def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
161 171 """
162 172 config: the Configurable confg object to pass around
163 173
164 preprocessors: list of function to run on ipynb json data before conversion
174 preprocessors: dict of **availlable** key/value function to run on ipynb json data before conversion
165 175 to extract/inline file,
166 176
167 177 """
168 178 super(ConverterTemplate, self).__init__(config=config, **kw)
169 179 self.env = texenv if self.tex_environement else env
170 180 self.ext = '.tplx' if self.tex_environement else '.tpl'
171 self.nb = None
172 self.preprocessors = preprocessors
173 181
174 182 for name in self.pre_transformer_order:
175 tr = getattr(trans, name)
176 if isinstance(tr, MetaHasTraits):
177 tr = tr(config=config)
178 self.preprocessors.append(tr)
183 transformer = getattr(preprocessors, name, getattr(trans, name, None))
184 if isinstance(transformer, MetaHasTraits):
185 transformer = transformer(config=config)
186 self.preprocessors.append(transformer)
187
188 ## for compat, remove later
179 189 if self.extract_figures:
180 190 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
181 191
192 ##
182 193 self.env.filters['filter_data_type'] = self.filter_data_type
183 194 self.env.filters['pycomment'] = python_comment
184 195 self.env.filters['indent'] = indent
185 196 self.env.filters['rm_fake'] = rm_fake
186 197 self.env.filters['rm_ansi'] = remove_ansi
187 198 self.env.filters['markdown'] = markdown
188 199 self.env.filters['highlight'] = highlight
189 200 self.env.filters['ansi2html'] = ansi2html
190 201 self.env.filters['markdown2latex'] = markdown2latex
202 for k, v in jinja_filters.iteritems():
203 self.env.filters[k] = v
191 204
192 205 self.template = self.env.get_template(self.template_file+self.ext)
193 206
194 207
195 def process(self):
208 def process(self, nb):
196 209 """
197 210 preprocess the notebook json for easier use with the templates.
198 211 will call all the `preprocessor`s in order before returning it.
199 212 """
200 nb = self.nb
201 213
202 214 # dict of 'resources' that could be made by the preprocessors
203 215 # like key/value data to extract files from ipynb like in latex conversion
204 216 resources = {}
205 217
206 218 for preprocessor in self.preprocessors:
207 219 nb, resources = preprocessor(nb, resources)
208 220
209 221 return nb, resources
210 222
211 def convert(self):
223 def convert(self, nb):
212 224 """ convert the ipynb file
213 225
214 226 return both the converted ipynb file and a dict containing potential
215 227 other resources
216 228 """
217 nb, resources = self.process()
229 nb, resources = self.process(nb)
218 230 return self.template.render(nb=nb, inlining=inlining), resources
219 231
220 232
221 def read(self, filename):
233 def from_filename(self, filename):
222 234 "read and parse notebook into NotebookNode called self.nb"
223 235 with io.open(filename) as f:
224 self.nb = nbformat.read(f, 'json')
225
226
236 return self.convert(nbformat.read(f, 'json'))
227 237
@@ -1,137 +1,136 b''
1 1 #!/usr/bin/env python
2 2 """
3 3 ================================================================================
4 4
5 5 |,---. | | , .| |
6 6 ||---', .|--- |---.,---.,---. |\ ||---.,---.,---.,---.. ,,---.,---.|---
7 7 || | || | || || | | \ || || | || | \ / |---'| |
8 8 `` `---|`---'` '`---'` ' ` `'`---'`---'`---'` ' `' `---'` `---'
9 9 `---'
10 10 ================================================================================
11 11
12 12 Highly experimental for now
13 13
14 14 """
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18 from __future__ import print_function
19 19 import sys
20 20 import io
21 21 import os
22 22
23 23 from converters.template import *
24 24 from converters.template import ConverterTemplate
25 25 from converters.html import ConverterHTML
26 26 # From IPython
27 27
28 28 # All the stuff needed for the configurable things
29 29 from IPython.config.application import Application
30 30 from IPython.config.loader import ConfigFileNotFound
31 31 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, CaselessStrEnum
32 32
33 33 from converters.transformers import (ConfigurableTransformers,Foobar,ExtractFigureTransformer)
34 34
35 35
36 36 class NbconvertApp(Application):
37 37
38 38 stdout = Bool(True, config=True)
39 39 write = Bool(False, config=True)
40 40
41 41 fileext = Unicode('txt', config=True)
42 42
43 43 aliases = {
44 44 'stdout':'NbconvertApp.stdout',
45 45 'write':'NbconvertApp.write',
46 46 }
47 47
48 48 flags= {}
49 49 flags['no-stdout'] = (
50 50 {'NbconvertApp' : {'stdout' : False}},
51 51 """the doc for this flag
52 52
53 53 """
54 54 )
55 55
56 56 def __init__(self, **kwargs):
57 57 super(NbconvertApp, self).__init__(**kwargs)
58 58 self.classes.insert(0,ConverterTemplate)
59 59 # register class here to have help with help all
60 60 self.classes.insert(0,ExtractFigureTransformer)
61 61 self.classes.insert(0,Foobar)
62 62 # ensure those are registerd
63 63
64 64 def load_config_file(self, profile_name):
65 65 try:
66 66 Application.load_config_file(
67 67 self,
68 68 profile_name+'.nbcv',
69 69 path=[os.path.join(os.getcwdu(),'profile')]
70 70 )
71 71 except ConfigFileNotFound:
72 72 self.log.warn("Config file for profile '%s' not found, giving up ",profile_name)
73 73 exit(1)
74 74
75 75
76 76 def initialize(self, argv=None):
77 77 self.parse_command_line(argv)
78 78 cl_config = self.config
79 79 profile_file = sys.argv[1]
80 80 self.load_config_file(profile_file)
81 81 self.update_config(cl_config)
82 82
83 83
84 84
85 85 def run(self):
86 86 """Convert a notebook to html in one step"""
87 87 template_file = (self.extra_args or [None])[0]
88 88 ipynb_file = (self.extra_args or [None])[1]
89 89
90 90 template_file = sys.argv[1]
91 91
92 92 C = ConverterTemplate(config=self.config)
93 C.read(ipynb_file)
94 93
95 output,resources = C.convert()
94 output,resources = C.from_filename(ipynb_file)
96 95 if self.stdout :
97 96 print(output.encode('utf-8'))
98 97
99 98 out_root = ipynb_file[:-6].replace('.','_').replace(' ','_')
100 99
101 100 keys = resources.get('figures',{}).keys()
102 101 if self.write :
103 102 with io.open(os.path.join(out_root+'.'+self.fileext),'w') as f:
104 103 f.write(output)
105 104 if keys :
106 105 if self.write and not os.path.exists(out_root+'_files'):
107 106 os.mkdir(out_root+'_files')
108 107 for key in keys:
109 108 if self.write:
110 109 with io.open(os.path.join(out_root+'_files',key),'wb') as f:
111 110 print(' writing to ',os.path.join(out_root,key))
112 111 f.write(resources['figures'][key])
113 112 if self.stdout:
114 113 print('''
115 114 ====================== Keys in Resources ==================================
116 115 ''')
117 116 print(resources['figures'].keys())
118 117 print("""
119 118 ===========================================================================
120 119 you are responsible from writing those data do a file in the right place if
121 120 they need to be.
122 121 ===========================================================================
123 122 """)
124 123
125 124 def main():
126 125 """Convert a notebook to html in one step"""
127 126 app = NbconvertApp.instance()
128 127 app.description = __doc__
129 128 app.initialize()
130 129 app.start()
131 130 app.run()
132 131 #-----------------------------------------------------------------------------
133 132 # Script main
134 133 #-----------------------------------------------------------------------------
135 134
136 135 if __name__ == '__main__':
137 136 main()
@@ -1,30 +1,29 b''
1 1 import io
2 2 import nose.tools as nt
3 3 import os
4 4 from nose.tools import nottest
5 5 from converters.template import ConverterTemplate
6 6 from IPython.config.loader import PyFileConfigLoader
7 7
8 8
9 9
10 10
11 11 def test_evens():
12 12 reflist = [
13 13 'tests/ipynbref/IntroNumPy.orig'
14 14 ]
15 15
16 16 test_profiles = [prof for prof in os.listdir('profile/test/') if prof.endswith('.py')]
17 17
18 18 ### null template should return empty
19 19 for prof in test_profiles :
20 20 yield check_null_profile,prof
21 21 ### end null test
22 22
23 23 def check_null_profile(profile):
24 24 loader = PyFileConfigLoader(profile, path=[os.path.join(os.getcwdu(),'profile/test')])
25 25 config = loader.load_config()
26 26 C = ConverterTemplate(config=config)
27 C.read('tests/ipynbref/IntroNumPy.orig.ipynb')
28 result,_ = C.convert()
27 result,_ = C.from_filename('tests/ipynbref/IntroNumPy.orig.ipynb')
29 28 nt.assert_equal(result,'')
30 29
General Comments 0
You need to be logged in to leave comments. Login now