##// END OF EJS Templates
Merge pull request #3607 from jdfreder/writers_no_yaml...
Min RK -
r11476:6a905927 merge
parent child Browse files
Show More
@@ -0,0 +1,79 b''
1 """Module containing a transformer that converts outputs in the notebook from
2 one format to another.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 from .base import Transformer
17 from IPython.utils.traitlets import Unicode
18
19 #-----------------------------------------------------------------------------
20 # Classes
21 #-----------------------------------------------------------------------------
22
23 class ConvertFiguresTransformer(Transformer):
24 """
25 Converts all of the outputs in a notebook from one format to another.
26 """
27
28 from_format = Unicode(config=True, help='Format the converter accepts')
29 to_format = Unicode(config=True, help='Format the converter writes')
30
31 def __init__(self, **kw):
32 """
33 Public constructor
34 """
35 super(ConvertFiguresTransformer, self).__init__(**kw)
36
37
38 def convert_figure(self, data_format, data):
39 raise NotImplementedError()
40
41
42 def transform_cell(self, cell, resources, cell_index):
43 """
44 Apply a transformation on each cell,
45
46 See base.py
47 """
48
49 #Loop through all of the datatypes of the outputs in the cell.
50 for index, cell_out in enumerate(cell.get('outputs', [])):
51 for data_type, data in cell_out.items():
52
53 #Get the name of the file exported by the extract figure
54 #transformer. Do not try to convert the figure if the extract
55 #fig transformer hasn't touched it
56 filename = cell_out.get(data_type + '_filename', None)
57 if filename:
58 figure_name = filename[:filename.rfind('.')]
59 self._convert_figure(cell_out, figure_name, resources, data_type, data)
60 return cell, resources
61
62
63 def _convert_figure(self, cell_out, resources, figure_name, data_type, data):
64 """
65 Convert a figure and output the results to the cell output
66 """
67
68 if not self.to_format in cell_out:
69 if data_type == self.from_format:
70 filename = figure_name + '.' + self.to_format
71 if filename not in resources['figures']:
72
73 #On the cell, make the figure available via
74 # cell.outputs[i].pdf_filename ... etc (PDF in example)
75 cell_out[self.to_format + '_filename'] = filename
76
77 #In the resources, make the figure available via
78 # resources['figures']['filename'] = data
79 resources['figures'][filename] = self.convert_figure(data_type, data)
@@ -0,0 +1,77 b''
1 """Module containing a transformer that converts outputs in the notebook from
2 one format to another.
3 """
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 import os
17 import sys
18 import subprocess
19
20 from IPython.utils.tempdir import TemporaryDirectory
21 from IPython.utils.traitlets import Unicode
22
23 from .convertfigures import ConvertFiguresTransformer
24
25
26 #-----------------------------------------------------------------------------
27 # Constants
28 #-----------------------------------------------------------------------------
29
30 INKSCAPE_COMMAND = 'inkscape --without-gui --export-pdf="{to_filename}" "{from_filename}"'
31 INKSCAPE_OSX_COMMAND = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape --without-gui --export-pdf="{to_filename}" "{from_filename}"'
32
33
34 #-----------------------------------------------------------------------------
35 # Classes
36 #-----------------------------------------------------------------------------
37
38 class SVG2PDFTransformer(ConvertFiguresTransformer):
39 """
40 Converts all of the outputs in a notebook from one format to another.
41 """
42
43 from_format = Unicode('svg', config=True, help='Format the converter accepts')
44 to_format = Unicode('pdf', config=False, help='Format the converter writes')
45
46
47 def convert_figure(self, data_format, data):
48 """
49 Convert a single Svg figure. Returns converted data.
50 """
51
52 #Work in a temporary directory
53 with TemporaryDirectory() as tmpdir:
54
55 #Write fig to temp file
56 input_filename = os.path.join(tmpdir, 'figure.' + data_format)
57 with open(input_filename, 'w') as f:
58 f.write(data)
59
60 #Determine command (different on Mac OSX)
61 command = INKSCAPE_COMMAND
62 if sys.platform == 'darwin':
63 command = INKSCAPE_OSX_COMMAND
64
65 #Call conversion application
66 output_filename = os.path.join(tmpdir, 'figure.pdf')
67 shell = command.format(from_filename=input_filename,
68 to_filename=output_filename)
69 subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
70
71 #Read output from drive
72 if os.path.isfile(output_filename):
73 with open(output_filename, 'rb') as f:
74 return f.read().encode("base64") #PDF is a nb supported binary
75 #data type, so base64 encode.
76 else:
77 return TypeError("Inkscape svg to png conversion failed")
@@ -0,0 +1,2 b''
1 from .files import FilesWriter
2 from .stdout import StdoutWriter
@@ -0,0 +1,57 b''
1 #!/usr/bin/env python
2 """
3 Contains writer base class.
4 """
5 #-----------------------------------------------------------------------------
6 #Copyright (c) 2013, the IPython Development Team.
7 #
8 #Distributed under the terms of the Modified BSD License.
9 #
10 #The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from IPython.utils.traitlets import List
18
19 from ..utils.base import NbConvertBase
20
21 #-----------------------------------------------------------------------------
22 # Classes
23 #-----------------------------------------------------------------------------
24
25 class WriterBase(NbConvertBase):
26 """Consumes output from nbconvert export...() methods and writes to a
27 useful location. """
28
29
30 files = List([], config=True, help="""
31 List of the files that the notebook references. Files will be
32 included with written output.""")
33
34
35 def __init__(self, config=None, **kw):
36 """
37 Constructor
38 """
39 super(WriterBase, self).__init__(config=config, **kw)
40
41
42 def write(self, output, resources, **kw):
43 """
44 Consume and write Jinja output.
45
46 Parameters
47 ----------
48 output : string
49 Conversion results. This string contains the file contents of the
50 converted file.
51 resources : dict
52 Resources created and filled by the nbconvert conversion process.
53 Includes output from transformers, such as the extract figure
54 transformer.
55 """
56
57 raise NotImplementedError()
@@ -0,0 +1,43 b''
1 #!/usr/bin/env python
2 """
3 Contains debug writer.
4 """
5 #-----------------------------------------------------------------------------
6 #Copyright (c) 2013, the IPython Development Team.
7 #
8 #Distributed under the terms of the Modified BSD License.
9 #
10 #The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from .base import WriterBase
18 from pprint import pprint
19
20 #-----------------------------------------------------------------------------
21 # Classes
22 #-----------------------------------------------------------------------------
23
24 class DebugWriter(WriterBase):
25 """Consumes output from nbconvert export...() methods and writes usefull
26 debugging information to the stdout. The information includes a list of
27 resources that were extracted from the notebook(s) during export."""
28
29
30 def write(self, output, resources, **kw):
31 """
32 Consume and write Jinja output.
33
34 See base for more...
35 """
36
37 if 'figures' in resources:
38 print("Figures extracted from %s" % notebook_name)
39 print('-' * 80)
40 pprint.pprint(resources['figures'], indent=2, width=70)
41 else:
42 print("No figures extracted from %s" % notebook_name)
43 print('=' * 80)
@@ -0,0 +1,98 b''
1 #!/usr/bin/env python
2 """
3 Contains writer for writing nbconvert output to filesystem.
4 """
5 #-----------------------------------------------------------------------------
6 #Copyright (c) 2013, the IPython Development Team.
7 #
8 #Distributed under the terms of the Modified BSD License.
9 #
10 #The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 import io
18 import os
19 import shutil
20 import glob
21
22 from IPython.utils.traitlets import Unicode
23
24 from .base import WriterBase
25
26 #-----------------------------------------------------------------------------
27 # Classes
28 #-----------------------------------------------------------------------------
29
30 class FilesWriter(WriterBase):
31 """Consumes nbconvert output and produces files."""
32
33
34 build_directory = Unicode("nbconvert_build", config=True,
35 help="""Directory to write output to. Leave blank
36 to output to the current directory""")
37
38
39 #Make sure that the output directory exists.
40 def _build_directory_changed(self, name, old, new):
41 if new and not os.path.isdir(new):
42 os.makedirs(new)
43
44
45 def __init__(self, **kw):
46 super(FilesWriter, self).__init__(**kw)
47 self._build_directory_changed('build_directory', self.build_directory,
48 self.build_directory)
49
50
51 def write(self, output, resources, notebook_name=None, **kw):
52 """
53 Consume and write Jinja output to the file system. Output directory
54 is set via the 'build_directory' variable of this instance (a
55 configurable).
56
57 See base for more...
58 """
59
60 #Pull the extension from the resources dict.
61 output_extension = resources['output_extension']
62
63 #Write all of the extracted resources to the destination directory.
64 #NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
65 #TRANSFORMER SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
66 for filename, data in resources.get('figures', {}).items():
67
68 #Determine where to write the file to
69 dest = os.path.join(self.build_directory, filename)
70
71 #Write file
72 with io.open(dest, 'wb') as f:
73 f.write(data)
74
75 #Copy referenced files to output directory
76 if self.build_directory:
77 for filename in self.files:
78
79 #Copy files that match search pattern
80 for matching_filename in glob.glob(filename):
81
82 #Make sure folder exists.
83 dest = os.path.join(self.build_directory, filename)
84 path = os.path.dirname(dest)
85 if not os.path.isdir(path):
86 os.makedirs(path)
87
88 #Copy
89 shutil.copyfile(matching_filename, dest)
90
91 #Determine where to write conversion results.
92 dest = notebook_name + '.' + output_extension
93 if self.build_directory:
94 dest = os.path.join(self.build_directory, dest)
95
96 #Write conversion results.
97 with io.open(dest, 'w') as f:
98 f.write(output)
@@ -0,0 +1,37 b''
1 #!/usr/bin/env python
2 """
3 Contains Stdout writer
4 """
5 #-----------------------------------------------------------------------------
6 #Copyright (c) 2013, the IPython Development Team.
7 #
8 #Distributed under the terms of the Modified BSD License.
9 #
10 #The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
17 from .base import WriterBase
18
19 #-----------------------------------------------------------------------------
20 # Classes
21 #-----------------------------------------------------------------------------
22
23 class StdoutWriter(WriterBase):
24 """Consumes output from nbconvert export...() methods and writes to the
25 stdout stream. Allows for quick debuging of nbconvert output. Using the
26 debug flag makes the writer pretty-print the figures contained within the
27 notebook."""
28
29
30 def write(self, output, resources, **kw):
31 """
32 Consume and write Jinja output.
33
34 See base for more...
35 """
36
37 print(output)
@@ -3,3 +3,4 b''
3 from .exporters import *
3 from .exporters import *
4 import filters
4 import filters
5 import transformers
5 import transformers
6 import writers
@@ -6,6 +6,6 b' from .reveal import RevealExporter'
6 from .latex import LatexExporter
6 from .latex import LatexExporter
7 from .markdown import MarkdownExporter
7 from .markdown import MarkdownExporter
8 from .python import PythonExporter
8 from .python import PythonExporter
9 from .rst import RstExporter
9 from .rst import RSTExporter
10 from .sphinx_howto import SphinxHowtoExporter
10 from .sphinx_howto import SphinxHowtoExporter
11 from .sphinx_manual import SphinxManualExporter
11 from .sphinx_manual import SphinxManualExporter
@@ -14,9 +14,9 b' Exporter that exports Basic HTML.'
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.utils.traitlets import Unicode
17 from IPython.utils.traitlets import Unicode, List
18
18
19 from ..transformers.csshtmlheader import CSSHTMLHeaderTransformer
19 from IPython.nbconvert import transformers
20
20
21 from .exporter import Exporter
21 from .exporter import Exporter
22
22
@@ -40,16 +40,3 b' class BasicHTMLExporter(Exporter):'
40 template_file = Unicode(
40 template_file = Unicode(
41 'basichtml', config=True,
41 'basichtml', config=True,
42 help="Name of the template file to use")
42 help="Name of the template file to use")
43
44
45 def _register_transformers(self):
46 """
47 Register all of the transformers needed for this exporter.
48 """
49
50 #Register the transformers of the base class.
51 super(BasicHTMLExporter, self)._register_transformers()
52
53 #Register CSSHTMLHeaderTransformer transformer
54 self.register_transformer(CSSHTMLHeaderTransformer)
55
@@ -16,6 +16,7 b' Module containing single call export functions.'
16 from functools import wraps
16 from functools import wraps
17
17
18 from IPython.nbformat.v3.nbbase import NotebookNode
18 from IPython.nbformat.v3.nbbase import NotebookNode
19 from IPython.config import Config
19
20
20 from .exporter import Exporter
21 from .exporter import Exporter
21 from .basichtml import BasicHTMLExporter
22 from .basichtml import BasicHTMLExporter
@@ -24,7 +25,7 b' from .latex import LatexExporter'
24 from .markdown import MarkdownExporter
25 from .markdown import MarkdownExporter
25 from .python import PythonExporter
26 from .python import PythonExporter
26 from .reveal import RevealExporter
27 from .reveal import RevealExporter
27 from .rst import RstExporter
28 from .rst import RSTExporter
28 from .sphinx_howto import SphinxHowtoExporter
29 from .sphinx_howto import SphinxHowtoExporter
29 from .sphinx_manual import SphinxManualExporter
30 from .sphinx_manual import SphinxManualExporter
30
31
@@ -32,22 +33,15 b' from .sphinx_manual import SphinxManualExporter'
32 # Classes
33 # Classes
33 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
34
35
35 def DocDecorator(f):
36 def DocDecorator(f):
36
37
37 #Set docstring of function
38 #Set docstring of function
38 f.__doc__ = f.__doc__ + """
39 f.__doc__ = f.__doc__ + """
39 nb : Notebook node
40 nb : Notebook node
40 config : config
41 config : config (optional, keyword arg)
41 User configuration instance.
42 User configuration instance.
42 transformers : list[of transformer]
43 resources : dict (optional, keyword arg)
43 Custom transformers to apply to the notebook prior to engaging
44 Resources used in the conversion process.
44 the Jinja template engine. Any transformers specified here
45 will override existing transformers if a naming conflict
46 occurs.
47 filters : list[of filter]
48 Custom filters to make accessible to the Jinja templates. Any
49 filters specified here will override existing filters if a
50 naming conflict occurs.
51
45
52 Returns
46 Returns
53 ----------
47 ----------
@@ -85,139 +79,148 b' __all__ = ['
85 'export_reveal',
79 'export_reveal',
86 'export_rst',
80 'export_rst',
87 'export_by_name',
81 'export_by_name',
88 'get_export_names'
82 'get_export_names',
83 'ExporterNameError'
89 ]
84 ]
90
85
86
87 class ExporterNameError(NameError):
88 pass
89
90
91 @DocDecorator
91 @DocDecorator
92 def export(exporter_type, nb, config=None, transformers=None, filters=None):
92 def export(exporter, nb, **kw):
93 """
93 """
94 Export a notebook object using specific exporter class.
94 Export a notebook object using specific exporter class.
95
95
96 exporter_type : Exporter class type
96 exporter : Exporter class type or instance
97 Class type of the exporter that should be used. This method
97 Class type or instance of the exporter that should be used. If the
98 will initialize it's own instance of the class. It is
98 method initializes it's own instance of the class, it is ASSUMED that
99 ASSUMED that the class type provided exposes a
99 the class type provided exposes a constructor (__init__) with the same
100 constructor (__init__) with the same signature as the
100 signature as the base Exporter class.
101 base Exporter class.}
102 """
101 """
103
102
104 #Check arguments
103 #Check arguments
105 if exporter_type is None:
104 if exporter is None:
106 raise TypeError("Exporter is None")
105 raise TypeError("Exporter is None")
107 elif not issubclass(exporter_type, Exporter):
106 elif not isinstance(exporter, Exporter) and not issubclass(exporter, Exporter):
108 raise TypeError("Exporter type does not inherit from Exporter (base)")
107 raise TypeError("exporter does not inherit from Exporter (base)")
109
110 if nb is None:
108 if nb is None:
111 raise TypeError("nb is None")
109 raise TypeError("nb is None")
112
110
113 #Create the exporter
111 #Create the exporter
114 exporter_instance = exporter_type(preprocessors=transformers,
112 resources = kw.pop('resources', None)
115 jinja_filters=filters, config=config)
113 if isinstance(exporter, Exporter):
114 exporter_instance = exporter
115 else:
116 exporter_instance = exporter(**kw)
116
117
117 #Try to convert the notebook using the appropriate conversion function.
118 #Try to convert the notebook using the appropriate conversion function.
118 if isinstance(nb, NotebookNode):
119 if isinstance(nb, NotebookNode):
119 output, resources = exporter_instance.from_notebook_node(nb)
120 output, resources = exporter_instance.from_notebook_node(nb, resources)
120 elif isinstance(nb, basestring):
121 elif isinstance(nb, basestring):
121 output, resources = exporter_instance.from_filename(nb)
122 output, resources = exporter_instance.from_filename(nb, resources)
122 else:
123 else:
123 output, resources = exporter_instance.from_file(nb)
124 output, resources = exporter_instance.from_file(nb, resources)
124 return output, resources, exporter_instance
125 return output, resources
125
126
126
127
127 @DocDecorator
128 @DocDecorator
128 def export_sphinx_manual(nb, config=None, transformers=None, filters=None):
129 def export_sphinx_manual(nb, **kw):
129 """
130 """
130 Export a notebook object to Sphinx Manual LaTeX
131 Export a notebook object to Sphinx Manual LaTeX
131 """
132 """
132 return export(SphinxManualExporter, nb, config, transformers, filters)
133 return export(SphinxManualExporter, nb, **kw)
133
134
134
135
135 @DocDecorator
136 @DocDecorator
136 def export_sphinx_howto(nb, config=None, transformers=None, filters=None):
137 def export_sphinx_howto(nb, **kw):
137 """
138 """
138 Export a notebook object to Sphinx HowTo LaTeX
139 Export a notebook object to Sphinx HowTo LaTeX
139 """
140 """
140 return export(SphinxHowtoExporter, nb, config, transformers, filters)
141 return export(SphinxHowtoExporter, nb, **kw)
141
142
142
143
143 @DocDecorator
144 @DocDecorator
144 def export_basic_html(nb, config=None, transformers=None, filters=None):
145 def export_basic_html(nb, **kw):
145 """
146 """
146 Export a notebook object to Basic HTML
147 Export a notebook object to Basic HTML
147 """
148 """
148 return export(BasicHTMLExporter, nb, config, transformers, filters)
149 return export(BasicHTMLExporter, nb, **kw)
149
150
150
151
151 @DocDecorator
152 @DocDecorator
152 def export_full_html(nb, config=None, transformers=None, filters=None):
153 def export_full_html(nb, **kw):
153 """
154 """
154 Export a notebook object to Full HTML
155 Export a notebook object to Full HTML
155 """
156 """
156 return export(FullHTMLExporter, nb, config, transformers, filters)
157 return export(FullHTMLExporter, nb, **kw)
157
158
158
159
159 @DocDecorator
160 @DocDecorator
160 def export_latex(nb, config=None, transformers=None, filters=None):
161 def export_latex(nb, **kw):
161 """
162 """
162 Export a notebook object to LaTeX
163 Export a notebook object to LaTeX
163 """
164 """
164 return export(LatexExporter, nb, config, transformers, filters)
165 return export(LatexExporter, nb, **kw)
165
166
166
167
167 @DocDecorator
168 @DocDecorator
168 def export_markdown(nb, config=None, transformers=None, filters=None):
169 def export_markdown(nb, **kw):
169 """
170 """
170 Export a notebook object to Markdown
171 Export a notebook object to Markdown
171 """
172 """
172 return export(MarkdownExporter, nb, config, transformers, filters)
173 return export(MarkdownExporter, nb, **kw)
173
174
174
175
175 @DocDecorator
176 @DocDecorator
176 def export_python(nb, config=None, transformers=None, filters=None):
177 def export_python(nb, **kw):
177 """
178 """
178 Export a notebook object to Python
179 Export a notebook object to Python
179 """
180 """
180 return export(PythonExporter, nb, config, transformers, filters)
181 return export(PythonExporter, nb, **kw)
181
182
182
183
183 @DocDecorator
184 @DocDecorator
184 def export_reveal(nb, config=None, transformers=None, filters=None):
185 def export_reveal(nb, **kw):
185 """
186 """
186 Export a notebook object to Reveal
187 Export a notebook object to a Reveal.js presentation
187 """
188 """
188 return export(RevealExporter, nb, config, transformers, filters)
189 return export(RevealExporter, nb, **kw)
189
190
190
191
191 @DocDecorator
192 @DocDecorator
192 def export_rst(nb, config=None, transformers=None, filters=None):
193 def export_rst(nb, **kw):
193 """
194 """
194 Export a notebook object to RST
195 Export a notebook object to reStructuredText
195 """
196 """
196 return export(RstExporter, nb, config, transformers, filters)
197 return export(RSTExporter, nb, **kw)
197
198
198
199
199 @DocDecorator
200 @DocDecorator
200 def export_by_name(template_name, nb, config=None, transformers=None, filters=None):
201 def export_by_name(format_name, nb, **kw):
201 """
202 """
202 Export a notebook object to a template type by its name. Reflection
203 Export a notebook object to a template type by its name. Reflection
203 (Inspect) is used to find the template's corresponding explicit export
204 (Inspect) is used to find the template's corresponding explicit export
204 method defined in this module. That method is then called directly.
205 method defined in this module. That method is then called directly.
205
206
206 template_name : str
207 format_name : str
207 Name of the template style to export to.
208 Name of the template style to export to.
208 """
209 """
209
210
210 function_name = "export_" + template_name.lower()
211 function_name = "export_" + format_name.lower()
211
212
212 if function_name in globals():
213 if function_name in globals():
213 return globals()[function_name](nb, config, transformers, filters)
214 return globals()[function_name](nb, **kw)
214 else:
215 else:
215 raise NameError("template for `%s` not found" % function_name)
216 raise ExporterNameError("template for `%s` not found" % function_name)
217
216
218
217 def get_export_names():
219 def get_export_names():
218 "Return a list of the currently supported export targets"
220 "Return a list of the currently supported export targets"
219 # grab everything after 'export_'
221 # grab everything after 'export_'
220 l = [x[len('export_'):] for x in __all__ if x.startswith('export_')]
222 l = [x[len('export_'):] for x in __all__ if x.startswith('export_')]
223
221 # filter out the one method that is not a template
224 # filter out the one method that is not a template
222 l = [x for x in l if 'by_name' not in x]
225 l = [x for x in l if 'by_name' not in x]
223 return sorted(l)
226 return sorted(l)
@@ -20,7 +20,10 b' from __future__ import print_function, absolute_import'
20 import io
20 import io
21 import os
21 import os
22 import inspect
22 import inspect
23 from copy import deepcopy
23 import types
24 import copy
25 import collections
26 import datetime
24
27
25 # other libs/dependencies
28 # other libs/dependencies
26 from jinja2 import Environment, FileSystemLoader, ChoiceLoader
29 from jinja2 import Environment, FileSystemLoader, ChoiceLoader
@@ -29,11 +32,12 b' from jinja2 import Environment, FileSystemLoader, ChoiceLoader'
29 from IPython.config.configurable import Configurable
32 from IPython.config.configurable import Configurable
30 from IPython.config import Config
33 from IPython.config import Config
31 from IPython.nbformat import current as nbformat
34 from IPython.nbformat import current as nbformat
32 from IPython.utils.traitlets import MetaHasTraits, Unicode
35 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict
36 from IPython.utils.importstring import import_item
33 from IPython.utils.text import indent
37 from IPython.utils.text import indent
34
38
39 from IPython.nbconvert import transformers as nbtransformers
35 from IPython.nbconvert import filters
40 from IPython.nbconvert import filters
36 from IPython.nbconvert import transformers
37
41
38 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
39 # Globals and constants
43 # Globals and constants
@@ -68,6 +72,11 b' default_filters = {'
68 # Class
72 # Class
69 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
70
74
75 class ResourcesDict(collections.defaultdict):
76 def __missing__(self, key):
77 return ''
78
79
71 class Exporter(Configurable):
80 class Exporter(Configurable):
72 """
81 """
73 Exports notebooks into other file formats. Uses Jinja 2 templating engine
82 Exports notebooks into other file formats. Uses Jinja 2 templating engine
@@ -112,27 +121,32 b' class Exporter(Configurable):'
112 #Extension that the template files use.
121 #Extension that the template files use.
113 template_extension = Unicode(".tpl", config=True)
122 template_extension = Unicode(".tpl", config=True)
114
123
115 #Processors that process the input data prior to the export, set in the
124 #Configurability, allows the user to easily add filters and transformers.
116 #constructor for this class.
125 transformers = List(config=True,
117 transformers = None
126 help="""List of transformers, by name or namespace, to enable.""")
118
127
119
128 filters = Dict(config=True,
120 def __init__(self, transformers=None, filters=None, config=None, extra_loaders=None, **kw):
129 help="""Dictionary of filters, by name and namespace, to add to the Jinja
130 environment.""")
131
132 default_transformers = List([nbtransformers.coalesce_streams,
133 nbtransformers.SVG2PDFTransformer,
134 nbtransformers.ExtractFigureTransformer,
135 nbtransformers.CSSHTMLHeaderTransformer,
136 nbtransformers.RevealHelpTransformer,
137 nbtransformers.LatexTransformer,
138 nbtransformers.SphinxTransformer],
139 config=True,
140 help="""List of transformers available by default, by name, namespace,
141 instance, or type.""")
142
143
144 def __init__(self, config=None, extra_loaders=None, **kw):
121 """
145 """
122 Public constructor
146 Public constructor
123
147
124 Parameters
148 Parameters
125 ----------
149 ----------
126 transformers : list[of transformer]
127 Custom transformers to apply to the notebook prior to engaging
128 the Jinja template engine. Any transformers specified here
129 will override existing transformers if a naming conflict
130 occurs.
131 filters : dict[of filter]
132 filters specified here will override existing filters if a naming
133 conflict occurs. Filters are availlable in jinja template through
134 the name of the corresponding key. Cf class docstring for
135 availlable default filters.
136 config : config
150 config : config
137 User configuration instance.
151 User configuration instance.
138 extra_loaders : list[of Jinja Loaders]
152 extra_loaders : list[of Jinja Loaders]
@@ -147,53 +161,41 b' class Exporter(Configurable):'
147
161
148 super(Exporter, self).__init__(config=c, **kw)
162 super(Exporter, self).__init__(config=c, **kw)
149
163
150 #Standard environment
164 #Init
151 self._init_environment(extra_loaders=extra_loaders)
165 self._init_environment(extra_loaders=extra_loaders)
166 self._init_transformers()
167 self._init_filters()
152
168
153 #Add transformers
154 self._register_transformers()
155
156 #Add filters to the Jinja2 environment
157 self._register_filters()
158
159 #Load user transformers. Overwrite existing transformers if need be.
160 if transformers :
161 for transformer in transformers:
162 self.register_transformer(transformer)
163
164 #Load user filters. Overwrite existing filters if need be.
165 if not filters is None:
166 for key, user_filter in filters.iteritems():
167 self.register_filter(key, user_filter)
168
169
169 @property
170 @property
170 def default_config(self):
171 def default_config(self):
171 return Config()
172 return Config()
172
173
173
174
174
175 def from_notebook_node(self, nb, resources=None, **kw):
175 def from_notebook_node(self, nb, resources=None):
176 """
176 """
177 Convert a notebook from a notebook node instance.
177 Convert a notebook from a notebook node instance.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 nb : Notebook node
181 nb : Notebook node
182 resources : a dict of additional resources that
182 resources : dict (**kw)
183 can be accessed read/write by transformers
183 of additional resources that can be accessed read/write by
184 and filters.
184 transformers and filters.
185 """
185 """
186 if resources is None:
186 nb_copy = copy.deepcopy(nb)
187 resources = {}
187 resources = self._init_resources(resources)
188 nb, resources = self._preprocess(nb, resources)
188
189
189 #Preprocess
190 #Load the template file.
190 nb_copy, resources = self._transform(nb_copy, resources)
191 self.template = self.environment.get_template(self.template_file+self.template_extension)
192
193 return self.template.render(nb=nb, resources=resources), resources
194
191
192 #Convert
193 self.template = self.environment.get_template(self.template_file + self.template_extension)
194 output = self.template.render(nb=nb_copy, resources=resources)
195 return output, resources
195
196
196 def from_filename(self, filename):
197
198 def from_filename(self, filename, resources=None, **kw):
197 """
199 """
198 Convert a notebook from a notebook file.
200 Convert a notebook from a notebook file.
199
201
@@ -202,12 +204,24 b' class Exporter(Configurable):'
202 filename : str
204 filename : str
203 Full filename of the notebook file to open and convert.
205 Full filename of the notebook file to open and convert.
204 """
206 """
207
208 #Pull the metadata from the filesystem.
209 if resources is None:
210 resources = ResourcesDict()
211 if not 'metadata' in resources or resources['metadata'] == '':
212 resources['metadata'] = ResourcesDict()
213 basename = os.path.basename(filename)
214 notebook_name = basename[:basename.rfind('.')]
215 resources['metadata']['name'] = notebook_name
216
217 modified_date = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
218 resources['metadata']['modified_date'] = modified_date.strftime("%B %-d, %Y")
205
219
206 with io.open(filename) as f:
220 with io.open(filename) as f:
207 return self.from_notebook_node(nbformat.read(f, 'json'))
221 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
208
222
209
223
210 def from_file(self, file_stream):
224 def from_file(self, file_stream, resources=None, **kw):
211 """
225 """
212 Convert a notebook from a notebook file.
226 Convert a notebook from a notebook file.
213
227
@@ -216,10 +230,10 b' class Exporter(Configurable):'
216 file_stream : file-like object
230 file_stream : file-like object
217 Notebook file-like object to convert.
231 Notebook file-like object to convert.
218 """
232 """
219 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
233 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
220
234
221
235
222 def register_transformer(self, transformer):
236 def register_transformer(self, transformer, enabled=False):
223 """
237 """
224 Register a transformer.
238 Register a transformer.
225 Transformers are classes that act upon the notebook before it is
239 Transformers are classes that act upon the notebook before it is
@@ -231,20 +245,39 b' class Exporter(Configurable):'
231 ----------
245 ----------
232 transformer : transformer
246 transformer : transformer
233 """
247 """
234 if self.transformers is None:
248 if transformer is None:
235 self.transformers = []
249 raise TypeError('transformer')
250 isclass = inspect.isclass(transformer)
251 constructed = not isclass
252
253 #Handle transformer's registration based on it's type
254 if constructed and isinstance(transformer, types.StringTypes):
255 #Transformer is a string, import the namespace and recursively call
256 #this register_transformer method
257 transformer_cls = import_item(transformer)
258 return self.register_transformer(transformer_cls, enabled)
236
259
237 if inspect.isfunction(transformer):
260 if constructed and hasattr(transformer, '__call__'):
238 self.transformers.append(transformer)
261 #Transformer is a function, no need to construct it.
262 #Register and return the transformer.
263 if enabled:
264 transformer.enabled = True
265 self._transformers.append(transformer)
239 return transformer
266 return transformer
240 elif isinstance(transformer, MetaHasTraits):
267
241 transformer_instance = transformer(config=self.config)
268 elif isclass and isinstance(transformer, MetaHasTraits):
242 self.transformers.append(transformer_instance)
269 #Transformer is configurable. Make sure to pass in new default for
243 return transformer_instance
270 #the enabled flag if one was specified.
271 self.register_transformer(transformer(parent=self), enabled)
272
273 elif isclass:
274 #Transformer is not configurable, construct it
275 self.register_transformer(transformer(), enabled)
276
244 else:
277 else:
245 transformer_instance = transformer()
278 #Transformer is an instance of something without a __call__
246 self.transformers.append(transformer_instance)
279 #attribute.
247 return transformer_instance
280 raise TypeError('transformer')
248
281
249
282
250 def register_filter(self, name, filter):
283 def register_filter(self, name, filter):
@@ -259,34 +292,37 b' class Exporter(Configurable):'
259 name to give the filter in the Jinja engine
292 name to give the filter in the Jinja engine
260 filter : filter
293 filter : filter
261 """
294 """
262 if inspect.isfunction(filter):
295 if filter is None:
296 raise TypeError('filter')
297 isclass = inspect.isclass(filter)
298 constructed = not isclass
299
300 #Handle filter's registration based on it's type
301 if constructed and isinstance(filter, types.StringTypes):
302 #filter is a string, import the namespace and recursively call
303 #this register_filter method
304 filter_cls = import_item(filter)
305 return self.register_filter(name, filter_cls)
306
307 if constructed and hasattr(filter, '__call__'):
308 #filter is a function, no need to construct it.
263 self.environment.filters[name] = filter
309 self.environment.filters[name] = filter
264 elif isinstance(filter, MetaHasTraits):
310 return filter
265 self.environment.filters[name] = filter(config=self.config)
311
312 elif isclass and isinstance(filter, MetaHasTraits):
313 #filter is configurable. Make sure to pass in new default for
314 #the enabled flag if one was specified.
315 self.register_filter(name, filter(parent=self))
316
317 elif isclass:
318 #filter is not configurable, construct it
319 self.register_filter(name, filter())
320
266 else:
321 else:
267 self.environment.filters[name] = filter()
322 #filter is an instance of something without a __call__
268 return self.environment.filters[name]
323 #attribute.
324 raise TypeError('filter')
269
325
270
271 def _register_transformers(self):
272 """
273 Register all of the transformers needed for this exporter.
274 """
275
276 self.register_transformer(transformers.coalesce_streams)
277
278 #Remember the figure extraction transformer so it can be enabled and
279 #disabled easily later.
280 self.extract_figure_transformer = self.register_transformer(transformers.ExtractFigureTransformer)
281
282
283 def _register_filters(self):
284 """
285 Register all of the filters required for the exporter.
286 """
287 for k, v in default_filters.iteritems():
288 self.register_filter(k, v)
289
290
326
291 def _init_environment(self, extra_loaders=None):
327 def _init_environment(self, extra_loaders=None):
292 """
328 """
@@ -321,8 +357,65 b' class Exporter(Configurable):'
321 if self.jinja_comment_block_end:
357 if self.jinja_comment_block_end:
322 self.environment.comment_end_string = self.jinja_comment_block_end
358 self.environment.comment_end_string = self.jinja_comment_block_end
323
359
360
361 def _init_transformers(self):
362 """
363 Register all of the transformers needed for this exporter, disabled
364 unless specified explicitly.
365 """
366 self._transformers = []
367
368 #Load default transformers (not necessarly enabled by default).
369 if self.default_transformers:
370 for transformer in self.default_transformers:
371 self.register_transformer(transformer)
372
373 #Load user transformers. Enable by default.
374 if self.transformers:
375 for transformer in self.transformers:
376 self.register_transformer(transformer, enabled=True)
377
378
379 def _init_filters(self):
380 """
381 Register all of the filters required for the exporter.
382 """
383
384 #Add default filters to the Jinja2 environment
385 for key, value in default_filters.iteritems():
386 self.register_filter(key, value)
387
388 #Load user filters. Overwrite existing filters if need be.
389 if self.filters:
390 for key, user_filter in self.filters.iteritems():
391 self.register_filter(key, user_filter)
392
393
394 def _init_resources(self, resources):
324
395
325 def _preprocess(self, nb, resources):
396 #Make sure the resources dict is of ResourcesDict type.
397 if resources is None:
398 resources = ResourcesDict()
399 if not isinstance(resources, ResourcesDict):
400 new_resources = ResourcesDict()
401 new_resources.update(resources)
402 resources = new_resources
403
404 #Make sure the metadata extension exists in resources
405 if 'metadata' in resources:
406 if not isinstance(resources['metadata'], ResourcesDict):
407 resources['metadata'] = ResourcesDict(resources['metadata'])
408 else:
409 resources['metadata'] = ResourcesDict()
410 if not resources['metadata']['name']:
411 resources['metadata']['name'] = 'Notebook'
412
413 #Set the output extension
414 resources['output_extension'] = self.file_extension
415 return resources
416
417
418 def _transform(self, nb, resources):
326 """
419 """
327 Preprocess the notebook before passing it into the Jinja engine.
420 Preprocess the notebook before passing it into the Jinja engine.
328 To preprocess the notebook is to apply all of the
421 To preprocess the notebook is to apply all of the
@@ -336,13 +429,13 b' class Exporter(Configurable):'
336 and filters.
429 and filters.
337 """
430 """
338
431
339 # Do a deepcopy first,
432 # Do a copy.deepcopy first,
340 # we are never safe enough with what the transformers could do.
433 # we are never safe enough with what the transformers could do.
341 nbc = deepcopy(nb)
434 nbc = copy.deepcopy(nb)
342 resc = deepcopy(resources)
435 resc = copy.deepcopy(resources)
436
343 #Run each transformer on the notebook. Carry the output along
437 #Run each transformer on the notebook. Carry the output along
344 #to each transformer
438 #to each transformer
345 for transformer in self.transformers:
439 for transformer in self._transformers:
346 nb, resources = transformer(nbc, resc)
440 nbc, resc = transformer(nbc, resc)
347 return nb, resources
441 return nbc, resc
348
@@ -20,7 +20,7 b' tags to circumvent Jinja/Latex syntax conflicts.'
20 import os
20 import os
21
21
22 # IPython imports
22 # IPython imports
23 from IPython.utils.traitlets import Unicode
23 from IPython.utils.traitlets import Unicode, List
24 from IPython.config import Config
24 from IPython.config import Config
25
25
26 from IPython.nbconvert import filters, transformers
26 from IPython.nbconvert import filters, transformers
@@ -68,41 +68,35 b' class LatexExporter(Exporter):'
68 #Extension that the template files use.
68 #Extension that the template files use.
69 template_extension = Unicode(".tplx", config=True)
69 template_extension = Unicode(".tplx", config=True)
70
70
71 def _register_filters(self):
71
72 def _init_filters(self):
72 """
73 """
73 Register all of the filters required for the exporter.
74 Register all of the filters required for the exporter.
74 """
75 """
75
76
76 #Register the filters of the base class.
77 #Register the filters of the base class.
77 super(LatexExporter, self)._register_filters()
78 super(LatexExporter, self)._init_filters()
78
79
79 #Add latex filters to the Jinja2 environment
80 #Add latex filters to the Jinja2 environment
80 self.register_filter('escape_tex', filters.escape_latex)
81 self.register_filter('escape_tex', filters.escape_latex)
81 self.register_filter('highlight', filters.highlight2latex)
82 self.register_filter('highlight', filters.highlight2latex)
82
83
83
84 def _register_transformers(self):
85 """
86 Register all of the transformers needed for this exporter.
87 """
88
89 #Register the transformers of the base class.
90 super(LatexExporter, self)._register_transformers()
91
92 #Register latex transformer
93 self.register_transformer(transformers.LatexTransformer)
94
84
95 @property
85 @property
96 def default_config(self):
86 def default_config(self):
97 c = Config({
87 c = Config({
98 'GlobalConfigurable': {
88 'NbConvertBase': {
99 'display_data_priority' : ['latex', 'svg', 'png', 'jpg', 'jpeg' , 'text']
89 'display_data_priority' : ['latex', 'png', 'jpg', 'svg', 'jpeg', 'text']
100 },
90 },
101 'ExtractFigureTransformer': {
91 'ExtractFigureTransformer': {
102 'enabled':True,
92 'enabled':True
103 'extra_ext_map':{'svg':'pdf'},
93 },
94 'SVG2PDFTransformer': {
95 'enabled':True
96 },
97 'LatexTransformer': {
98 'enabled':True
104 }
99 }
105 })
100 })
106 c.merge(super(LatexExporter,self).default_config)
101 c.merge(super(LatexExporter,self).default_config)
107 return c
102 return c
108
@@ -13,7 +13,7 b' Reveal slide show exporter.'
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.utils.traitlets import Unicode
16 from IPython.utils.traitlets import Unicode, List
17 from IPython.config import Config
17 from IPython.config import Config
18
18
19 from .basichtml import BasicHTMLExporter
19 from .basichtml import BasicHTMLExporter
@@ -35,17 +35,7 b' class RevealExporter(BasicHTMLExporter):'
35 template_file = Unicode(
35 template_file = Unicode(
36 'reveal', config=True,
36 'reveal', config=True,
37 help="Name of the template file to use")
37 help="Name of the template file to use")
38
38
39 def _register_transformers(self):
40 """
41 Register all of the transformers needed for this exporter.
42 """
43
44 #Register the transformers of the base class.
45 super(RevealExporter, self)._register_transformers()
46
47 #Register reveal help transformer
48 self.register_transformer(transformers.RevealHelpTransformer)
49
39
50 @property
40 @property
51 def default_config(self):
41 def default_config(self):
@@ -22,7 +22,7 b' from .exporter import Exporter'
22 # Classes
22 # Classes
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class RstExporter(Exporter):
25 class RSTExporter(Exporter):
26 """
26 """
27 Exports restructured text documents.
27 Exports restructured text documents.
28 """
28 """
@@ -38,5 +38,5 b' class RstExporter(Exporter):'
38 @property
38 @property
39 def default_config(self):
39 def default_config(self):
40 c = Config({'ExtractFigureTransformer':{'enabled':True}})
40 c = Config({'ExtractFigureTransformer':{'enabled':True}})
41 c.merge(super(RstExporter,self).default_config)
41 c.merge(super(RSTExporter,self).default_config)
42 return c
42 return c
@@ -14,7 +14,7 b' formatted for use with PDFLatex.'
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.utils.traitlets import Unicode
17 from IPython.utils.traitlets import Unicode, List
18 from IPython.config import Config
18 from IPython.config import Config
19
19
20 # local import
20 # local import
@@ -36,19 +36,9 b' class SphinxHowtoExporter(LatexExporter):'
36 'sphinx_howto', config=True,
36 'sphinx_howto', config=True,
37 help="Name of the template file to use")
37 help="Name of the template file to use")
38
38
39 def _register_transformers(self):
39
40
41 #Register the transformers of the base class.
42 super(SphinxHowtoExporter, self)._register_transformers()
43
44 #Register sphinx latex transformer
45 self.register_transformer(transformers.SphinxTransformer)
46
47 @property
40 @property
48 def default_config(self):
41 def default_config(self):
49 c = Config({
42 c = Config({'SphinxTransformer': {'enabled':True}})
50 'SphinxTransformer': {'enabled':True}
51 })
52 c.merge(super(SphinxHowtoExporter,self).default_config)
43 c.merge(super(SphinxHowtoExporter,self).default_config)
53 return c
44 return c
54
@@ -36,7 +36,7 b' def remove_ansi(source):'
36 Source to remove the ansi from
36 Source to remove the ansi from
37 """
37 """
38
38
39 return re.sub(r'\033\[(0|\d;\d\d)m', '', source)
39 return re.sub(r'\033\[(\d|;)+?m', '', source)
40
40
41
41
42 def ansi2html(text):
42 def ansi2html(text):
@@ -3,7 +3,7 b''
3 The filter contained in the file allows the converter templates to select
3 The filter contained in the file allows the converter templates to select
4 the output format that is most valuable to the active export format. The
4 the output format that is most valuable to the active export format. The
5 value of the different formats is set via
5 value of the different formats is set via
6 GlobalConfigurable.display_data_priority
6 NbConvertBase.display_data_priority
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (c) 2013, the IPython Development Team.
9 # Copyright (c) 2013, the IPython Development Team.
@@ -17,11 +17,11 b' GlobalConfigurable.display_data_priority'
17 # Classes and functions
17 # Classes and functions
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from ..utils.config import GlobalConfigurable
20 from ..utils.base import NbConvertBase
21
21
22 __all__ = ['DataTypeFilter']
22 __all__ = ['DataTypeFilter']
23
23
24 class DataTypeFilter(GlobalConfigurable):
24 class DataTypeFilter(NbConvertBase):
25 """ Returns the preferred display format """
25 """ Returns the preferred display format """
26
26
27 def __call__(self, output):
27 def __call__(self, output):
@@ -1,8 +1,7 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 Commandline interface for the NBConvert conversion utility. Read the
4 Command-line interface for the NbConvert conversion utility.
5 readme.rst for usage information
6 """
5 """
7 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
8 #Copyright (c) 2013, the IPython Development Team.
7 #Copyright (c) 2013, the IPython Development Team.
@@ -19,211 +18,212 b' readme.rst for usage information'
19 #Stdlib imports
18 #Stdlib imports
20 from __future__ import print_function
19 from __future__ import print_function
21 import sys
20 import sys
22 import io
23 import os
21 import os
22 import glob
24
23
25 #From IPython
24 #From IPython
26 from IPython.config.application import Application
25 from IPython.core.application import BaseIPythonApplication, base_aliases, base_flags
27 from IPython.utils.traitlets import Bool, Unicode
26 from IPython.config import catch_config_error, Configurable
28
27 from IPython.utils.traitlets import (
29 from .exporters.export import export_by_name, get_export_names
28 Unicode, List, Instance, DottedObjectName, Type, CaselessStrEnum,
30 from .exporters.exporter import Exporter
29 )
31 from .transformers import extractfigure
30 from IPython.utils.importstring import import_item
32 from .utils.config import GlobalConfigurable
33
34 #-----------------------------------------------------------------------------
35 #Globals and constants
36 #-----------------------------------------------------------------------------
37
38 #'Keys in resources' user prompt.
39 KEYS_PROMPT_HEAD = "====================== Keys in Resources =================================="
40 KEYS_PROMPT_BODY = """
41 ===========================================================================
42 You are responsible for writing these files into the appropriate
43 directory(ies) if need be. If you do not want to see this message, enable
44 the 'write' (boolean) flag of the converter.
45 ===========================================================================
46 """
47
48 _examples = """
49 ipython nbconvert rst Untitled0.ipynb # convert ipynb to ReStructured Text
50 ipython nbconvert latex Untitled0.ipynb # convert ipynb to LaTeX
51 ipython nbconvert reveal Untitled0.ipynb # convert to Reveal (HTML/JS) slideshow
52 """
53
31
32 from .exporters.export import export_by_name, get_export_names, ExporterNameError
33 from IPython.nbconvert import exporters, transformers, writers
34 from .utils.base import NbConvertBase
54
35
55 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
56 #Classes and functions
37 #Classes and functions
57 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
58
39
59 class NbConvertApp(Application):
40 nbconvert_aliases = {}
60 __doc__ = """IPython notebook conversion utility
41 nbconvert_aliases.update(base_aliases)
61
42 nbconvert_aliases.update({
62 Convert to and from notebook file type (*.ipynb)
43 'format' : 'NbConvertApp.export_format',
63
44 'notebooks' : 'NbConvertApp.notebooks',
64 ipython nbconvert TARGET FILENAME
45 'writer' : 'NbConvertApp.writer_class',
65
46 })
66 Supported export TARGETs are: %s
47
67 """ % (" ".join(get_export_names()))
48 nbconvert_flags = {}
68 description = Unicode(__doc__)
49 nbconvert_flags.update(base_flags)
69
50 nbconvert_flags.update({
70 examples = _examples
51 'stdout' : (
71
52 {'NbConvertApp' : {'writer_class' : "StdoutWriter"}},
72 stdout = Bool(
53 "Write notebook output to stdout instead of files."
73 False, config=True,
74 help="""Whether to print the converted IPYNB file to stdout
75 use full do diff files without actually writing a new file"""
76 )
77
78 write = Bool(
79 True, config=True,
80 help="""Should the converted notebook file be written to disk
81 along with potential extracted resources."""
82 )
54 )
55 })
83
56
84 aliases = {
85 'stdout':'NbConvertApp.stdout',
86 'write':'NbConvertApp.write',
87 }
88
57
89 flags = {}
58 class NbConvertApp(BaseIPythonApplication):
59 """Application used to convert to and from notebook file type (*.ipynb)"""
90
60
91 flags['stdout'] = (
61 name = 'ipython-nbconvert'
92 {'NbConvertApp' : {'stdout' : True}},
62 aliases = nbconvert_aliases
93 """Print converted file to stdout, equivalent to --stdout=True
63 flags = nbconvert_flags
94 """
64
95 )
65 def _classes_default(self):
96
66 classes = [NbConvertBase]
97 flags['no-write'] = (
67 for pkg in (exporters, transformers, writers):
98 {'NbConvertApp' : {'write' : True}},
68 for name in dir(pkg):
99 """Do not write to disk, equivalent to --write=False
69 cls = getattr(pkg, name)
100 """
70 if isinstance(cls, type) and issubclass(cls, Configurable):
71 classes.append(cls)
72 return classes
73
74 description = Unicode(
75 u"""This application is used to convert notebook files (*.ipynb)
76 to various other formats.""")
77
78 examples = Unicode(u"""
79 The simplest way to use nbconvert is
80
81 > ipython nbconvert mynotebook.ipynb
82
83 which will convert mynotebook.ipynb to the default format (probably HTML).
84
85 You can specify the export format with `--format`.
86 Options include {0}
87
88 > ipython nbconvert --format latex mynotebook.ipnynb
89
90 You can also pipe the output to stdout, rather than a file
91
92 > ipython nbconvert mynotebook.ipynb --stdout
93
94 Multiple notebooks can be given at the command line in a couple of
95 different ways:
96
97 > ipython nbconvert notebook*.ipynb
98 > ipython nbconvert notebook1.ipynb notebook2.ipynb
99
100 or you can specify the notebooks list in a config file, containing::
101
102 c.NbConvertApp.notebooks = ["my_notebook.ipynb"]
103
104 > ipython nbconvert --config mycfg.py
105 """.format(get_export_names()))
106 #Writer specific variables
107 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
108 help="""Instance of the writer class used to write the
109 results of the conversion.""")
110 writer_class = DottedObjectName('FilesWriter', config=True,
111 help="""Writer class used to write the
112 results of the conversion""")
113 writer_aliases = {'FilesWriter': 'IPython.nbconvert.writers.files.FilesWriter',
114 'DebugWriter': 'IPython.nbconvert.writers.debug.DebugWriter',
115 'StdoutWriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
116 writer_factory = Type()
117
118 def _writer_class_changed(self, name, old, new):
119 if new in self.writer_aliases:
120 new = self.writer_aliases[new]
121 self.writer_factory = import_item(new)
122
123
124 #Other configurable variables
125 export_format = CaselessStrEnum(get_export_names(),
126 default_value="full_html",
127 config=True,
128 help="""The export format to be used."""
101 )
129 )
102
130
131 notebooks = List([], config=True, help="""List of notebooks to convert.
132 Wildcards are supported.
133 Filenames passed positionally will be added to the list.
134 """)
135
136 @catch_config_error
137 def initialize(self, argv=None):
138 super(NbConvertApp, self).initialize(argv)
139 self.init_notebooks()
140 self.init_writer()
141
142 def init_notebooks(self):
143 """Construct the list of notebooks.
144 If notebooks are passed on the command-line,
145 they override notebooks specified in config files.
146 Glob each notebook to replace notebook patterns with filenames.
147 """
103
148
104 def __init__(self, **kwargs):
149 # Specifying notebooks on the command-line overrides (rather than adds)
105 """Public constructor"""
150 # the notebook list
106
151 if self.extra_args:
107 #Call base class
152 patterns = self.extra_args
108 super(NbConvertApp, self).__init__(**kwargs)
153 else:
109
154 patterns = self.notebooks
110 #Register class here to have help with help all
111 self.classes.insert(0, Exporter)
112 self.classes.insert(0, GlobalConfigurable)
113
155
156 #Use glob to replace all the notebook patterns with filenames.
157 filenames = []
158 for pattern in patterns:
159 for filename in glob.glob(pattern):
160 if not filename in filenames:
161 filenames.append(filename)
162 self.notebooks = filenames
114
163
115 def start(self, argv=None):
164 def init_writer(self):
116 """Entrypoint of NbConvert application.
117
118 Parameters
119 ----------
120 argv : list
121 Commandline arguments
122 """
165 """
123
166 Initialize the writer (which is stateless)
124 #Parse the commandline options.
167 """
125 self.parse_command_line(argv)
168 self._writer_class_changed(None, self.writer_class, self.writer_class)
169 self.writer = self.writer_factory(parent=self)
126
170
127 #Call base
171 def start(self):
172 """
173 Ran after initialization completed
174 """
128 super(NbConvertApp, self).start()
175 super(NbConvertApp, self).start()
176 self.convert_notebooks()
129
177
130 #The last arguments in list will be used by nbconvert
178 def convert_notebooks(self):
131 if len(self.extra_args) is not 3:
132 print( "Wrong number of arguments, use --help flag for usage", file=sys.stderr)
133 sys.exit(-1)
134 export_type = (self.extra_args)[1]
135 ipynb_file = (self.extra_args)[2]
136
137 #Export
138 try:
139 return_value = export_by_name(export_type, ipynb_file)
140 except NameError as e:
141 print("Error: '%s' exporter not found." % export_type,
142 file=sys.stderr)
143 print("Known exporters are:",
144 "\n\t" + "\n\t".join(get_export_names()),
145 file=sys.stderr)
146 sys.exit(-1)
147 else:
148 (output, resources, exporter) = return_value
149
150 #TODO: Allow user to set output directory and file.
151 destination_filename = None
152 destination_directory = None
153 if self.write:
154
155 #Get the file name without the '.ipynb' (6 chars) extension and then
156 #remove any addition periods and spaces. The resulting name will
157 #be used to create the directory that the files will be exported
158 #into.
159 out_root = ipynb_file[:-6].replace('.', '_').replace(' ', '_')
160 destination_filename = os.path.join(out_root+'.'+exporter.file_extension)
161
162 destination_directory = out_root+'_files'
163 if not os.path.exists(destination_directory):
164 os.mkdir(destination_directory)
165
166 #Write the results
167 if self.stdout or not (destination_filename is None and destination_directory is None):
168 self._write_results(output, resources, destination_filename, destination_directory)
169
170
171 def _write_results(self, output, resources, destination_filename=None, destination_directory=None):
172 """Output the conversion results to the console and/or filesystem
173
174 Parameters
175 ----------
176 output : str
177 Output of conversion
178 resources : dictionary
179 Additional input/output used by the transformers. For
180 example, the ExtractFigure transformer outputs the
181 figures it extracts into this dictionary. This method
182 relies on the figures being in this dictionary when
183 attempting to write the figures to the file system.
184 destination_filename : str, Optional
185 Filename to write output into. If None, output is not
186 written to a file.
187 destination_directory : str, Optional
188 Directory to write notebook data (i.e. figures) to. If
189 None, figures are not written to the file system.
190 """
179 """
191
180 Convert the notebooks in the self.notebook traitlet
192 if self.stdout:
181 """
193 print(output.encode('utf-8'))
182 #Export each notebook
194
183 conversion_success = 0
195 #Write file output from conversion.
184 for notebook_filename in self.notebooks:
196 if not destination_filename is None:
185
197 with io.open(destination_filename, 'w') as f:
186 #Get a unique key for the notebook and set it in the resources object.
198 f.write(output)
187 basename = os.path.basename(notebook_filename)
199
188 notebook_name = basename[:basename.rfind('.')]
200 #Get the key names used by the extract figure transformer
189 resources = {}
201 figures_key = extractfigure.FIGURES_KEY
190 resources['unique_key'] = notebook_name
202 binary_key = extractfigure.BINARY_KEY
191
203 text_key = extractfigure.TEXT_KEY
192 #Try to export
204
193 try:
205 #Output any associate figures into the same "root" directory.
194 output, resources = export_by_name(self.export_format,
206 binkeys = resources.get(figures_key, {}).get(binary_key,{}).keys()
195 notebook_filename,
207 textkeys = resources.get(figures_key, {}).get(text_key,{}).keys()
196 resources=resources,
208 if binkeys or textkeys :
197 config=self.config)
209 if not destination_directory is None:
198 except ExporterNameError as e:
210 for key in binkeys:
199 print("Error: '%s' exporter not found." % self.export_format,
211 with io.open(os.path.join(destination_directory, key), 'wb') as f:
200 file=sys.stderr)
212 f.write(resources[figures_key][binary_key][key])
201 print("Known exporters are:",
213 for key in textkeys:
202 "\n\t" + "\n\t".join(get_export_names()),
214 with io.open(os.path.join(destination_directory, key), 'w') as f:
203 file=sys.stderr)
215 f.write(resources[figures_key][text_key][key])
204 sys.exit(-1)
216
205 #except Exception as e:
217 #Figures that weren't exported which will need to be created by the
206 #print("Error: could not export '%s'" % notebook_filename, file=sys.stderr)
218 #user. Tell the user what figures these are.
207 #print(e, file=sys.stderr)
219 if self.stdout:
208 else:
220 print(KEYS_PROMPT_HEAD, file=sys.stderr)
209 self.writer.write(output, resources, notebook_name=notebook_name)
221 print(resources[figures_key].keys(), file=sys.stderr)
210 conversion_success += 1
222 print(KEYS_PROMPT_BODY , file=sys.stderr)
211
212 #If nothing was converted successfully, help the user.
213 if conversion_success == 0:
214
215 #No notebooks were specified, show help.
216 if len(self.notebooks) == 0:
217 self.print_help()
218
219 #Notebooks were specified, but not converted successfully. Show how
220 #to access help.
221 else:
222 print('For help, use "ipython nbconvert --help"')
223
223
224
224 #-----------------------------------------------------------------------------
225 #-----------------------------------------------------------------------------
225 # Main entry point
226 # Main entry point
226 #-----------------------------------------------------------------------------
227 #-----------------------------------------------------------------------------
227
228
228 launch_new_instance = NbConvertApp.launch_instance
229 launch_new_instance = NbConvertApp.launch_instance
229
@@ -41,21 +41,21 b' it introduces a new line'
41
41
42 ((*- block data_png -*))
42 ((*- block data_png -*))
43 \begin{center}
43 \begin{center}
44 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{(((output.key_png)))}
44 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{(((output.png_filename)))}
45 \par
45 \par
46 \end{center}
46 \end{center}
47 ((*- endblock -*))
47 ((*- endblock -*))
48
48
49 ((*- block data_jpg -*))
49 ((*- block data_jpg -*))
50 \begin{center}
50 \begin{center}
51 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{(((output.key_jpeg)))}
51 \includegraphics[max size={0.7\textwidth}{0.9\textheight}]{(((output.jpeg_filename)))}
52 \par
52 \par
53 \end{center}
53 \end{center}
54 ((*- endblock -*))
54 ((*- endblock -*))
55
55
56 ((*- block data_svg -*))
56 ((*- block data_svg -*))
57 \begin{center}
57 \begin{center}
58 \includegraphics[width=0.7\textwidth]{(((output.key_svg)))}
58 \includegraphics[width=0.7\textwidth]{(((output.svg_filename)))}
59 \par
59 \par
60 \end{center}
60 \end{center}
61 ((*- endblock -*))
61 ((*- endblock -*))
@@ -145,11 +145,11 b' Note: For best display, use latex syntax highlighting. =))'
145 \sloppy
145 \sloppy
146
146
147 % Document level variables
147 % Document level variables
148 \title{((( nb.metadata.name | escape_tex )))}
148 \title{((( resources.metadata.name | escape_tex )))}
149 \date{((( nb.metadata._draft.date | escape_tex )))}
149 \date{((( resources.sphinx.date | escape_tex )))}
150 \release{((( nb.metadata._draft.version | escape_tex )))}
150 \release{((( resources.sphinx.version | escape_tex )))}
151 \author{((( nb.metadata._draft.author | escape_tex )))}
151 \author{((( resources.sphinx.author | escape_tex )))}
152 \renewcommand{\releasename}{((( nb.metadata._draft.release | escape_tex )))}
152 \renewcommand{\releasename}{((( resources.sphinx.release | escape_tex )))}
153
153
154 % TODO: Add option for the user to specify a logo for his/her export.
154 % TODO: Add option for the user to specify a logo for his/her export.
155 \newcommand{\sphinxlogo}{}
155 \newcommand{\sphinxlogo}{}
@@ -347,11 +347,15 b' Note: For best display, use latex syntax highlighting. =))'
347 % Supported image formats
347 % Supported image formats
348 %==============================================================================
348 %==============================================================================
349 ((*- block data_png -*))
349 ((*- block data_png -*))
350 ((( conditionally_center_output(insert_graphics(output.key_png)) )))
350 ((( conditionally_center_output(insert_graphics(output.png_filename)) )))
351 ((*- endblock -*))
352
353 ((*- block data_jpg -*))
354 ((( conditionally_center_output(insert_graphics(output.jpg_filename)) )))
351 ((*- endblock -*))
355 ((*- endblock -*))
352
356
353 ((*- block data_svg -*))
357 ((*- block data_svg -*))
354 ((( conditionally_center_output(insert_graphics(output.key_svg)) )))
358 ((( conditionally_center_output(insert_graphics(output.svg_filename)) )))
355 ((*- endblock -*))
359 ((*- endblock -*))
356
360
357 ((*- block data_latex *))
361 ((*- block data_latex *))
@@ -30,15 +30,15 b" In[{{cell.prompt_number if cell.prompt_number else ' '}}]:{% endblock in_prompt "
30
30
31
31
32 {% block data_svg %}
32 {% block data_svg %}
33 [!image]({{output.key_svg}})
33 [!image]({{output.svg_filename}})
34 {% endblock data_svg %}
34 {% endblock data_svg %}
35
35
36 {% block data_png %}
36 {% block data_png %}
37 [!image]({{output.key_png}})
37 [!image]({{output.png_filename}})
38 {% endblock data_png %}
38 {% endblock data_png %}
39
39
40 {% block data_jpg %}
40 {% block data_jpg %}
41 [!image]({{output.key_jpg}})
41 [!image]({{output.jpg_filename}})
42 {% endblock data_jpg %}
42 {% endblock data_jpg %}
43
43
44
44
@@ -33,15 +33,15 b' Out[{{cell.prompt_number}}]:{% endif %}{% endblock output_prompt %}'
33
33
34
34
35
35
36 {% block data_svg %}.. image:: {{output.key_svg}}
36 {% block data_svg %}.. image:: {{output.svg_filename}}
37
37
38 {% endblock data_svg %}
38 {% endblock data_svg %}
39
39
40 {% block data_png %}.. image:: {{output.key_png}}
40 {% block data_png %}.. image:: {{output.png_filename}}
41
41
42 {% endblock data_png %}
42 {% endblock data_png %}
43
43
44 {% block data_jpg %}..jpg image:: {{output.key_jpg}}
44 {% block data_jpg %}..jpg image:: {{output.jpg_filename}}
45
45
46 {% endblock data_jpg %}
46 {% endblock data_jpg %}
47
47
@@ -1,10 +1,12 b''
1 # Class base Transformers
1 # Class base Transformers
2 from .activatable import ActivatableTransformer
2 from .base import Transformer
3 from .base import ConfigurableTransformer
3 from .convertfigures import ConvertFiguresTransformer
4 from .svg2pdf import SVG2PDFTransformer
4 from .extractfigure import ExtractFigureTransformer
5 from .extractfigure import ExtractFigureTransformer
5 from .revealhelp import RevealHelpTransformer
6 from .revealhelp import RevealHelpTransformer
6 from .latex import LatexTransformer
7 from .latex import LatexTransformer
7 from .sphinx import SphinxTransformer
8 from .sphinx import SphinxTransformer
9 from .csshtmlheader import CSSHTMLHeaderTransformer
8
10
9 # decorated function Transformers
11 # decorated function Transformers
10 from .coalescestreams import coalesce_streams
12 from .coalescestreams import coalesce_streams
@@ -16,13 +16,14 b' It exposes a convenient class to inherit from to access configurability.'
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from ..utils.config import GlobalConfigurable
19 from ..utils.base import NbConvertBase
20 from IPython.utils.traitlets import Bool
20
21
21 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
22 # Classes and Functions
23 # Classes and Functions
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24
25
25 class ConfigurableTransformer(GlobalConfigurable):
26 class Transformer(NbConvertBase):
26 """ A configurable transformer
27 """ A configurable transformer
27
28
28 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
@@ -31,11 +32,16 b' class ConfigurableTransformer(GlobalConfigurable):'
31 Any configurable traitlets this class exposed will be configurable in profiles
32 Any configurable traitlets this class exposed will be configurable in profiles
32 using c.SubClassName.atribute=value
33 using c.SubClassName.atribute=value
33
34
34 you can overwrite cell_transform to apply a transformation independently on each cell
35 you can overwrite transform_cell to apply a transformation independently on each cell
35 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
38 Disabled by default and can be enabled via the config by
39 'c.YourTransformerName.enabled = True'
36 """
40 """
37
41
38 def __init__(self, config=None, **kw):
42 enabled = Bool(False, config=True)
43
44 def __init__(self, **kw):
39 """
45 """
40 Public constructor
46 Public constructor
41
47
@@ -47,11 +53,15 b' class ConfigurableTransformer(GlobalConfigurable):'
47 Additional arguments
53 Additional arguments
48 """
54 """
49
55
50 super(ConfigurableTransformer, self).__init__(config=config, **kw)
56 super(Transformer, self).__init__(**kw)
51
57
52
58
53 def __call__(self, nb, resources):
59 def __call__(self, nb, resources):
54 return self.call(nb,resources)
60 if self.enabled:
61 return self.call(nb,resources)
62 else:
63 return nb, resources
64
55
65
56 def call(self, nb, resources):
66 def call(self, nb, resources):
57 """
67 """
@@ -59,7 +69,7 b' class ConfigurableTransformer(GlobalConfigurable):'
59
69
60 You should return modified nb, resources.
70 You should return modified nb, resources.
61 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
62 overwrite cell_transform method instead.
72 overwrite transform_cell method instead.
63
73
64 Parameters
74 Parameters
65 ----------
75 ----------
@@ -72,13 +82,13 b' class ConfigurableTransformer(GlobalConfigurable):'
72 try :
82 try :
73 for worksheet in nb.worksheets :
83 for worksheet in nb.worksheets :
74 for index, cell in enumerate(worksheet.cells):
84 for index, cell in enumerate(worksheet.cells):
75 worksheet.cells[index], resources = self.cell_transform(cell, resources, index)
85 worksheet.cells[index], resources = self.transform_cell(cell, resources, index)
76 return nb, resources
86 return nb, resources
77 except NotImplementedError:
87 except NotImplementedError:
78 raise NotImplementedError('should be implemented by subclass')
88 raise NotImplementedError('should be implemented by subclass')
79
89
80
90
81 def cell_transform(self, cell, resources, index):
91 def transform_cell(self, cell, resources, index):
82 """
92 """
83 Overwrite if you want to apply a transformation on each cell. You
93 Overwrite if you want to apply a transformation on each cell. You
84 should return modified cell and resource dictionary.
94 should return modified cell and resource dictionary.
@@ -72,4 +72,3 b' def coalesce_streams(cell, resources, index):'
72
72
73 cell.outputs = new_outputs
73 cell.outputs = new_outputs
74 return cell, resources
74 return cell, resources
75
@@ -16,18 +16,18 b' import os'
16 import io
16 import io
17
17
18 from pygments.formatters import HtmlFormatter
18 from pygments.formatters import HtmlFormatter
19
19
20 from IPython.utils import path
20 from IPython.utils import path
21
21
22 from .activatable import ActivatableTransformer
22 from .base import Transformer
23
23
24 from IPython.utils.traitlets import Unicode
24 from IPython.utils.traitlets import Unicode
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Classes and functions
27 # Classes and functions
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class CSSHTMLHeaderTransformer(ActivatableTransformer):
30 class CSSHTMLHeaderTransformer(Transformer):
31 """
31 """
32 Transformer used to pre-process notebook for HTML output. Adds IPython notebook
32 Transformer used to pre-process notebook for HTML output. Adds IPython notebook
33 front-end CSS and Pygments CSS to HTML output.
33 front-end CSS and Pygments CSS to HTML output.
@@ -12,59 +12,26 b" notebook file. The extracted figures are returned in the 'resources' dictionary"
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 import itertools
16
15
17 from IPython.utils.traitlets import Dict, Unicode
16 import sys
18 from .activatable import ActivatableTransformer
17 from IPython.utils.traitlets import Unicode
19
18 from .base import Transformer
20 #-----------------------------------------------------------------------------
21 # Constants
22 #-----------------------------------------------------------------------------
23
24 FIGURES_KEY = "figures"
25 BINARY_KEY = "binary"
26 TEXT_KEY = "text"
27
19
28 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
29 # Classes
21 # Classes
30 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
31
23
32 class ExtractFigureTransformer(ActivatableTransformer):
24 class ExtractFigureTransformer(Transformer):
33 """
25 """
34 Extracts all of the figures from the notebook file. The extracted
26 Extracts all of the figures from the notebook file. The extracted
35 figures are returned in the 'resources' dictionary.
27 figures are returned in the 'resources' dictionary.
36 """
28 """
37
29
38 extra_extension_map = Dict({},
30 figure_filename_template = Unicode(
39 config=True,
31 "{unique_key}_{cell_index}_{index}.{extension}", config=True)
40 help="""Extra map to override extension based on type.
41 Useful for latex where SVG will be converted to PDF before inclusion
42 """)
43
44 key_format_map = Dict({}, config=True,)
45 figure_name_format_map = Dict({}, config=True)
46
47 #TODO: Change this to .format {} syntax
48 default_key_template = Unicode('_fig_{index:02d}.{ext}', config=True)
49
50 def __init__(self, config=None, **kw):
51 """
52 Public constructor
53
54 Parameters
55 ----------
56 config : Config
57 Configuration file structure
58 **kw : misc
59 Additional arguments
60 """
61
62 super(ExtractFigureTransformer, self).__init__(config=config, **kw)
63
32
64 # A unique index for association with extracted figures
65 self.index_generator = itertools.count(1)
66
33
67 def cell_transform(self, cell, resources, index):
34 def transform_cell(self, cell, resources, cell_index):
68 """
35 """
69 Apply a transformation on each cell,
36 Apply a transformation on each cell,
70
37
@@ -75,69 +42,49 b' class ExtractFigureTransformer(ActivatableTransformer):'
75 resources : dictionary
42 resources : dictionary
76 Additional resources used in the conversion process. Allows
43 Additional resources used in the conversion process. Allows
77 transformers to pass variables into the Jinja engine.
44 transformers to pass variables into the Jinja engine.
78 index : int
45 cell_index : int
79 Index of the cell being processed (see base.py)
46 Index of the cell being processed (see base.py)
80 """
47 """
48
49 #Get the unique key from the resource dict if it exists. If it does not
50 #exist, use 'figure' as the default.
51 unique_key = resources.get('unique_key', 'figure')
81
52
82 if resources.get(FIGURES_KEY, None) is None :
53 #Make sure figures key exists
83 resources[FIGURES_KEY] = {TEXT_KEY:{},BINARY_KEY:{}}
54 if not 'figures' in resources:
55 resources['figures'] = {}
84
56
85 for out in cell.get('outputs', []):
57 #Loop through all of the outputs in the cell
58 for index, out in enumerate(cell.get('outputs', [])):
59
60 #Get the output in data formats that the template is interested in.
86 for out_type in self.display_data_priority:
61 for out_type in self.display_data_priority:
87
88 if out.hasattr(out_type):
62 if out.hasattr(out_type):
89 figname, key, data, binary = self._new_figure(out[out_type], out_type)
63 data = out[out_type]
90 out['key_'+out_type] = figname
64
65 #Binary files are base64-encoded, SVG is already XML
66 if out_type in ('png', 'jpg', 'jpeg', 'pdf'):
67 data = data.decode('base64')
68 elif sys.platform == 'win32':
69 data = data.replace('\n', '\r\n').encode("UTF-8")
70 else:
71 data = data.encode("UTF-8")
91
72
92 if binary :
73 #Build a figure name
93 resources[FIGURES_KEY][BINARY_KEY][key] = data
74 figure_name = self.figure_filename_template.format(
94 else :
75 unique_key=unique_key,
95 resources[FIGURES_KEY][TEXT_KEY][key] = data
76 cell_index=cell_index,
96
77 index=index,
97 index += 1
78 extension=out_type)
98 return cell, resources
79
99
80 #On the cell, make the figure available via
81 # cell.outputs[i].svg_filename ... etc (svg in example)
82 # Where
83 # cell.outputs[i].svg contains the data
84 out[out_type + '_filename'] = figure_name
85
86 #In the resources, make the figure available via
87 # resources['figures']['filename'] = data
88 resources['figures'][figure_name] = data
100
89
101 def _get_override_extension(self, extension):
90 return cell, resources
102 """Gets the overriden extension if it exists, else returns extension.
103
104 Parameters
105 ----------
106 extension : str
107 File extension.
108 """
109
110 if extension in self.extra_extension_map :
111 return self.extra_extension_map[extension]
112
113 return extension
114
115
116 def _new_figure(self, data, format):
117 """Create a new figure file in the given format.
118
119 Parameters
120 ----------
121 data : str
122 Cell data (from Notebook node cell)
123 format : str
124 Figure format
125 index : int
126 Index of the figure being extracted
127 """
128
129 figure_name_template = self.figure_name_format_map.get(format, self.default_key_template)
130 key_template = self.key_format_map.get(format, self.default_key_template)
131
132 #TODO: option to pass the hash as data?
133 index = next(self.index_generator)
134 figure_name = figure_name_template.format(index=index, ext=self._get_override_extension(format))
135 key = key_template.format(index=index, ext=self._get_override_extension(format))
136
137 #Binary files are base64-encoded, SVG is already XML
138 binary = False
139 if format in ('png', 'jpg', 'pdf'):
140 data = data.decode('base64')
141 binary = True
142
143 return figure_name, key, data, binary
@@ -17,19 +17,19 b' from __future__ import print_function, absolute_import'
17
17
18 # Our own imports
18 # Our own imports
19 # Needed to override transformer
19 # Needed to override transformer
20 from .activatable import (ActivatableTransformer)
20 from .base import (Transformer)
21 from IPython.nbconvert import filters
21 from IPython.nbconvert import filters
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Classes
24 # Classes
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 class LatexTransformer(ActivatableTransformer):
27 class LatexTransformer(Transformer):
28 """
28 """
29 Converter for latex destined documents.
29 Converter for latex destined documents.
30 """
30 """
31
31
32 def cell_transform(self, cell, resources, index):
32 def transform_cell(self, cell, resources, index):
33 """
33 """
34 Apply a transformation on each cell,
34 Apply a transformation on each cell,
35
35
@@ -12,14 +12,14 b''
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from .base import ConfigurableTransformer
15 from .base import Transformer
16 from IPython.utils.traitlets import Unicode
16 from IPython.utils.traitlets import Unicode
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Classes and functions
19 # Classes and functions
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 class RevealHelpTransformer(ConfigurableTransformer):
22 class RevealHelpTransformer(Transformer):
23
23
24 url_prefix = Unicode('//cdn.jsdelivr.net/reveal.js/2.4.0',
24 url_prefix = Unicode('//cdn.jsdelivr.net/reveal.js/2.4.0',
25 config=True,
25 config=True,
@@ -39,9 +39,8 b' class RevealHelpTransformer(ConfigurableTransformer):'
39 transformers to pass variables into the Jinja engine.
39 transformers to pass variables into the Jinja engine.
40 """
40 """
41
41
42
43 for worksheet in nb.worksheets :
42 for worksheet in nb.worksheets :
44 for i, cell in enumerate(worksheet.cells):
43 for index, cell in enumerate(worksheet.cells):
45
44
46 #Make sure the cell has slideshow metadata.
45 #Make sure the cell has slideshow metadata.
47 cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
46 cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
@@ -50,9 +49,9 b' class RevealHelpTransformer(ConfigurableTransformer):'
50 #Get the slide type. If type is start of subslide or slide,
49 #Get the slide type. If type is start of subslide or slide,
51 #end the last subslide/slide.
50 #end the last subslide/slide.
52 if cell.metadata.slide_type in ['slide']:
51 if cell.metadata.slide_type in ['slide']:
53 worksheet.cells[i - 1].metadata.slide_helper = 'slide_end'
52 worksheet.cells[index - 1].metadata.slide_helper = 'slide_end'
54 if cell.metadata.slide_type in ['subslide']:
53 if cell.metadata.slide_type in ['subslide']:
55 worksheet.cells[i - 1].metadata.slide_helper = 'subslide_end'
54 worksheet.cells[index - 1].metadata.slide_helper = 'subslide_end'
56
55
57
56
58 if 'reveal' not in resources:
57 if 'reveal' not in resources:
@@ -33,7 +33,7 b' from pygments.formatters import LatexFormatter'
33 from IPython.utils.traitlets import Unicode, Bool
33 from IPython.utils.traitlets import Unicode, Bool
34
34
35 # Needed to override transformer
35 # Needed to override transformer
36 from .activatable import (ActivatableTransformer) #TODO
36 from .base import (Transformer)
37
37
38 from IPython.nbconvert.utils import console
38 from IPython.nbconvert.utils import console
39
39
@@ -41,7 +41,7 b' from IPython.nbconvert.utils import console'
41 # Classes and functions
41 # Classes and functions
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 class SphinxTransformer(ActivatableTransformer):
44 class SphinxTransformer(Transformer):
45 """
45 """
46 Sphinx utility transformer.
46 Sphinx utility transformer.
47
47
@@ -127,9 +127,6 b' class SphinxTransformer(ActivatableTransformer):'
127 # TODO: Add versatile method of additional notebook metadata. Include
127 # TODO: Add versatile method of additional notebook metadata. Include
128 # handling of multiple files. For now use a temporay namespace,
128 # handling of multiple files. For now use a temporay namespace,
129 # '_draft' to signify that this needs to change.
129 # '_draft' to signify that this needs to change.
130 if not "_draft" in nb.metadata:
131 nb.metadata._draft = {}
132
133 if not "sphinx" in resources:
130 if not "sphinx" in resources:
134 resources["sphinx"] = {}
131 resources["sphinx"] = {}
135
132
@@ -137,10 +134,10 b' class SphinxTransformer(ActivatableTransformer):'
137
134
138 # Prompt the user for additional meta data that doesn't exist currently
135 # Prompt the user for additional meta data that doesn't exist currently
139 # but would be usefull for Sphinx.
136 # but would be usefull for Sphinx.
140 nb.metadata._draft["author"] = self._prompt_author()
137 resources["sphinx"]["author"] = self._prompt_author()
141 nb.metadata._draft["version"] = self._prompt_version()
138 resources["sphinx"]["version"] = self._prompt_version()
142 nb.metadata._draft["release"] = self._prompt_release()
139 resources["sphinx"]["release"] = self._prompt_release()
143 nb.metadata._draft["date"] = self._prompt_date()
140 resources["sphinx"]["date"] = self._prompt_date()
144
141
145 # Prompt the user for the document style.
142 # Prompt the user for the document style.
146 resources["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
143 resources["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
@@ -152,15 +149,17 b' class SphinxTransformer(ActivatableTransformer):'
152 else:
149 else:
153
150
154 # Try to use the traitlets.
151 # Try to use the traitlets.
155 nb.metadata._draft["author"] = self.author
152 resources["sphinx"]["author"] = self.author
156 nb.metadata._draft["version"] = self.version
153 resources["sphinx"]["version"] = self.version
157 nb.metadata._draft["release"] = self.release
154 resources["sphinx"]["release"] = self.release
158
155
159 # Use todays date if none is provided.
156 # Use todays date if none is provided.
160 if len(self.publish_date.strip()) == 0:
157 if self.publish_date:
161 nb.metadata._draft["date"] = date.today().strftime("%B %d, %Y")
158 resources["sphinx"]["date"] = self.publish_date
159 elif len(resources['metadata']['modified_date'].strip()) == 0:
160 resources["sphinx"]["date"] = date.today().strftime("%B %-d, %Y")
162 else:
161 else:
163 nb.metadata._draft["date"] = self.publish_date
162 resources["sphinx"]["date"] = resources['metadata']['modified_date']
164
163
165 # Sphinx traitlets.
164 # Sphinx traitlets.
166 resources["sphinx"]["chapterstyle"] = self.chapter_style
165 resources["sphinx"]["chapterstyle"] = self.chapter_style
@@ -175,7 +174,7 b' class SphinxTransformer(ActivatableTransformer):'
175 resources["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
174 resources["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
176
175
177 if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
176 if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
178 nb.metadata.name = self.overridetitle
177 resources['metadata']['name'] = self.overridetitle
179
178
180 # End
179 # End
181 return nb, resources
180 return nb, resources
@@ -212,12 +211,16 b' class SphinxTransformer(ActivatableTransformer):'
212 return console.input("Release Name (ie ""Rough draft""): ")
211 return console.input("Release Name (ie ""Rough draft""): ")
213
212
214
213
215 def _prompt_date(self):
214 def _prompt_date(self, resources):
216 """
215 """
217 Prompt the user to enter a date
216 Prompt the user to enter a date
218 """
217 """
219
218
220 default_date = date.today().strftime("%B %d, %Y")
219 if resources['metadata']['modified_date']:
220 default_date = resources['metadata']['modified_date']
221 else:
222 default_date = date.today().strftime("%B %-d, %Y")
223
221 user_date = console.input("Date (deafults to \"" + default_date + "\"): ")
224 user_date = console.input("Date (deafults to \"" + default_date + "\"): ")
222 if len(user_date.strip()) == 0:
225 if len(user_date.strip()) == 0:
223 user_date = default_date
226 user_date = default_date
@@ -18,7 +18,7 b' from IPython.config.configurable import Configurable'
18 # Classes and functions
18 # Classes and functions
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 class GlobalConfigurable(Configurable):
21 class NbConvertBase(Configurable):
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
@@ -33,5 +33,5 b' class GlobalConfigurable(Configurable):'
33 """
33 """
34 )
34 )
35
35
36 def __init__(self, config=None, **kw):
36 def __init__(self, **kw):
37 super(GlobalConfigurable, self).__init__( config=config, **kw)
37 super(NbConvertBase, self).__init__(**kw)
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now