##// END OF EJS Templates
allow configurable filters
Matthias BUSSONNIER -
Show More
@@ -1,42 +1,88 b''
1 1 #-----------------------------------------------------------------------------
2 2 # Copyright (c) 2012, the IPython Development Team.
3 3 #
4 4 # Distributed under the terms of the Modified BSD License.
5 5 #
6 6 # The full license is in the file COPYING.txt, distributed with this software.
7 7 #-----------------------------------------------------------------------------
8 8
9 9 from __future__ import absolute_import
10 10
11 11 # Stdlib imports
12 12 import re
13 13
14 14 from IPython.utils.text import indent
15 15 from markdown import markdown
16 16 from .utils import remove_ansi
17 17 from .utils import highlight, ansi2html
18 18 from .utils import markdown2latex
19
20 from IPython.config.configurable import Configurable
21 from IPython.utils.traitlets import Unicode, Bool, Dict, List
22
19 23 #-----------------------------------------------------------------------------
20 24 # Class declarations
21 25 #-----------------------------------------------------------------------------
26
27 class GlobalConfigurable(Configurable):
28 """Global configurable class for shared config
29
30 Usefull for display data priority that might be use by many trasnformers
31 """
32
33 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
34 config=True,
35 help= """
36 An ordered list of prefered output type, the first
37 encounterd will usually be used when converting discarding
38 the others.
39 """
40 )
41
42 def __init__(self, config=None, **kw):
43 super(GlobalConfigurable, self).__init__( config=config, **kw)
44
45 class ConfigurableFilter(GlobalConfigurable):
46 """Configurable Jinja Filter"""
47
48 def __init__(self, config=None, **kw):
49 super(ConfigurableFilter, self).__init__(config=config, **kw)
50
51 def __call__(self, *args, **kwargs):
52 raise NotImplementedError('should be implemented by subclass')
53
54
55 class FilterDataType(ConfigurableFilter):
56 """ return the preferd displayed format
57 """
58
59 def __call__(self, output):
60 """ return the first availlable format in priority """
61 for fmt in self.display_data_priority:
62 if fmt in output:
63 return [fmt]
64 raise Exception("did not found any format I can extract in output, shoudl at lest have one")
65
66
67
22 68 def rm_fake(strng):
23 69 return strng.replace('/files/', '')
24 70
25 71 def python_comment(string):
26 72 return '# '+'\n# '.join(string.split('\n'))
27 73
28 74 LATEX_SUBS = (
29 75 (re.compile(r'\\'), r'\\textbackslash'),
30 76 (re.compile(r'([{}_#%&$])'), r'\\\1'),
31 77 (re.compile(r'~'), r'\~{}'),
32 78 (re.compile(r'\^'), r'\^{}'),
33 79 (re.compile(r'"'), r"''"),
34 80 (re.compile(r'\.\.\.+'), r'\\ldots'),
35 81 )
36 82
37 83 def escape_tex(value):
38 84 newval = value
39 85 for pattern, replacement in LATEX_SUBS:
40 86 newval = pattern.sub(replacement, newval)
41 87 return newval
42 88
@@ -1,242 +1,230 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 ansi2html, markdown2latex, escape_tex)
22 ansi2html, markdown2latex, escape_tex, FilterDataType)
23 23
24 24 from converters.utils import markdown2rst
25 25
26 26
27 27
28 28 # Stdlib imports
29 29 import io
30 30 import os
31 31 from IPython.utils import path
32 32 from IPython.utils.traitlets import MetaHasTraits
33 33
34 34 from jinja2 import Environment, FileSystemLoader
35 35 env = Environment(
36 36 loader=FileSystemLoader([
37 37 './templates/',
38 38 './templates/skeleton/',
39 39 ]),
40 40 extensions=['jinja2.ext.loopcontrols']
41 41 )
42 42
43 43 texenv = Environment(
44 44 loader=FileSystemLoader([
45 45 './templates/tex/',
46 46 './templates/skeleton/tex/',
47 47 ]),
48 48 extensions=['jinja2.ext.loopcontrols']
49 49 )
50 50
51 51 # IPython imports
52 52 from IPython.nbformat import current as nbformat
53 53 from IPython.config.configurable import Configurable
54 54 from IPython.utils.traitlets import ( Unicode, Any, List, Bool)
55 55
56 56 #-----------------------------------------------------------------------------
57 57 # Class declarations
58 58 #-----------------------------------------------------------------------------
59 59 class ConversionException(Exception):
60 60 pass
61 61
62 62 #todo move this out
63 63 def header_body():
64 64 """Return the body of the header as a list of strings."""
65 65
66 66 from pygments.formatters import HtmlFormatter
67 67
68 68 header = []
69 69 static = os.path.join(path.get_ipython_package_dir(),
70 70 'frontend', 'html', 'notebook', 'static',
71 71 )
72 72 here = os.path.split(os.path.realpath(__file__))[0]
73 73 css = os.path.join(static, 'css')
74 74 for sheet in [
75 75 # do we need jquery and prettify?
76 76 # os.path.join(static, 'jquery', 'css', 'themes', 'base',
77 77 # 'jquery-ui.min.css'),
78 78 # os.path.join(static, 'prettify', 'prettify.css'),
79 79 os.path.join(css, 'boilerplate.css'),
80 80 os.path.join(css, 'fbm.css'),
81 81 os.path.join(css, 'notebook.css'),
82 82 os.path.join(css, 'renderedhtml.css'),
83 os.path.join(css, 'style.min.css'),
83 84 # our overrides:
84 85 os.path.join(here, '..', 'css', 'static_html.css'),
85 86 ]:
86
87 try:
87 88 with io.open(sheet, encoding='utf-8') as f:
88 89 s = f.read()
89 90 header.append(s)
91 except IOError:
92 # new version of ipython with style.min.css, pass
93 pass
90 94
91 95 pygments_css = HtmlFormatter().get_style_defs('.highlight')
92 96 header.append(pygments_css)
93 97 return header
94 98
95 99
96 100
97 101
98 102
99 103 inlining = {}
100 104 inlining['css'] = header_body()
101 105
102 106
103 107
104 108 texenv.block_start_string = '((*'
105 109 texenv.block_end_string = '*))'
110
106 111 texenv.variable_start_string = '((('
107 112 texenv.variable_end_string = ')))'
113
108 114 texenv.comment_start_string = '((='
109 115 texenv.comment_end_string = '=))'
116
110 117 texenv.filters['escape_tex'] = escape_tex
111 118
112 119
113 120 class ConverterTemplate(Configurable):
114 121 """ A Jinja2 base converter templates
115 122
116 123 Preprocess the ipynb files, feed it throug jinja templates,
117 124 and spit an converted files and a data object with other data
118 125
119 126 shoudl be mostly configurable
120 127 """
121 128
122 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
123 config=True,
124 help= """
125 An ordered list of prefered output type, the first
126 encounterd will usually be used when converting discarding
127 the others.
128 """
129 )
130
131 129 pre_transformer_order = List(['haspyout_transformer'],
132 130 config=True,
133 131 help= """
134 132 An ordered list of pre transformer to apply to the ipynb
135 133 file befor running through templates
136 134 """
137 135 )
138 136
139 extract_figures = Bool(False,
140 config=True,
141 help= """
142 wether to remove figure data from ipynb and store them in auxiliary
143 dictionnary
144 """
145 )
146
147 137 tex_environement = Bool(False,
148 138 config=True,
149 139 help=""" is this a tex environment or not """)
150 140
151 141 template_file = Unicode('',
152 142 config=True,
153 143 help=""" Name of the template file to use """ )
154 144 #-------------------------------------------------------------------------
155 145 # Instance-level attributes that are set in the constructor for this
156 146 # class.
157 147 #-------------------------------------------------------------------------
158 infile = Any()
159
160
161 infile_dir = Unicode()
162 148
163 #todo: move to filter
164 def filter_data_type(self, output):
165 """ return the first availlable format in priority """
166 for fmt in self.display_data_priority:
167 if fmt in output:
168 return [fmt]
169 raise Exception("did not found any format I can extract in output, shoudl at lest have one")
170 149
171 150 preprocessors = []
172 151
173 152 def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
174 """
175 config: the Configurable confg object to pass around
153 """ Init a new converter.
154
155
156 config: the Configurable confgg object to pass around
176 157
177 preprocessors: dict of **availlable** key/value function to run on ipynb json data before conversion
178 to extract/inline file,
158 preprocessors: dict of **availlable** key/value function to run on
159 ipynb json data before conversion to extract/inline file,
160
161 jinja_filter : dict of supplementary jinja filter that should be made
162 availlable in template. If those are of Configurable Class type, they
163 will be instanciated with the config object as argument.
179 164
180 165 """
181 166 super(ConverterTemplate, self).__init__(config=config, **kw)
182 167 self.env = texenv if self.tex_environement else env
183 168 self.ext = '.tplx' if self.tex_environement else '.tpl'
184 169
185 170 for name in self.pre_transformer_order:
186 171 transformer = getattr(preprocessors, name, getattr(trans, name, None))
187 172 if isinstance(transformer, MetaHasTraits):
188 173 transformer = transformer(config=config)
189 174 self.preprocessors.append(transformer)
190 175
191 176 ## for compat, remove later
192 if self.extract_figures:
193 177 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
194 178 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
195 179
196 180 ##
197 self.env.filters['filter_data_type'] = self.filter_data_type
181 self.env.filters['filter_data_type'] = FilterDataType(config=config)
198 182 self.env.filters['pycomment'] = python_comment
199 183 self.env.filters['indent'] = indent
200 184 self.env.filters['rm_fake'] = rm_fake
201 185 self.env.filters['rm_ansi'] = remove_ansi
202 186 self.env.filters['markdown'] = markdown
203 187 self.env.filters['highlight'] = highlight
204 188 self.env.filters['ansi2html'] = ansi2html
205 189 self.env.filters['markdown2latex'] = markdown2latex
206 190 self.env.filters['markdown2rst'] = markdown2rst
207 for k, v in jinja_filters.iteritems():
208 self.env.filters[k] = v
191 for key, filtr in jinja_filters.iteritems():
192 if isinstance(filtr, MetaHasTraits):
193 self.env.filters[key] = filtr(config=config)
194 else :
195 self.env.filters[key] = filtr
209 196
210 197 self.template = self.env.get_template(self.template_file+self.ext)
211 198
212 199
213 200 def process(self, nb):
214 201 """
215 202 preprocess the notebook json for easier use with the templates.
216 203 will call all the `preprocessor`s in order before returning it.
217 204 """
218 205
219 206 # dict of 'resources' that could be made by the preprocessors
220 207 # like key/value data to extract files from ipynb like in latex conversion
221 208 resources = {}
222 209
223 210 for preprocessor in self.preprocessors:
224 211 nb, resources = preprocessor(nb, resources)
225 212
226 213 return nb, resources
227 214
228 215 def convert(self, nb):
229 216 """ convert the ipynb file
230 217
231 218 return both the converted ipynb file and a dict containing potential
232 219 other resources
233 220 """
234 221 nb, resources = self.process(nb)
235 222 return self.template.render(nb=nb, inlining=inlining), resources
236 223
237 224
238 225 def from_filename(self, filename):
239 226 "read and parse notebook into NotebookNode called self.nb"
240 227 with io.open(filename) as f:
241 228 return self.convert(nbformat.read(f, 'json'))
242 229
230
@@ -1,233 +1,225 b''
1 1 """
2 2
3 3 """
4 4
5 from __future__ import print_function
5 from __future__ import print_function, absolute_import
6 6
7 7 from IPython.config.configurable import Configurable
8 8 from IPython.utils.traitlets import Unicode, Bool, Dict, List
9 from .jinja_filters import GlobalConfigurable
9 10
10 class ConfigurableTransformers(Configurable):
11 class ConfigurableTransformers(GlobalConfigurable):
11 12 """ A configurable transformer """
12 13
13 14 def __init__(self, config=None, **kw):
14 15 super(ConfigurableTransformers, self).__init__(config=config, **kw)
15 16
16 17 def __call__(self, nb, other):
17 18 try :
18 19 for worksheet in nb.worksheets :
19 20 for index, cell in enumerate(worksheet.cells):
20 21 worksheet.cells[index], other = self.cell_transform(cell, other, index)
21 22 return nb, other
22 23 except NotImplementedError as error :
23 24 raise NotImplementedError('should be implemented by subclass')
24 25
25 26 def cell_transform(self, cell, other, index):
26 27 """
27 28 Overwrite if you want to apply a transformation on each cell
28 29 """
29 30 raise NotImplementedError('should be implemented by subclass')
30 31
31 32
32 33 class ActivatableTransformer(ConfigurableTransformers):
33 34
34 35 enabled = Bool(False, config=True)
35 36
36 37 def __call__(self, nb, other):
37 38 if not self.enabled :
38 39 return nb,other
39 40 else :
40 41 return super(ActivatableTransformer,self).__call__(nb, other)
41 42
42 43
43 44 def cell_preprocessor(function):
44 45 """ wrap a function to be executed on all cells of a notebook
45 46
46 47 wrapped function parameters :
47 48 cell : the cell
48 49 other : external resources
49 50 index : index of the cell
50 51 """
51 52 def wrappedfunc(nb, other):
52 53 for worksheet in nb.worksheets :
53 54 for index, cell in enumerate(worksheet.cells):
54 55 worksheet.cells[index], other = function(cell, other, index)
55 56 return nb, other
56 57 return wrappedfunc
57 58
58 59
59 60 @cell_preprocessor
60 61 def haspyout_transformer(cell, other, count):
61 62 """
62 63 Add a haspyout flag to cell that have it
63 64
64 65 Easier for templating, where you can't know in advance
65 66 wether to write the out prompt
66 67
67 68 """
68 69 cell.type = cell.cell_type
69 70 cell.haspyout = False
70 71 for out in cell.get('outputs', []):
71 72 if out.output_type == 'pyout':
72 73 cell.haspyout = True
73 74 break
74 75 return cell, other
75 76
76 77
77 78 # todo, make the key part configurable.
78 79
79 80 class ExtractFigureTransformer(ActivatableTransformer):
80 81
81 82 extra_ext_map = Dict({},
82 83 config=True,
83 84 help="""extra map to override extension based on type.
84 85 Usefull for latex where svg will be converted to pdf before inclusion
85 86 """
86 87 )
87 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
88 config=True,
89 help= """
90 An ordered list of prefered output type, the first
91 encounterd will usually be used when converting discarding
92 the others.
93 """
94 )
95
96 88
97 89 #to do change this to .format {} syntax
98 90 key_tpl = Unicode('_fig_%02i.%s', config=True)
99 91
100 92 def _get_ext(self, ext):
101 93 if ext in self.extra_ext_map :
102 94 return self.extra_ext_map[ext]
103 95 return ext
104 96
105 97 def _new_figure(self, data, fmt, count):
106 98 """Create a new figure file in the given format.
107 99
108 100 Returns a path relative to the input file.
109 101 """
110 102 figname = self.key_tpl % (count, self._get_ext(fmt))
111 103 key = self.key_tpl % (count, fmt)
112 104
113 105 # Binary files are base64-encoded, SVG is already XML
114 106 if fmt in ('png', 'jpg', 'pdf'):
115 107 data = data.decode('base64')
116 108
117 109 return figname, key, data
118 110
119 111
120 112 def cell_transform(self, cell, other, count):
121 113 if other.get('figures',None) is None :
122 114 other['figures']={}
123 115 for i, out in enumerate(cell.get('outputs', [])):
124 116 for type in self.display_data_priority:
125 117 if out.hasattr(type):
126 118 figname, key, data = self._new_figure(out[type], type, count)
127 119 out['key_'+type] = figname
128 120 other['figures'][key] = data
129 121 count = count+1
130 122 return cell, other
131 123
132 124 class RevealHelpTransformer(ConfigurableTransformers):
133 125
134 126 section_open = False
135 127 subsection_open = False
136 128 fragment_open = False
137 129
138 130 def open_subsection(self):
139 131 self.subsection_open = True
140 132 return True
141 133
142 134 def open_section(self):
143 135 self.section_open = True
144 136 return True
145 137
146 138 def open_fragment(self):
147 139 self.fragment_open = True
148 140 return True
149 141
150 142 # could probaly write those maybe_close/open
151 143 # with a function functor
152 144 def maybe_close_section(self):
153 145 """return True is already open, false otherwise
154 146 and change state to close
155 147 """
156 148 if self.section_open :
157 149 self.section_open = False
158 150 return True
159 151 else :
160 152 return False
161 153
162 154 def maybe_open_section(self):
163 155 """return True is already open, false otherwise
164 156 and change state to close
165 157 """
166 158 if not self.section_open :
167 159 self.section_open = True
168 160 return True
169 161 else :
170 162 return False
171 163
172 164 def maybe_open_subsection(self):
173 165 """return True is already open, false otherwise
174 166 and change state to close
175 167 """
176 168 if not self.subsection_open :
177 169 self.subsection_open = True
178 170 return True
179 171 else :
180 172 return False
181 173
182 174 def maybe_close_subsection(self):
183 175 """return True is already open, false otherwise
184 176 and change state to close
185 177 """
186 178 if self.subsection_open :
187 179 self.subsection_open = False
188 180 return True
189 181 else :
190 182 return False
191 183
192 184 def maybe_close_fragment(self):
193 185 """return True is already open, false otherwise
194 186 and change state to close
195 187 """
196 188 if self.fragment_open :
197 189 self.fragment_open = False
198 190 return True
199 191 else :
200 192 return False
201 193
202 194 def cell_transform(self, cell, other,count):
203 195 ctype = cell.metadata.get('slideshow',{}).get('slide_type',None)
204 196 if ctype in [None, '-'] :
205 197 cell.metadata.slideshow = {}
206 198 cell.metadata.slideshow['slide_type'] = None
207 199 elif ctype == 'fragment':
208 200 cell.metadata.slideshow.close_fragment = self.maybe_close_fragment()
209 201 cell.metadata.slideshow.close_subsection = False
210 202 cell.metadata.slideshow.close_section = False
211 203
212 204 cell.metadata.slideshow.open_section = self.maybe_open_section()
213 205 cell.metadata.slideshow.open_subsection = self.maybe_open_subsection()
214 206 cell.metadata.slideshow.open_fragment = self.open_fragment()
215 207
216 208 elif ctype == 'subslide':
217 209 cell.metadata.slideshow.close_fragment = self.maybe_close_fragment()
218 210 cell.metadata.slideshow.close_subsection = self.maybe_close_subsection()
219 211 cell.metadata.slideshow.close_section = False
220 212
221 213 cell.metadata.slideshow.open_section = self.maybe_open_section()
222 214 cell.metadata.slideshow.open_subsection = self.open_subsection()
223 215 cell.metadata.slideshow.open_fragment = False
224 216 elif ctype == 'slide':
225 217 cell.metadata.slideshow.close_fragment = self.maybe_close_fragment()
226 218 cell.metadata.slideshow.close_subsection = self.maybe_close_subsection()
227 219 cell.metadata.slideshow.close_section = self.maybe_close_section()
228 220
229 221 cell.metadata.slideshow.open_section = self.open_section()
230 222 cell.metadata.slideshow.open_subsection = self.open_subsection()
231 223 cell.metadata.slideshow.open_fragment = False
232 224 return cell,other
233 225
@@ -1,135 +1,138 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,ExtractFigureTransformer)
34 34
35 from converters.jinja_filters import GlobalConfigurable
36
35 37
36 38 class NbconvertApp(Application):
37 39
38 40 stdout = Bool(True, config=True)
39 41 write = Bool(False, config=True)
40 42
41 43 fileext = Unicode('txt', config=True)
42 44
43 45 aliases = {
44 46 'stdout':'NbconvertApp.stdout',
45 47 'write':'NbconvertApp.write',
46 48 }
47 49
48 50 flags= {}
49 51 flags['no-stdout'] = (
50 52 {'NbconvertApp' : {'stdout' : False}},
51 53 """the doc for this flag
52 54
53 55 """
54 56 )
55 57
56 58 def __init__(self, **kwargs):
57 59 super(NbconvertApp, self).__init__(**kwargs)
58 60 self.classes.insert(0,ConverterTemplate)
59 61 # register class here to have help with help all
60 62 self.classes.insert(0,ExtractFigureTransformer)
63 self.classes.insert(0,GlobalConfigurable)
61 64 # ensure those are registerd
62 65
63 66 def load_config_file(self, profile_name):
64 67 try:
65 68 Application.load_config_file(
66 69 self,
67 70 profile_name+'.nbcv',
68 71 path=[os.path.join(os.getcwdu(),'profile')]
69 72 )
70 73 except ConfigFileNotFound:
71 74 self.log.warn("Config file for profile '%s' not found, giving up ",profile_name)
72 75 exit(1)
73 76
74 77
75 78 def initialize(self, argv=None):
76 79 self.parse_command_line(argv)
77 80 cl_config = self.config
78 81 profile_file = sys.argv[1]
79 82 self.load_config_file(profile_file)
80 83 self.update_config(cl_config)
81 84
82 85
83 86
84 87 def run(self):
85 88 """Convert a notebook to html in one step"""
86 89 template_file = (self.extra_args or [None])[0]
87 90 ipynb_file = (self.extra_args or [None])[1]
88 91
89 92 template_file = sys.argv[1]
90 93
91 94 C = ConverterTemplate(config=self.config)
92 95
93 96 output,resources = C.from_filename(ipynb_file)
94 97 if self.stdout :
95 98 print(output.encode('utf-8'))
96 99
97 100 out_root = ipynb_file[:-6].replace('.','_').replace(' ','_')
98 101
99 102 keys = resources.get('figures',{}).keys()
100 103 if self.write :
101 104 with io.open(os.path.join(out_root+'.'+self.fileext),'w') as f:
102 105 f.write(output)
103 106 if keys :
104 107 if self.write and not os.path.exists(out_root+'_files'):
105 108 os.mkdir(out_root+'_files')
106 109 for key in keys:
107 110 if self.write:
108 111 with io.open(os.path.join(out_root+'_files',key),'wb') as f:
109 112 print(' writing to ',os.path.join(out_root,key))
110 113 f.write(resources['figures'][key])
111 114 if self.stdout:
112 115 print('''
113 116 ====================== Keys in Resources ==================================
114 117 ''')
115 118 print(resources['figures'].keys())
116 119 print("""
117 120 ===========================================================================
118 121 you are responsible from writing those data do a file in the right place if
119 122 they need to be.
120 123 ===========================================================================
121 124 """)
122 125
123 126 def main():
124 127 """Convert a notebook to html in one step"""
125 128 app = NbconvertApp.instance()
126 129 app.description = __doc__
127 130 app.initialize()
128 131 app.start()
129 132 app.run()
130 133 #-----------------------------------------------------------------------------
131 134 # Script main
132 135 #-----------------------------------------------------------------------------
133 136
134 137 if __name__ == '__main__':
135 138 main()
General Comments 0
You need to be logged in to leave comments. Login now