##// END OF EJS Templates
add basic logging to NbConvert stages
MinRK -
Show More
@@ -1,321 +1,328 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """NBConvert is a utility for conversion of .ipynb files.
2 """NBConvert is a utility for conversion of .ipynb files.
3
3
4 Command-line interface for the NbConvert conversion utility.
4 Command-line interface for the NbConvert conversion utility.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 #Copyright (c) 2013, the IPython Development Team.
7 #Copyright (c) 2013, 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 # Stdlib imports
18 # Stdlib imports
19 from __future__ import print_function
19 from __future__ import print_function
20
21 import logging
20 import sys
22 import sys
21 import os
23 import os
22 import glob
24 import glob
23
25
24 # From IPython
26 # From IPython
25 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
27 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
26 from IPython.config import catch_config_error, Configurable
28 from IPython.config import catch_config_error, Configurable
27 from IPython.utils.traitlets import (
29 from IPython.utils.traitlets import (
28 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
30 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
29 )
31 )
30 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
31 from IPython.utils.text import dedent
33 from IPython.utils.text import dedent
32
34
33 from .exporters.export import export_by_name, get_export_names, ExporterNameError
35 from .exporters.export import export_by_name, get_export_names, ExporterNameError
34 from IPython.nbconvert import exporters, transformers, writers, post_processors
36 from IPython.nbconvert import exporters, transformers, writers, post_processors
35 from .utils.base import NbConvertBase
37 from .utils.base import NbConvertBase
36 from .utils.exceptions import ConversionException
38 from .utils.exceptions import ConversionException
37
39
38 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
39 #Classes and functions
41 #Classes and functions
40 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
41
43
42 class DottedOrNone(DottedObjectName):
44 class DottedOrNone(DottedObjectName):
43 """
45 """
44 A string holding a valid dotted object name in Python, such as A.b3._c
46 A string holding a valid dotted object name in Python, such as A.b3._c
45 Also allows for None type."""
47 Also allows for None type."""
46
48
47 default_value = u''
49 default_value = u''
48
50
49 def validate(self, obj, value):
51 def validate(self, obj, value):
50 if value is not None and len(value) > 0:
52 if value is not None and len(value) > 0:
51 return super(DottedOrNone, self).validate(obj, value)
53 return super(DottedOrNone, self).validate(obj, value)
52 else:
54 else:
53 return value
55 return value
54
56
55 nbconvert_aliases = {}
57 nbconvert_aliases = {}
56 nbconvert_aliases.update(base_aliases)
58 nbconvert_aliases.update(base_aliases)
57 nbconvert_aliases.update({
59 nbconvert_aliases.update({
58 'to' : 'NbConvertApp.export_format',
60 'to' : 'NbConvertApp.export_format',
59 'template' : 'Exporter.template_file',
61 'template' : 'Exporter.template_file',
60 'notebooks' : 'NbConvertApp.notebooks',
62 'notebooks' : 'NbConvertApp.notebooks',
61 'writer' : 'NbConvertApp.writer_class',
63 'writer' : 'NbConvertApp.writer_class',
62 'post': 'NbConvertApp.post_processor_class',
64 'post': 'NbConvertApp.post_processor_class',
63 'output': 'NbConvertApp.output_base'
65 'output': 'NbConvertApp.output_base'
64 })
66 })
65
67
66 nbconvert_flags = {}
68 nbconvert_flags = {}
67 nbconvert_flags.update(base_flags)
69 nbconvert_flags.update(base_flags)
68 nbconvert_flags.update({
70 nbconvert_flags.update({
69 'stdout' : (
71 'stdout' : (
70 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
72 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
71 "Write notebook output to stdout instead of files."
73 "Write notebook output to stdout instead of files."
72 )
74 )
73 })
75 })
74
76
75
77
76 class NbConvertApp(BaseIPythonApplication):
78 class NbConvertApp(BaseIPythonApplication):
77 """Application used to convert to and from notebook file type (*.ipynb)"""
79 """Application used to convert to and from notebook file type (*.ipynb)"""
78
80
79 name = 'ipython-nbconvert'
81 name = 'ipython-nbconvert'
80 aliases = nbconvert_aliases
82 aliases = nbconvert_aliases
81 flags = nbconvert_flags
83 flags = nbconvert_flags
82
84
85 def _log_level_default(self):
86 return logging.INFO
87
83 def _classes_default(self):
88 def _classes_default(self):
84 classes = [NbConvertBase]
89 classes = [NbConvertBase]
85 for pkg in (exporters, transformers, writers):
90 for pkg in (exporters, transformers, writers):
86 for name in dir(pkg):
91 for name in dir(pkg):
87 cls = getattr(pkg, name)
92 cls = getattr(pkg, name)
88 if isinstance(cls, type) and issubclass(cls, Configurable):
93 if isinstance(cls, type) and issubclass(cls, Configurable):
89 classes.append(cls)
94 classes.append(cls)
90 return classes
95 return classes
91
96
92 description = Unicode(
97 description = Unicode(
93 u"""This application is used to convert notebook files (*.ipynb)
98 u"""This application is used to convert notebook files (*.ipynb)
94 to various other formats.
99 to various other formats.
95
100
96 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
101 WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""")
97
102
98 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
103 output_base = Unicode('', config=True, help='''overwrite base name use for output files.
99 can only be use when converting one notebook at a time.
104 can only be use when converting one notebook at a time.
100 ''')
105 ''')
101
106
102 examples = Unicode(u"""
107 examples = Unicode(u"""
103 The simplest way to use nbconvert is
108 The simplest way to use nbconvert is
104
109
105 > ipython nbconvert mynotebook.ipynb
110 > ipython nbconvert mynotebook.ipynb
106
111
107 which will convert mynotebook.ipynb to the default format (probably HTML).
112 which will convert mynotebook.ipynb to the default format (probably HTML).
108
113
109 You can specify the export format with `--to`.
114 You can specify the export format with `--to`.
110 Options include {0}
115 Options include {0}
111
116
112 > ipython nbconvert --to latex mynotebook.ipnynb
117 > ipython nbconvert --to latex mynotebook.ipnynb
113
118
114 Both HTML and LaTeX support multiple output templates. LaTeX includes
119 Both HTML and LaTeX support multiple output templates. LaTeX includes
115 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
120 'basic', 'book', and 'article'. HTML includes 'basic' and 'full'. You
116 can specify the flavor of the format used.
121 can specify the flavor of the format used.
117
122
118 > ipython nbconvert --to html --template basic mynotebook.ipynb
123 > ipython nbconvert --to html --template basic mynotebook.ipynb
119
124
120 You can also pipe the output to stdout, rather than a file
125 You can also pipe the output to stdout, rather than a file
121
126
122 > ipython nbconvert mynotebook.ipynb --stdout
127 > ipython nbconvert mynotebook.ipynb --stdout
123
128
124 A post-processor can be used to compile a PDF
129 A post-processor can be used to compile a PDF
125
130
126 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
131 > ipython nbconvert mynotebook.ipynb --to latex --post PDF
127
132
128 You can get (and serve) a Reveal.js-powered slideshow
133 You can get (and serve) a Reveal.js-powered slideshow
129
134
130 > ipython nbconvert myslides.ipynb --to slides --post serve
135 > ipython nbconvert myslides.ipynb --to slides --post serve
131
136
132 Multiple notebooks can be given at the command line in a couple of
137 Multiple notebooks can be given at the command line in a couple of
133 different ways:
138 different ways:
134
139
135 > ipython nbconvert notebook*.ipynb
140 > ipython nbconvert notebook*.ipynb
136 > ipython nbconvert notebook1.ipynb notebook2.ipynb
141 > ipython nbconvert notebook1.ipynb notebook2.ipynb
137
142
138 or you can specify the notebooks list in a config file, containing::
143 or you can specify the notebooks list in a config file, containing::
139
144
140 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
145 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
141
146
142 > ipython nbconvert --config mycfg.py
147 > ipython nbconvert --config mycfg.py
143 """.format(get_export_names()))
148 """.format(get_export_names()))
144
149
145 # Writer specific variables
150 # Writer specific variables
146 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
151 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
147 help="""Instance of the writer class used to write the
152 help="""Instance of the writer class used to write the
148 results of the conversion.""")
153 results of the conversion.""")
149 writer_class = DottedObjectName('FilesWriter', config=True,
154 writer_class = DottedObjectName('FilesWriter', config=True,
150 help="""Writer class used to write the
155 help="""Writer class used to write the
151 results of the conversion""")
156 results of the conversion""")
152 writer_aliases = {'FilesWriter': 'IPython.nbconvert.writers.files.FilesWriter',
157 writer_aliases = {'FilesWriter': 'IPython.nbconvert.writers.files.FilesWriter',
153 'DebugWriter': 'IPython.nbconvert.writers.debug.DebugWriter',
158 'DebugWriter': 'IPython.nbconvert.writers.debug.DebugWriter',
154 'StdoutWriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
159 'StdoutWriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
155 writer_factory = Type()
160 writer_factory = Type()
156
161
157 def _writer_class_changed(self, name, old, new):
162 def _writer_class_changed(self, name, old, new):
158 if new in self.writer_aliases:
163 if new in self.writer_aliases:
159 new = self.writer_aliases[new]
164 new = self.writer_aliases[new]
160 self.writer_factory = import_item(new)
165 self.writer_factory = import_item(new)
161
166
162 # Post-processor specific variables
167 # Post-processor specific variables
163 post_processor = Instance('IPython.nbconvert.post_processors.base.PostProcessorBase',
168 post_processor = Instance('IPython.nbconvert.post_processors.base.PostProcessorBase',
164 help="""Instance of the PostProcessor class used to write the
169 help="""Instance of the PostProcessor class used to write the
165 results of the conversion.""")
170 results of the conversion.""")
166
171
167 post_processor_class = DottedOrNone(config=True,
172 post_processor_class = DottedOrNone(config=True,
168 help="""PostProcessor class used to write the
173 help="""PostProcessor class used to write the
169 results of the conversion""")
174 results of the conversion""")
170 post_processor_aliases = {'PDF': 'IPython.nbconvert.post_processors.pdf.PDFPostProcessor',
175 post_processor_aliases = {'PDF': 'IPython.nbconvert.post_processors.pdf.PDFPostProcessor',
171 'serve': 'IPython.nbconvert.post_processors.serve.ServePostProcessor'}
176 'serve': 'IPython.nbconvert.post_processors.serve.ServePostProcessor'}
172 post_processor_factory = Type()
177 post_processor_factory = Type()
173
178
174 def _post_processor_class_changed(self, name, old, new):
179 def _post_processor_class_changed(self, name, old, new):
175 if new in self.post_processor_aliases:
180 if new in self.post_processor_aliases:
176 new = self.post_processor_aliases[new]
181 new = self.post_processor_aliases[new]
177 if new:
182 if new:
178 self.post_processor_factory = import_item(new)
183 self.post_processor_factory = import_item(new)
179
184
180
185
181 # Other configurable variables
186 # Other configurable variables
182 export_format = CaselessStrEnum(get_export_names(),
187 export_format = CaselessStrEnum(get_export_names(),
183 default_value="html",
188 default_value="html",
184 config=True,
189 config=True,
185 help="""The export format to be used."""
190 help="""The export format to be used."""
186 )
191 )
187
192
188 notebooks = List([], config=True, help="""List of notebooks to convert.
193 notebooks = List([], config=True, help="""List of notebooks to convert.
189 Wildcards are supported.
194 Wildcards are supported.
190 Filenames passed positionally will be added to the list.
195 Filenames passed positionally will be added to the list.
191 """)
196 """)
192
197
193 @catch_config_error
198 @catch_config_error
194 def initialize(self, argv=None):
199 def initialize(self, argv=None):
195 super(NbConvertApp, self).initialize(argv)
200 super(NbConvertApp, self).initialize(argv)
196 self.init_syspath()
201 self.init_syspath()
197 self.init_notebooks()
202 self.init_notebooks()
198 self.init_writer()
203 self.init_writer()
199 self.init_post_processor()
204 self.init_post_processor()
200
205
201
206
202
207
203 def init_syspath(self):
208 def init_syspath(self):
204 """
209 """
205 Add the cwd to the sys.path ($PYTHONPATH)
210 Add the cwd to the sys.path ($PYTHONPATH)
206 """
211 """
207 sys.path.insert(0, os.getcwd())
212 sys.path.insert(0, os.getcwd())
208
213
209
214
210 def init_notebooks(self):
215 def init_notebooks(self):
211 """Construct the list of notebooks.
216 """Construct the list of notebooks.
212 If notebooks are passed on the command-line,
217 If notebooks are passed on the command-line,
213 they override notebooks specified in config files.
218 they override notebooks specified in config files.
214 Glob each notebook to replace notebook patterns with filenames.
219 Glob each notebook to replace notebook patterns with filenames.
215 """
220 """
216
221
217 # Specifying notebooks on the command-line overrides (rather than adds)
222 # Specifying notebooks on the command-line overrides (rather than adds)
218 # the notebook list
223 # the notebook list
219 if self.extra_args:
224 if self.extra_args:
220 patterns = self.extra_args
225 patterns = self.extra_args
221 else:
226 else:
222 patterns = self.notebooks
227 patterns = self.notebooks
223
228
224 # Use glob to replace all the notebook patterns with filenames.
229 # Use glob to replace all the notebook patterns with filenames.
225 filenames = []
230 filenames = []
226 for pattern in patterns:
231 for pattern in patterns:
227
232
228 # Use glob to find matching filenames. Allow the user to convert
233 # Use glob to find matching filenames. Allow the user to convert
229 # notebooks without having to type the extension.
234 # notebooks without having to type the extension.
230 globbed_files = glob.glob(pattern)
235 globbed_files = glob.glob(pattern)
231 globbed_files.extend(glob.glob(pattern + '.ipynb'))
236 globbed_files.extend(glob.glob(pattern + '.ipynb'))
232
237
233 for filename in globbed_files:
238 for filename in globbed_files:
234 if not filename in filenames:
239 if not filename in filenames:
235 filenames.append(filename)
240 filenames.append(filename)
236 self.notebooks = filenames
241 self.notebooks = filenames
237
242
238 def init_writer(self):
243 def init_writer(self):
239 """
244 """
240 Initialize the writer (which is stateless)
245 Initialize the writer (which is stateless)
241 """
246 """
242 self._writer_class_changed(None, self.writer_class, self.writer_class)
247 self._writer_class_changed(None, self.writer_class, self.writer_class)
243 self.writer = self.writer_factory(parent=self)
248 self.writer = self.writer_factory(parent=self)
244
249
245 def init_post_processor(self):
250 def init_post_processor(self):
246 """
251 """
247 Initialize the post_processor (which is stateless)
252 Initialize the post_processor (which is stateless)
248 """
253 """
249 self._post_processor_class_changed(None, self.post_processor_class,
254 self._post_processor_class_changed(None, self.post_processor_class,
250 self.post_processor_class)
255 self.post_processor_class)
251 if self.post_processor_factory:
256 if self.post_processor_factory:
252 self.post_processor = self.post_processor_factory(parent=self)
257 self.post_processor = self.post_processor_factory(parent=self)
253
258
254 def start(self):
259 def start(self):
255 """
260 """
256 Ran after initialization completed
261 Ran after initialization completed
257 """
262 """
258 super(NbConvertApp, self).start()
263 super(NbConvertApp, self).start()
259 self.convert_notebooks()
264 self.convert_notebooks()
260
265
261 def convert_notebooks(self):
266 def convert_notebooks(self):
262 """
267 """
263 Convert the notebooks in the self.notebook traitlet
268 Convert the notebooks in the self.notebook traitlet
264 """
269 """
265 # Export each notebook
270 # Export each notebook
266 conversion_success = 0
271 conversion_success = 0
267
272
268 if self.output_base != '' and len(self.notebooks) > 1:
273 if self.output_base != '' and len(self.notebooks) > 1:
269 print(dedent(
274 print(dedent(
270 """UsageError: --output flag or `NbConvertApp.output_base` config option
275 """UsageError: --output flag or `NbConvertApp.output_base` config option
271 cannot be used when converting multiple notebooks.
276 cannot be used when converting multiple notebooks.
272 """))
277 """))
273 self.exit(1)
278 self.exit(1)
274
279
275 for notebook_filename in self.notebooks:
280 for notebook_filename in self.notebooks:
281 self.log.info("Converting notebook %s to %s", notebook_filename, self.export_format)
276
282
277 # Get a unique key for the notebook and set it in the resources object.
283 # Get a unique key for the notebook and set it in the resources object.
278 basename = os.path.basename(notebook_filename)
284 basename = os.path.basename(notebook_filename)
279 notebook_name = basename[:basename.rfind('.')]
285 notebook_name = basename[:basename.rfind('.')]
280 if self.output_base:
286 if self.output_base:
281 notebook_name = self.output_base
287 notebook_name = self.output_base
282 resources = {}
288 resources = {}
283 resources['unique_key'] = notebook_name
289 resources['unique_key'] = notebook_name
284 resources['output_files_dir'] = '%s_files' % notebook_name
290 resources['output_files_dir'] = '%s_files' % notebook_name
291 self.log.debug("Writing extra files to %s", resources['output_files_dir'])
285
292
286 # Try to export
293 # Try to export
287 try:
294 try:
288 output, resources = export_by_name(self.export_format,
295 output, resources = export_by_name(self.export_format,
289 notebook_filename,
296 notebook_filename,
290 resources=resources,
297 resources=resources,
291 config=self.config)
298 config=self.config)
292 except ExporterNameError as e:
299 except ExporterNameError as e:
293 print("Error while converting '%s': '%s' exporter not found."
300 print("Error while converting '%s': '%s' exporter not found."
294 %(notebook_filename, self.export_format),
301 %(notebook_filename, self.export_format),
295 file=sys.stderr)
302 file=sys.stderr)
296 print("Known exporters are:",
303 print("Known exporters are:",
297 "\n\t" + "\n\t".join(get_export_names()),
304 "\n\t" + "\n\t".join(get_export_names()),
298 file=sys.stderr)
305 file=sys.stderr)
299 self.exit(1)
306 self.exit(1)
300 except ConversionException as e:
307 except ConversionException as e:
301 print("Error while converting '%s': %s" %(notebook_filename, e),
308 print("Error while converting '%s': %s" %(notebook_filename, e),
302 file=sys.stderr)
309 file=sys.stderr)
303 self.exit(1)
310 self.exit(1)
304 else:
311 else:
305 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
312 write_resultes = self.writer.write(output, resources, notebook_name=notebook_name)
306
313
307 #Post-process if post processor has been defined.
314 #Post-process if post processor has been defined.
308 if hasattr(self, 'post_processor') and self.post_processor:
315 if hasattr(self, 'post_processor') and self.post_processor:
309 self.post_processor(write_resultes)
316 self.post_processor(write_resultes)
310 conversion_success += 1
317 conversion_success += 1
311
318
312 # If nothing was converted successfully, help the user.
319 # If nothing was converted successfully, help the user.
313 if conversion_success == 0:
320 if conversion_success == 0:
314 self.print_help()
321 self.print_help()
315 sys.exit(-1)
322 sys.exit(-1)
316
323
317 #-----------------------------------------------------------------------------
324 #-----------------------------------------------------------------------------
318 # Main entry point
325 # Main entry point
319 #-----------------------------------------------------------------------------
326 #-----------------------------------------------------------------------------
320
327
321 launch_new_instance = NbConvertApp.launch_instance
328 launch_new_instance = NbConvertApp.launch_instance
@@ -1,109 +1,110 b''
1 """
1 """
2 Module that re-groups transformer that would be applied to ipynb files
2 Module that re-groups transformer that would be applied to ipynb files
3 before going through the templating machinery.
3 before going through the templating machinery.
4
4
5 It exposes a convenient class to inherit from to access configurability.
5 It exposes a convenient class to inherit from to access configurability.
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2013, the IPython Development Team.
8 # Copyright (c) 2013, the IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from ..utils.base import NbConvertBase
19 from ..utils.base import NbConvertBase
20 from IPython.utils.traitlets import Bool
20 from IPython.utils.traitlets import Bool
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Classes and Functions
23 # Classes and Functions
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 class Transformer(NbConvertBase):
26 class Transformer(NbConvertBase):
27 """ A configurable transformer
27 """ A configurable transformer
28
28
29 Inherit from this class if you wish to have configurability for your
29 Inherit from this class if you wish to have configurability for your
30 transformer.
30 transformer.
31
31
32 Any configurable traitlets this class exposed will be configurable in profiles
32 Any configurable traitlets this class exposed will be configurable in profiles
33 using c.SubClassName.atribute=value
33 using c.SubClassName.atribute=value
34
34
35 you can overwrite transform_cell to apply a transformation independently on each cell
35 you can overwrite transform_cell to apply a transformation independently on each cell
36 or __call__ if you prefer your own logic. See corresponding docstring for informations.
36 or __call__ if you prefer your own logic. See corresponding docstring for informations.
37
37
38 Disabled by default and can be enabled via the config by
38 Disabled by default and can be enabled via the config by
39 'c.YourTransformerName.enabled = True'
39 'c.YourTransformerName.enabled = True'
40 """
40 """
41
41
42 enabled = Bool(False, config=True)
42 enabled = Bool(False, config=True)
43
43
44 def __init__(self, **kw):
44 def __init__(self, **kw):
45 """
45 """
46 Public constructor
46 Public constructor
47
47
48 Parameters
48 Parameters
49 ----------
49 ----------
50 config : Config
50 config : Config
51 Configuration file structure
51 Configuration file structure
52 **kw : misc
52 **kw : misc
53 Additional arguments
53 Additional arguments
54 """
54 """
55
55
56 super(Transformer, self).__init__(**kw)
56 super(Transformer, self).__init__(**kw)
57
57
58
58
59 def __call__(self, nb, resources):
59 def __call__(self, nb, resources):
60 if self.enabled:
60 if self.enabled:
61 return self.call(nb,resources)
61 return self.call(nb,resources)
62 else:
62 else:
63 return nb, resources
63 return nb, resources
64
64
65
65
66 def call(self, nb, resources):
66 def call(self, nb, resources):
67 """
67 """
68 Transformation to apply on each notebook.
68 Transformation to apply on each notebook.
69
69
70 You should return modified nb, resources.
70 You should return modified nb, resources.
71 If you wish to apply your transform on each cell, you might want to
71 If you wish to apply your transform on each cell, you might want to
72 overwrite transform_cell method instead.
72 overwrite transform_cell method instead.
73
73
74 Parameters
74 Parameters
75 ----------
75 ----------
76 nb : NotebookNode
76 nb : NotebookNode
77 Notebook being converted
77 Notebook being converted
78 resources : dictionary
78 resources : dictionary
79 Additional resources used in the conversion process. Allows
79 Additional resources used in the conversion process. Allows
80 transformers to pass variables into the Jinja engine.
80 transformers to pass variables into the Jinja engine.
81 """
81 """
82 self.log.debug("Applying transform: %s", self.__class__.__name__)
82 try :
83 try :
83 for worksheet in nb.worksheets :
84 for worksheet in nb.worksheets:
84 for index, cell in enumerate(worksheet.cells):
85 for index, cell in enumerate(worksheet.cells):
85 worksheet.cells[index], resources = self.transform_cell(cell, resources, index)
86 worksheet.cells[index], resources = self.transform_cell(cell, resources, index)
86 return nb, resources
87 return nb, resources
87 except NotImplementedError:
88 except NotImplementedError:
88 raise NotImplementedError('should be implemented by subclass')
89 raise NotImplementedError('should be implemented by subclass')
89
90
90
91
91 def transform_cell(self, cell, resources, index):
92 def transform_cell(self, cell, resources, index):
92 """
93 """
93 Overwrite if you want to apply a transformation on each cell. You
94 Overwrite if you want to apply a transformation on each cell. You
94 should return modified cell and resource dictionary.
95 should return modified cell and resource dictionary.
95
96
96 Parameters
97 Parameters
97 ----------
98 ----------
98 cell : NotebookNode cell
99 cell : NotebookNode cell
99 Notebook cell being processed
100 Notebook cell being processed
100 resources : dictionary
101 resources : dictionary
101 Additional resources used in the conversion process. Allows
102 Additional resources used in the conversion process. Allows
102 transformers to pass variables into the Jinja engine.
103 transformers to pass variables into the Jinja engine.
103 index : int
104 index : int
104 Index of the cell being processed
105 Index of the cell being processed
105 """
106 """
106
107
107 raise NotImplementedError('should be implemented by subclass')
108 raise NotImplementedError('should be implemented by subclass')
108 return cell, resources
109 return cell, resources
109
110
@@ -1,37 +1,37 b''
1 """Global configuration class."""
1 """Global configuration class."""
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2013, the IPython Development Team.
3 # Copyright (c) 2013, the IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 from IPython.utils.traitlets import List
14 from IPython.utils.traitlets import List
15 from IPython.config.configurable import Configurable
15 from IPython.config.configurable import LoggingConfigurable
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Classes and functions
18 # Classes and functions
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 class NbConvertBase(Configurable):
21 class NbConvertBase(LoggingConfigurable):
22 """Global configurable class for shared config
22 """Global configurable class for shared config
23
23
24 Usefull for display data priority that might be use by many trasnformers
24 Usefull for display data priority that might be use by many trasnformers
25 """
25 """
26
26
27 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
27 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
28 config=True,
28 config=True,
29 help= """
29 help= """
30 An ordered list of prefered output type, the first
30 An ordered list of prefered output type, the first
31 encounterd will usually be used when converting discarding
31 encounterd will usually be used when converting discarding
32 the others.
32 the others.
33 """
33 """
34 )
34 )
35
35
36 def __init__(self, **kw):
36 def __init__(self, **kw):
37 super(NbConvertBase, self).__init__(**kw)
37 super(NbConvertBase, self).__init__(**kw)
@@ -1,102 +1,108 b''
1 """
1 """
2 Contains writer for writing nbconvert output to filesystem.
2 Contains writer for writing nbconvert output to filesystem.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 #Copyright (c) 2013, the IPython Development Team.
5 #Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 #Distributed under the terms of the Modified BSD License.
7 #Distributed under the terms of the Modified BSD License.
8 #
8 #
9 #The full license is in the file COPYING.txt, distributed with this software.
9 #The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import io
16 import io
17 import os
17 import os
18 import glob
18 import glob
19
19
20 from IPython.utils.traitlets import Unicode
20 from IPython.utils.traitlets import Unicode
21 from IPython.utils.path import link_or_copy
21 from IPython.utils.path import link_or_copy
22
22
23 from .base import WriterBase
23 from .base import WriterBase
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Classes
26 # Classes
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 class FilesWriter(WriterBase):
29 class FilesWriter(WriterBase):
30 """Consumes nbconvert output and produces files."""
30 """Consumes nbconvert output and produces files."""
31
31
32
32
33 build_directory = Unicode(".", config=True,
33 build_directory = Unicode(".", config=True,
34 help="""Directory to write output to. Leave blank
34 help="""Directory to write output to. Leave blank
35 to output to the current directory""")
35 to output to the current directory""")
36
36
37
37
38 # Make sure that the output directory exists.
38 # Make sure that the output directory exists.
39 def _build_directory_changed(self, name, old, new):
39 def _build_directory_changed(self, name, old, new):
40 if new and not os.path.isdir(new):
40 if new and not os.path.isdir(new):
41 os.makedirs(new)
41 os.makedirs(new)
42
42
43
43
44 def __init__(self, **kw):
44 def __init__(self, **kw):
45 super(FilesWriter, self).__init__(**kw)
45 super(FilesWriter, self).__init__(**kw)
46 self._build_directory_changed('build_directory', self.build_directory,
46 self._build_directory_changed('build_directory', self.build_directory,
47 self.build_directory)
47 self.build_directory)
48
48
49 def _makedir(self, path):
50 """Make a directory if it doesn't already exist"""
51 if not os.path.isdir(path):
52 self.log.info("Making directory %s", path)
53 os.makedirs(path)
49
54
50 def write(self, output, resources, notebook_name=None, **kw):
55 def write(self, output, resources, notebook_name=None, **kw):
51 """
56 """
52 Consume and write Jinja output to the file system. Output directory
57 Consume and write Jinja output to the file system. Output directory
53 is set via the 'build_directory' variable of this instance (a
58 is set via the 'build_directory' variable of this instance (a
54 configurable).
59 configurable).
55
60
56 See base for more...
61 See base for more...
57 """
62 """
58
63
59 # Pull the extension and subdir from the resources dict.
64 # Pull the extension and subdir from the resources dict.
60 output_extension = resources['output_extension']
65 output_extension = resources['output_extension']
61
66
62 # Write all of the extracted resources to the destination directory.
67 # Write all of the extracted resources to the destination directory.
63 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
68 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
64 # TRANSFORMER SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
69 # TRANSFORMER SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
65 for filename, data in resources.get('outputs', {}).items():
70 for filename, data in resources.get('outputs', {}).items():
66
71
67 # Determine where to write the file to
72 # Determine where to write the file to
68 dest = os.path.join(self.build_directory, filename)
73 dest = os.path.join(self.build_directory, filename)
69 path = os.path.dirname(dest)
74 path = os.path.dirname(dest)
70 if not os.path.isdir(path):
75 self._makedir(path)
71 os.makedirs(path)
72
76
73 # Write file
77 # Write file
78 self.log.info("Writing support file %s", dest)
74 with io.open(dest, 'wb') as f:
79 with io.open(dest, 'wb') as f:
75 f.write(data)
80 f.write(data)
76
81
77 # Copy referenced files to output directory
82 # Copy referenced files to output directory
78 if self.build_directory:
83 if self.build_directory:
79 for filename in self.files:
84 for filename in self.files:
80
85
81 # Copy files that match search pattern
86 # Copy files that match search pattern
82 for matching_filename in glob.glob(filename):
87 for matching_filename in glob.glob(filename):
83
88
84 # Make sure folder exists.
89 # Make sure folder exists.
85 dest = os.path.join(self.build_directory, filename)
90 dest = os.path.join(self.build_directory, filename)
86 path = os.path.dirname(dest)
91 path = os.path.dirname(dest)
87 if not os.path.isdir(path):
92 self._makedir(path)
88 os.makedirs(path)
89
93
90 # Copy if destination is different.
94 # Copy if destination is different.
91 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
95 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
96 self.log.info("Linking %s -> %s", matching_filename, dest)
92 link_or_copy(matching_filename, dest)
97 link_or_copy(matching_filename, dest)
93
98
94 # Determine where to write conversion results.
99 # Determine where to write conversion results.
95 dest = notebook_name + '.' + output_extension
100 dest = notebook_name + '.' + output_extension
96 if self.build_directory:
101 if self.build_directory:
97 dest = os.path.join(self.build_directory, dest)
102 dest = os.path.join(self.build_directory, dest)
98
103
99 # Write conversion results.
104 # Write conversion results.
105 self.log.info("Writing %s", dest)
100 with io.open(dest, 'w') as f:
106 with io.open(dest, 'w') as f:
101 f.write(output)
107 f.write(output)
102 return dest No newline at end of file
108 return dest
General Comments 0
You need to be logged in to leave comments. Login now