##// END OF EJS Templates
Added writers and supporting code.
Jonathan Frederic -
Show More
@@ -0,0 +1,74 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 .activatable import ActivatableTransformer
17
18 #-----------------------------------------------------------------------------
19 # Classes
20 #-----------------------------------------------------------------------------
21
22 class ConvertFiguresTransformer(ActivatableTransformer):
23 """
24 Converts all of the outputs in a notebook from one format to another.
25 """
26
27
28 def __init__(self, from_formats, to_format, **kw):
29 """
30 Public constructor
31
32 Parameters
33 ----------
34 from_formats : list [of string]
35 Formats that the converter can convert from
36 to_format : string
37 Format that the converter converts to
38 config : Config
39 Configuration file structure
40 **kw : misc
41 Additional arguments
42 """
43 super(ConvertFiguresTransformer, self).__init__(**kw)
44
45 self._from_formats = from_formats
46 self._to_format = to_format
47
48
49 def convert_figure(self, data_format, data):
50 raise NotImplementedError()
51
52
53 def transform_cell(self, cell, resources, cell_index):
54 """
55 Apply a transformation on each cell,
56
57 See base.py
58 """
59
60 #Loop through all of the datatypes of the outputs in the cell.
61 for index, cell_out in enumerate(cell.get('outputs', [])):
62 for data_type, data in cell_out.items():
63 self._convert_figure(cell_out, data_type, data)
64 return cell, resources
65
66
67 def _convert_figure(self, cell_out, data_type, data):
68 """
69 Convert a figure and output the results to the cell output
70 """
71
72 if not self._to_format in cell_out:
73 if data_type in self._from_formats:
74 cell_out[self._to_format] = self.convert_figure(data_type, data)
@@ -0,0 +1,70 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 from IPython.utils.tempdir import TemporaryDirectory
18
19 from .convertfigures import ConvertFiguresTransformer
20
21
22 #-----------------------------------------------------------------------------
23 # Constants
24 #-----------------------------------------------------------------------------
25
26 INKSCAPE_COMMAND = "inkscape --without-gui --export-pdf=\"{to_filename}\" \"{from_filename}\""
27
28
29 #-----------------------------------------------------------------------------
30 # Classes
31 #-----------------------------------------------------------------------------
32
33 class ConvertSvgTransformer(ConvertFiguresTransformer):
34 """
35 Converts all of the outputs in a notebook from one format to another.
36 """
37
38
39 def __init__(self, **kw):
40 """
41 Constructor
42 """
43 super(ConvertSvgTransformer, self).__init__(['svg'], 'pdf', **kw)
44
45
46 def convert_figure(self, data_format, data):
47 """
48 Convert a single Svg figure. Returns converted data.
49 """
50
51 #Work in a temporary directory
52 with TemporaryDirectory() as tmpdir:
53
54 #Write fig to temp file
55 input_filename = os.path.join(tmpdir, 'figure.' + data_format)
56 with open(input_filename, 'w') as f:
57 f.write(data)
58
59 #Call conversion application
60 output_filename = os.path.join(tmpdir, 'figure.pdf')
61 shell = INKSCAPE_COMMAND.format(from_filename=input_filename,
62 to_filename=output_filename)
63 subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
64
65 #Read output from drive
66 if os.path.isfile(output_filename):
67 with open(output_filename) as f:
68 return f.read()
69 else:
70 return TypeError("Inkscape svg to png conversion failed")
@@ -1,5 +1,6 b''
1 1 """Utilities for converting notebooks to and from different formats."""
2 2
3 3 from .exporters import *
4 4 import filters
5 5 import transformers
6 import writers
@@ -1,223 +1,217 b''
1 1 """
2 2 Module containing single call export functions.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from functools import wraps
17 17
18 18 from IPython.nbformat.v3.nbbase import NotebookNode
19 from IPython.config import Config
19 20
20 21 from .exporter import Exporter
21 22 from .basichtml import BasicHTMLExporter
22 23 from .fullhtml import FullHTMLExporter
23 24 from .latex import LatexExporter
24 25 from .markdown import MarkdownExporter
25 26 from .python import PythonExporter
26 27 from .reveal import RevealExporter
27 28 from .rst import RstExporter
28 29 from .sphinx_howto import SphinxHowtoExporter
29 30 from .sphinx_manual import SphinxManualExporter
30 31
31 32 #-----------------------------------------------------------------------------
32 33 # Classes
33 34 #-----------------------------------------------------------------------------
34 35
35 36 def DocDecorator(f):
36 37
37 38 #Set docstring of function
38 39 f.__doc__ = f.__doc__ + """
39 40 nb : Notebook node
40 config : config
41 config : config (optional, keyword arg)
41 42 User configuration instance.
42 transformers : list[of transformer]
43 Custom transformers to apply to the notebook prior to engaging
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.
43 resources : dict (optional, keyword arg)
44 Resources used in the conversion process.
51 45
52 46 Returns
53 47 ----------
54 48 tuple- output, resources, exporter_instance
55 49 output : str
56 50 Jinja 2 output. This is the resulting converted notebook.
57 51 resources : dictionary
58 52 Dictionary of resources used prior to and during the conversion
59 53 process.
60 54 exporter_instance : Exporter
61 55 Instance of the Exporter class used to export the document. Useful
62 56 to caller because it provides a 'file_extension' property which
63 57 specifies what extension the output should be saved as."""
64 58
65 59 @wraps(f)
66 60 def decorator(*args, **kwargs):
67 61 return f(*args, **kwargs)
68 62
69 63 return decorator
70 64
71 65
72 66 #-----------------------------------------------------------------------------
73 67 # Functions
74 68 #-----------------------------------------------------------------------------
75 69
76 70 __all__ = [
77 71 'export',
78 72 'export_sphinx_manual',
79 73 'export_sphinx_howto',
80 74 'export_basic_html',
81 75 'export_full_html',
82 76 'export_latex',
83 77 'export_markdown',
84 78 'export_python',
85 79 'export_reveal',
86 80 'export_rst',
87 81 'export_by_name',
88 82 'get_export_names'
89 83 ]
90 84
91 85 @DocDecorator
92 def export(exporter_type, nb, config=None, transformers=None, filters=None):
86 def export(exporter_type, nb, **kw):
93 87 """
94 88 Export a notebook object using specific exporter class.
95 89
96 90 exporter_type : Exporter class type
97 91 Class type of the exporter that should be used. This method
98 92 will initialize it's own instance of the class. It is
99 93 ASSUMED that the class type provided exposes a
100 94 constructor (__init__) with the same signature as the
101 95 base Exporter class.}
102 96 """
103 97
104 98 #Check arguments
105 99 if exporter_type is None:
106 100 raise TypeError("Exporter is None")
107 101 elif not issubclass(exporter_type, Exporter):
108 102 raise TypeError("Exporter type does not inherit from Exporter (base)")
109
110 103 if nb is None:
111 104 raise TypeError("nb is None")
112 105
113 106 #Create the exporter
114 exporter_instance = exporter_type(preprocessors=transformers,
115 jinja_filters=filters, config=config)
107 exporter_instance = exporter_type(config=kw.get('config', Config()))
116 108
117 109 #Try to convert the notebook using the appropriate conversion function.
110 resources = kw.get('resources', {})
118 111 if isinstance(nb, NotebookNode):
119 output, resources = exporter_instance.from_notebook_node(nb)
112 output, resources = exporter_instance.from_notebook_node(nb, resources)
120 113 elif isinstance(nb, basestring):
121 output, resources = exporter_instance.from_filename(nb)
114 output, resources = exporter_instance.from_filename(nb, resources)
122 115 else:
123 output, resources = exporter_instance.from_file(nb)
124 return output, resources, exporter_instance
116 output, resources = exporter_instance.from_file(nb, resources)
117 return output, resources
125 118
126 119
127 120 @DocDecorator
128 def export_sphinx_manual(nb, config=None, transformers=None, filters=None):
121 def export_sphinx_manual(nb, **kw):
129 122 """
130 123 Export a notebook object to Sphinx Manual LaTeX
131 124 """
132 return export(SphinxManualExporter, nb, config, transformers, filters)
125 return export(SphinxManualExporter, nb, **kw)
133 126
134 127
135 128 @DocDecorator
136 def export_sphinx_howto(nb, config=None, transformers=None, filters=None):
129 def export_sphinx_howto(nb, **kw):
137 130 """
138 131 Export a notebook object to Sphinx HowTo LaTeX
139 132 """
140 return export(SphinxHowtoExporter, nb, config, transformers, filters)
133 return export(SphinxHowtoExporter, nb, **kw)
141 134
142 135
143 136 @DocDecorator
144 def export_basic_html(nb, config=None, transformers=None, filters=None):
137 def export_basic_html(nb, **kw):
145 138 """
146 139 Export a notebook object to Basic HTML
147 140 """
148 return export(BasicHTMLExporter, nb, config, transformers, filters)
141 return export(BasicHTMLExporter, nb, **kw)
149 142
150 143
151 144 @DocDecorator
152 def export_full_html(nb, config=None, transformers=None, filters=None):
145 def export_full_html(nb, **kw):
153 146 """
154 147 Export a notebook object to Full HTML
155 148 """
156 return export(FullHTMLExporter, nb, config, transformers, filters)
149 return export(FullHTMLExporter, nb, **kw)
157 150
158 151
159 152 @DocDecorator
160 def export_latex(nb, config=None, transformers=None, filters=None):
153 def export_latex(nb, **kw):
161 154 """
162 155 Export a notebook object to LaTeX
163 156 """
164 return export(LatexExporter, nb, config, transformers, filters)
157 return export(LatexExporter, nb, **kw)
165 158
166 159
167 160 @DocDecorator
168 def export_markdown(nb, config=None, transformers=None, filters=None):
161 def export_markdown(nb, **kw):
169 162 """
170 163 Export a notebook object to Markdown
171 164 """
172 return export(MarkdownExporter, nb, config, transformers, filters)
165 return export(MarkdownExporter, nb, **kw)
173 166
174 167
175 168 @DocDecorator
176 def export_python(nb, config=None, transformers=None, filters=None):
169 def export_python(nb, **kw):
177 170 """
178 171 Export a notebook object to Python
179 172 """
180 return export(PythonExporter, nb, config, transformers, filters)
173 return export(PythonExporter, nb, **kw)
181 174
182 175
183 176 @DocDecorator
184 def export_reveal(nb, config=None, transformers=None, filters=None):
177 def export_reveal(nb, **kw):
185 178 """
186 179 Export a notebook object to Reveal
187 180 """
188 return export(RevealExporter, nb, config, transformers, filters)
181 return export(RevealExporter, nb, **kw)
189 182
190 183
191 184 @DocDecorator
192 def export_rst(nb, config=None, transformers=None, filters=None):
185 def export_rst(nb, **kw):
193 186 """
194 187 Export a notebook object to RST
195 188 """
196 return export(RstExporter, nb, config, transformers, filters)
189 return export(RstExporter, nb, **kw)
197 190
198 191
199 192 @DocDecorator
200 def export_by_name(template_name, nb, config=None, transformers=None, filters=None):
193 def export_by_name(format_name, nb, **kw):
201 194 """
202 195 Export a notebook object to a template type by its name. Reflection
203 196 (Inspect) is used to find the template's corresponding explicit export
204 197 method defined in this module. That method is then called directly.
205 198
206 template_name : str
199 format_name : str
207 200 Name of the template style to export to.
208 201 """
209 202
210 function_name = "export_" + template_name.lower()
203 function_name = "export_" + format_name.lower()
211 204
212 205 if function_name in globals():
213 return globals()[function_name](nb, config, transformers, filters)
206 return globals()[function_name](nb, **kw)
214 207 else:
215 208 raise NameError("template for `%s` not found" % function_name)
216 209
217 210 def get_export_names():
218 211 "Return a list of the currently supported export targets"
219 212 # grab everything after 'export_'
220 213 l = [x[len('export_'):] for x in __all__ if x.startswith('export_')]
221 # filter out the one method that is not a template
214
215 # filter out the one method that is not a template
222 216 l = [x for x in l if 'by_name' not in x]
223 217 return sorted(l)
@@ -1,346 +1,360 b''
1 1 """This module defines Exporter, a highly configurable converter
2 2 that uses Jinja2 to export notebook files into different formats.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from __future__ import print_function, absolute_import
18 18
19 19 # Stdlib imports
20 20 import io
21 21 import os
22 22 import inspect
23 import types
23 24 from copy import deepcopy
24 25
25 26 # other libs/dependencies
26 27 from jinja2 import Environment, FileSystemLoader, ChoiceLoader
27 28
28 29 # IPython imports
29 30 from IPython.config.configurable import Configurable
30 31 from IPython.config import Config
31 32 from IPython.nbformat import current as nbformat
32 from IPython.utils.traitlets import MetaHasTraits, Unicode
33 from IPython.utils.traitlets import MetaHasTraits, DottedObjectName, Unicode, List, Dict
34 from IPython.utils.importstring import import_item
33 35 from IPython.utils.text import indent
34 36
35 37 from IPython.nbconvert import filters
36 38 from IPython.nbconvert import transformers
37 39
38 40 #-----------------------------------------------------------------------------
39 41 # Globals and constants
40 42 #-----------------------------------------------------------------------------
41 43
42 44 #Jinja2 extensions to load.
43 45 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
44 46
45 47 default_filters = {
46 48 'indent': indent,
47 49 'markdown': filters.markdown2html,
48 50 'ansi2html': filters.ansi2html,
49 51 'filter_data_type': filters.DataTypeFilter,
50 52 'get_lines': filters.get_lines,
51 53 'highlight': filters.highlight,
52 54 'highlight2html': filters.highlight,
53 55 'highlight2latex': filters.highlight2latex,
54 56 'markdown2latex': filters.markdown2latex,
55 57 'markdown2rst': filters.markdown2rst,
56 58 'pycomment': filters.python_comment,
57 59 'rm_ansi': filters.remove_ansi,
58 60 'rm_dollars': filters.strip_dollars,
59 61 'rm_fake': filters.rm_fake,
60 62 'ansi2latex': filters.ansi2latex,
61 63 'rm_math_space': filters.rm_math_space,
62 64 'wrap': filters.wrap
63 65 }
64 66
65 67 #-----------------------------------------------------------------------------
66 68 # Class
67 69 #-----------------------------------------------------------------------------
68 70
69 71 class Exporter(Configurable):
70 72 """
71 73 Exports notebooks into other file formats. Uses Jinja 2 templating engine
72 74 to output new formats. Inherit from this class if you are creating a new
73 75 template type along with new filters/transformers. If the filters/
74 76 transformers provided by default suffice, there is no need to inherit from
75 77 this class. Instead, override the template_file and file_extension
76 78 traits via a config file.
77 79
78 80 {filters}
79 81 """
80 82
81 83 # finish the docstring
82 84 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
83 85
84 86
85 87 template_file = Unicode(
86 88 '', config=True,
87 89 help="Name of the template file to use")
88 90
89 91 file_extension = Unicode(
90 92 'txt', config=True,
91 93 help="Extension of the file that should be written to disk"
92 94 )
93 95
94 96 template_path = Unicode(
95 97 os.path.join("..", "templates"), config=True,
96 98 help="Path where the template files are located.")
97 99
98 100 template_skeleton_path = Unicode(
99 101 os.path.join("..", "templates", "skeleton"), config=True,
100 102 help="Path where the template skeleton files are located.")
101 103
102 104 #Jinja block definitions
103 105 jinja_comment_block_start = Unicode("", config=True)
104 106 jinja_comment_block_end = Unicode("", config=True)
105 107 jinja_variable_block_start = Unicode("", config=True)
106 108 jinja_variable_block_end = Unicode("", config=True)
107 109 jinja_logic_block_start = Unicode("", config=True)
108 110 jinja_logic_block_end = Unicode("", config=True)
109 111
110 112 #Extension that the template files use.
111 113 template_extension = Unicode(".tpl", config=True)
112 114
113 #Processors that process the input data prior to the export, set in the
114 #constructor for this class.
115 transformers = None
116
115 #Configurability, allows the user to easily add filters and transformers.
116 transformers = List(config=True,
117 help="""List of transformers, by name or namespace, to enable.""")
118 filters = Dict(config=True,
119 help="""Dictionary of filters, by name and namespace, to add to the Jinja
120 environment.""")
117 121
118 def __init__(self, transformers=None, filters=None, config=None, extra_loaders=None, **kw):
122 def __init__(self, config=None, extra_loaders=None, **kw):
119 123 """
120 124 Public constructor
121 125
122 126 Parameters
123 127 ----------
124 transformers : list[of transformer]
125 Custom transformers to apply to the notebook prior to engaging
126 the Jinja template engine. Any transformers specified here
127 will override existing transformers if a naming conflict
128 occurs.
129 filters : dict[of filter]
130 filters specified here will override existing filters if a naming
131 conflict occurs. Filters are availlable in jinja template through
132 the name of the corresponding key. Cf class docstring for
133 availlable default filters.
134 128 config : config
135 129 User configuration instance.
136 130 extra_loaders : list[of Jinja Loaders]
137 131 ordered list of Jinja loder to find templates. Will be tried in order
138 132 before the default FileSysteme ones.
139 133 """
140 134
141 135 #Call the base class constructor
142 136 c = self.default_config
143 137 if config:
144 138 c.merge(config)
145 139
146 140 super(Exporter, self).__init__(config=c, **kw)
147 141
148 142 #Standard environment
149 143 self._init_environment(extra_loaders=extra_loaders)
150 144
151 145 #Add transformers
146 self._transformers = []
152 147 self._register_transformers()
153 148
154 149 #Add filters to the Jinja2 environment
155 150 self._register_filters()
156 151
157 #Load user transformers. Overwrite existing transformers if need be.
158 if transformers :
159 for transformer in transformers:
160 self.register_transformer(transformer)
152 #Load user transformers. Enabled by default.
153 if self.transformers:
154 for transformer in self.transformers:
155 self.register_transformer(transformer, True)
161 156
162 157 #Load user filters. Overwrite existing filters if need be.
163 if not filters is None:
164 for key, user_filter in filters.iteritems():
158 if self.filters:
159 for key, user_filter in self.filters.iteritems():
165 160 self.register_filter(key, user_filter)
166 161
162
167 163 @property
168 164 def default_config(self):
169 165 return Config()
170 166
171 167
172
173 def from_notebook_node(self, nb, resources=None):
168 def from_notebook_node(self, nb, resources={}, **kw):
174 169 """
175 170 Convert a notebook from a notebook node instance.
176 171
177 172 Parameters
178 173 ----------
179 174 nb : Notebook node
180 resources : a dict of additional resources that
181 can be accessed read/write by transformers
182 and filters.
175 resources : dict (**kw)
176 of additional resources that can be accessed read/write by
177 transformers and filters.
183 178 """
184 if resources is None:
185 resources = {}
179
180 #Preprocess
186 181 nb, resources = self._preprocess(nb, resources)
187
188 #Load the template file.
189 self.template = self.environment.get_template(self.template_file+self.template_extension)
190
191 return self.template.render(nb=nb, resources=resources), resources
192 182
183 #Convert
184 self.template = self.environment.get_template(self.template_file + self.template_extension)
185 output = self.template.render(nb=nb, resources=resources)
186
187 #Set output extension in resources dict
188 resources['output_extension'] = self.file_extension
189 return output, resources
193 190
194 def from_filename(self, filename):
191
192 def from_filename(self, filename, resources={}, **kw):
195 193 """
196 194 Convert a notebook from a notebook file.
197 195
198 196 Parameters
199 197 ----------
200 198 filename : str
201 199 Full filename of the notebook file to open and convert.
202 200 """
203 201
204 202 with io.open(filename) as f:
205 return self.from_notebook_node(nbformat.read(f, 'json'))
203 return self.from_notebook_node(nbformat.read(f, 'json'), resources=resources,**kw)
206 204
207 205
208 def from_file(self, file_stream):
206 def from_file(self, file_stream, resources={}, **kw):
209 207 """
210 208 Convert a notebook from a notebook file.
211 209
212 210 Parameters
213 211 ----------
214 212 file_stream : file-like object
215 213 Notebook file-like object to convert.
216 214 """
217 return self.from_notebook_node(nbformat.read(file_stream, 'json'))
215 return self.from_notebook_node(nbformat.read(file_stream, 'json'), resources=resources, **kw)
218 216
219 217
220 def register_transformer(self, transformer):
218 def register_transformer(self, transformer, enabled=None):
221 219 """
222 220 Register a transformer.
223 221 Transformers are classes that act upon the notebook before it is
224 222 passed into the Jinja templating engine. Transformers are also
225 223 capable of passing additional information to the Jinja
226 224 templating engine.
227 225
228 226 Parameters
229 227 ----------
230 228 transformer : transformer
231 229 """
232 if self.transformers is None:
233 self.transformers = []
234
230
231 #Handle transformer's registration based on it's type
235 232 if inspect.isfunction(transformer):
236 self.transformers.append(transformer)
233 #Transformer is a function, no need to construct it.
234 self._transformers.append(transformer)
237 235 return transformer
236
237 elif isinstance(transformer, types.StringTypes):
238 #Transformer is a string, import the namespace and recursively call
239 #this register_transformer method
240 transformer_cls = import_item(DottedObjectName(transformer))
241 return self.register_transformer(transformer_cls, enabled=None)
242
238 243 elif isinstance(transformer, MetaHasTraits):
239 transformer_instance = transformer(config=self.config)
240 self.transformers.append(transformer_instance)
241 return transformer_instance
244 #Transformer is configurable. Make sure to pass in new default for
245 #the enabled flag if one was specified.
246 c = Config()
247 if not enabled is None:
248 c = Config({transformer.__name__: {'enabled': enabled}})
249 c.merge(self.config)
250 transformer_instance = transformer(config=c)
251
242 252 else:
253 #Transformer is not configurable, construct it
243 254 transformer_instance = transformer()
244 self.transformers.append(transformer_instance)
245 return transformer_instance
255
256 #Register and return the transformer.
257 self._transformers.append(transformer_instance)
258 return transformer_instance
246 259
247 260
248 261 def register_filter(self, name, filter):
249 262 """
250 263 Register a filter.
251 264 A filter is a function that accepts and acts on one string.
252 265 The filters are accesible within the Jinja templating engine.
253 266
254 267 Parameters
255 268 ----------
256 269 name : str
257 270 name to give the filter in the Jinja engine
258 271 filter : filter
259 272 """
260 273 if inspect.isfunction(filter):
261 274 self.environment.filters[name] = filter
275 elif isinstance(filter, types.StringTypes):
276 filter_cls = import_item(DottedObjectName(filter))
277 self.register_filter(name, filter_cls)
262 278 elif isinstance(filter, MetaHasTraits):
263 279 self.environment.filters[name] = filter(config=self.config)
264 280 else:
265 281 self.environment.filters[name] = filter()
266 282 return self.environment.filters[name]
267 283
268 284
269 285 def _register_transformers(self):
270 286 """
271 Register all of the transformers needed for this exporter.
287 Register all of the transformers needed for this exporter, disabled
288 unless specified explicitly.
272 289 """
273
290
274 291 self.register_transformer(transformers.coalesce_streams)
275
276 #Remember the figure extraction transformer so it can be enabled and
277 #disabled easily later.
278 self.extract_figure_transformer = self.register_transformer(transformers.ExtractFigureTransformer)
292 self.register_transformer(transformers.ExtractFigureTransformer)
279 293
280 294
281 295 def _register_filters(self):
282 296 """
283 297 Register all of the filters required for the exporter.
284 298 """
285 for k, v in default_filters.iteritems():
286 self.register_filter(k, v)
299 for key, value in default_filters.iteritems():
300 self.register_filter(key, value)
287 301
288 302
289 303 def _init_environment(self, extra_loaders=None):
290 304 """
291 305 Create the Jinja templating environment.
292 306 """
293 307 here = os.path.dirname(os.path.realpath(__file__))
294 308 loaders = []
295 309 if extra_loaders:
296 310 loaders.extend(extra_loaders)
297 311
298 312 loaders.append(FileSystemLoader([
299 313 os.path.join(here, self.template_path),
300 314 os.path.join(here, self.template_skeleton_path),
301 315 ]))
302 316
303 317 self.environment = Environment(
304 318 loader= ChoiceLoader(loaders),
305 319 extensions=JINJA_EXTENSIONS
306 320 )
307 321
308 322 #Set special Jinja2 syntax that will not conflict with latex.
309 323 if self.jinja_logic_block_start:
310 324 self.environment.block_start_string = self.jinja_logic_block_start
311 325 if self.jinja_logic_block_end:
312 326 self.environment.block_end_string = self.jinja_logic_block_end
313 327 if self.jinja_variable_block_start:
314 328 self.environment.variable_start_string = self.jinja_variable_block_start
315 329 if self.jinja_variable_block_end:
316 330 self.environment.variable_end_string = self.jinja_variable_block_end
317 331 if self.jinja_comment_block_start:
318 332 self.environment.comment_start_string = self.jinja_comment_block_start
319 333 if self.jinja_comment_block_end:
320 334 self.environment.comment_end_string = self.jinja_comment_block_end
321 335
322 336
323 337 def _preprocess(self, nb, resources):
324 338 """
325 339 Preprocess the notebook before passing it into the Jinja engine.
326 340 To preprocess the notebook is to apply all of the
327 341
328 342 Parameters
329 343 ----------
330 344 nb : notebook node
331 345 notebook that is being exported.
332 346 resources : a dict of additional resources that
333 347 can be accessed read/write by transformers
334 348 and filters.
335 349 """
336 350
337 351 # Do a deepcopy first,
338 352 # we are never safe enough with what the transformers could do.
339 353 nbc = deepcopy(nb)
340 354 resc = deepcopy(resources)
355
341 356 #Run each transformer on the notebook. Carry the output along
342 357 #to each transformer
343 for transformer in self.transformers:
344 nb, resources = transformer(nbc, resc)
345 return nb, resources
346
358 for transformer in self._transformers:
359 nbc, resc = transformer(nbc, resc)
360 return nbc, resc
@@ -1,108 +1,111 b''
1 1 """
2 2 Exporter that allows Latex Jinja templates to work. Contains logic to
3 3 appropriately prepare IPYNB files for export to LaTeX. Including but
4 4 not limited to escaping LaTeX, fixing math region tags, using special
5 5 tags to circumvent Jinja/Latex syntax conflicts.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2013, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Stdlib imports
20 20 import os
21 21
22 22 # IPython imports
23 23 from IPython.utils.traitlets import Unicode
24 24 from IPython.config import Config
25 25
26 26 from IPython.nbconvert import filters, transformers
27 27 from .exporter import Exporter
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Classes and functions
31 31 #-----------------------------------------------------------------------------
32 32
33 33 class LatexExporter(Exporter):
34 34 """
35 35 Exports to a Latex template. Inherit from this class if your template is
36 36 LaTeX based and you need custom tranformers/filters. Inherit from it if
37 37 you are writing your own HTML template and need custom tranformers/filters.
38 38 If you don't need custom tranformers/filters, just change the
39 39 'template_file' config option. Place your template in the special "/latex"
40 40 subfolder of the "../templates" folder.
41 41 """
42 42
43 43 file_extension = Unicode(
44 44 'tex', config=True,
45 45 help="Extension of the file that should be written to disk")
46 46
47 47 template_file = Unicode(
48 48 'base', config=True,
49 49 help="Name of the template file to use")
50 50
51 51 #Latex constants
52 52 template_path = Unicode(
53 53 os.path.join("..", "templates", "latex"), config=True,
54 54 help="Path where the template files are located.")
55 55
56 56 template_skeleton_path = Unicode(
57 57 os.path.join("..", "templates", "latex", "skeleton"), config=True,
58 58 help="Path where the template skeleton files are located.")
59 59
60 60 #Special Jinja2 syntax that will not conflict when exporting latex.
61 61 jinja_comment_block_start = Unicode("((=", config=True)
62 62 jinja_comment_block_end = Unicode("=))", config=True)
63 63 jinja_variable_block_start = Unicode("(((", config=True)
64 64 jinja_variable_block_end = Unicode(")))", config=True)
65 65 jinja_logic_block_start = Unicode("((*", config=True)
66 66 jinja_logic_block_end = Unicode("*))", config=True)
67 67
68 68 #Extension that the template files use.
69 69 template_extension = Unicode(".tplx", config=True)
70 70
71 71 def _register_filters(self):
72 72 """
73 73 Register all of the filters required for the exporter.
74 74 """
75 75
76 76 #Register the filters of the base class.
77 77 super(LatexExporter, self)._register_filters()
78 78
79 79 #Add latex filters to the Jinja2 environment
80 80 self.register_filter('escape_tex', filters.escape_latex)
81 81 self.register_filter('highlight', filters.highlight2latex)
82 82
83 83
84 84 def _register_transformers(self):
85 85 """
86 86 Register all of the transformers needed for this exporter.
87 87 """
88
89 #Register ConvertSvgTransformer before any other transformers!
90 #Important because it allows the conversion of svg->png BEFORE the
91 #extract figure transformer acts on the data.
92 self.register_transformer(transformers.ConvertSvgTransformer, True)
88 93
89 #Register the transformers of the base class.
94 #Register transformers
90 95 super(LatexExporter, self)._register_transformers()
91
92 #Register latex transformer
93 self.register_transformer(transformers.LatexTransformer)
96 self.register_transformer(transformers.LatexTransformer, True)
94 97
95 98 @property
96 99 def default_config(self):
97 100 c = Config({
98 101 'GlobalConfigurable': {
99 'display_data_priority' : ['latex', 'svg', 'png', 'jpg', 'jpeg' , 'text']
102 'display_data_priority' : ['latex', 'png', 'jpg', 'jpeg']
100 103 },
101 104 'ExtractFigureTransformer': {
102 'enabled':True,
103 'extra_ext_map':{'svg':'pdf'},
105 'enabled':True
104 106 }
107
105 108 })
106 109 c.merge(super(LatexExporter,self).default_config)
107 110 return c
108 111
@@ -1,61 +1,61 b''
1 1 """
2 2 Reveal slide show exporter.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from IPython.utils.traitlets import Unicode
17 17 from IPython.config import Config
18 18
19 19 from .basichtml import BasicHTMLExporter
20 20 from IPython.nbconvert import transformers
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Classes
24 24 #-----------------------------------------------------------------------------
25 25
26 26 class RevealExporter(BasicHTMLExporter):
27 27 """
28 28 Exports a Reveal slide show (.HTML) which may be rendered in a web browser.
29 29 """
30 30
31 31 file_extension = Unicode(
32 32 'reveal.html', config=True,
33 33 help="Extension of the file that should be written to disk")
34 34
35 35 template_file = Unicode(
36 36 'reveal', config=True,
37 37 help="Name of the template file to use")
38 38
39 39 def _register_transformers(self):
40 40 """
41 41 Register all of the transformers needed for this exporter.
42 42 """
43 43
44 44 #Register the transformers of the base class.
45 45 super(RevealExporter, self)._register_transformers()
46 46
47 47 #Register reveal help transformer
48 self.register_transformer(transformers.RevealHelpTransformer)
48 self.register_transformer(transformers.RevealHelpTransformer, True)
49 49
50 50 @property
51 51 def default_config(self):
52 52 c = Config({
53 53 'CSSHTMLHeaderTransformer':{
54 54 'enabled':True
55 55 },
56 56 'RevealHelpTransformer':{
57 57 'enabled':True,
58 58 },
59 59 })
60 60 c.merge(super(RevealExporter,self).default_config)
61 61 return c
@@ -1,54 +1,45 b''
1 1 """
2 2 Exporter for exporting notebooks to Sphinx 'HowTo' style latex. Latex
3 3 formatted for use with PDFLatex.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from IPython.utils.traitlets import Unicode
18 18 from IPython.config import Config
19 19
20 20 # local import
21 21 from .latex import LatexExporter
22 22
23 23 from IPython.nbconvert import transformers
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Classes
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class SphinxHowtoExporter(LatexExporter):
30 30 """
31 31 Exports Sphinx "HowTo" LaTeX documents. The Sphinx "HowTo" exporter
32 32 produces short document format latex for use with PDFLatex.
33 33 """
34 34
35 35 template_file = Unicode(
36 36 'sphinx_howto', config=True,
37 37 help="Name of the template file to use")
38 38
39 39 def _register_transformers(self):
40 40
41 41 #Register the transformers of the base class.
42 42 super(SphinxHowtoExporter, self)._register_transformers()
43 43
44 44 #Register sphinx latex transformer
45 self.register_transformer(transformers.SphinxTransformer)
46
47 @property
48 def default_config(self):
49 c = Config({
50 'SphinxTransformer': {'enabled':True}
51 })
52 c.merge(super(SphinxHowtoExporter,self).default_config)
53 return c
54
45 self.register_transformer(transformers.SphinxTransformer, True)
@@ -1,229 +1,167 b''
1 1 #!/usr/bin/env python
2 2 """NBConvert is a utility for conversion of IPYNB files.
3 3
4 4 Commandline interface for the NBConvert conversion utility. Read the
5 5 readme.rst for usage information
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 #Copyright (c) 2013, the IPython Development Team.
9 9 #
10 10 #Distributed under the terms of the Modified BSD License.
11 11 #
12 12 #The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 #Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #Stdlib imports
20 20 from __future__ import print_function
21 21 import sys
22 import io
23 22 import os
23 import glob
24 24
25 25 #From IPython
26 from IPython.config.application import Application
27 from IPython.utils.traitlets import Bool, Unicode
26 from IPython.core.application import BaseIPythonApplication
27 from IPython.config.application import catch_config_error
28 from IPython.utils.traitlets import Unicode, List, Instance, DottedObjectName, Type
29 from IPython.utils.importstring import import_item
28 30
29 31 from .exporters.export import export_by_name, get_export_names
30 32 from .exporters.exporter import Exporter
31 from .transformers import extractfigure
33 from .writers.base import WriterBase
32 34 from .utils.config import GlobalConfigurable
33 35
34 36 #-----------------------------------------------------------------------------
35 #Globals and constants
37 #Classes and functions
36 38 #-----------------------------------------------------------------------------
37 39
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 """
40 class NbConvertApp(BaseIPythonApplication):
41 """Application used to convert to and from notebook file type (*.ipynb)"""
47 42
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 43
44 description = Unicode(
45 u"""This application is used to convert notebook files (*.ipynb).
46 An ipython config file can be used to batch convert notebooks in the
47 current directory.""")
54 48
55 #-----------------------------------------------------------------------------
56 #Classes and functions
57 #-----------------------------------------------------------------------------
49 examples = Unicode(u"""
50 Running `ipython nbconvert` will read the directory config file and then
51 apply it to one or more notebooks.
58 52
59 class NbConvertApp(Application):
60 __doc__ = """IPython notebook conversion utility
53 Multiple notebooks can be given at the command line in a couple of
54 different ways:
55
56 > ipython nbconvert notebook*.ipynb
57 > ipython nbconvert notebook1.ipynb notebook2.ipynb
58 > ipython nbconvert # this will use the config file to fill in the notebooks
59 """)
61 60
62 Convert to and from notebook file type (*.ipynb)
61 config_file_name = Unicode(u'ipython_nbconvert_config.py')
63 62
64 ipython nbconvert TARGET FILENAME
63 #Writer specific variables
64 writer = Instance('IPython.nbconvert.writers.base.WriterBase',
65 help="""Instance of the writer class used to write the
66 results of the conversion.""")
67 writer_class = DottedObjectName('FilesWriter', config=True,
68 help="""Writer class used to write the
69 results of the conversion""")
70 writer_aliases = {'FilesWriter': 'IPython.nbconvert.writers.files.FilesWriter',
71 'DebugWriter': 'IPython.nbconvert.writers.debug.DebugWriter',
72 'StdoutWriter': 'IPython.nbconvert.writers.stdout.StdoutWriter'}
73 writer_factory = Type()
65 74
66 Supported export TARGETs are: %s
67 """ % (" ".join(get_export_names()))
68 description = Unicode(__doc__)
75 def _writer_class_changed(self, name, old, new):
76 if new in self.writer_aliases:
77 new = self.writer_aliases[new]
78 self.writer_factory = import_item(new)
69 79
70 examples = _examples
71 80
72 stdout = Bool(
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 )
81 #Other configurable variables
82 export_format = Unicode(
83 "", config=True,
84 help="""If specified, nbconvert will convert the document(s) specified
85 using this format.""")
77 86
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 )
87 notebooks = List([], config=True, help="""List of notebooks to convert.
88 Search patterns are supported.""")
83 89
84 aliases = {
85 'stdout':'NbConvertApp.stdout',
86 'write':'NbConvertApp.write',
87 }
90 aliases = {'format':'NbConvertApp.export_format',
91 'notebooks':'NbConvertApp.notebooks',
92 'writer':'NbConvertApp.writer_class'}
88 93
89 flags = {}
90 94
91 flags['stdout'] = (
92 {'NbConvertApp' : {'stdout' : True}},
93 """Print converted file to stdout, equivalent to --stdout=True
94 """
95 )
95 @catch_config_error
96 def initialize(self, argv=None):
97 super(NbConvertApp, self).initialize(argv)
96 98
97 flags['no-write'] = (
98 {'NbConvertApp' : {'write' : True}},
99 """Do not write to disk, equivalent to --write=False
100 """
101 )
99 #Register class here to have help with help all
100 self.classes.insert(0, Exporter)
101 self.classes.insert(0, WriterBase)
102 self.classes.insert(0, GlobalConfigurable)
102 103
104 #Init
105 self.init_config(self.extra_args)
106 self.init_writer()
103 107
104 def __init__(self, **kwargs):
105 """Public constructor"""
106 108
107 #Call base class
108 super(NbConvertApp, self).__init__(**kwargs)
109 def init_config(self, extra_args):
110 """
111 Add notebooks to the config if needed. Glob each notebook to replace
112 notebook patterns with filenames.
113 """
109 114
110 #Register class here to have help with help all
111 self.classes.insert(0, Exporter)
112 self.classes.insert(0, GlobalConfigurable)
115 #Get any additional notebook patterns from the commandline
116 if len(extra_args) > 0:
117 for pattern in extra_args:
118 self.notebooks.append(pattern)
119
120 #Use glob to replace all the notebook patterns with filenames.
121 filenames = []
122 for pattern in self.notebooks:
123 for filename in glob.glob(pattern):
124 if not filename in filenames:
125 filenames.append(filename)
126 self.notebooks = filenames
127
128
129 def init_writer(self):
130 """
131 Initialize the writer (which is stateless)
132 """
133 self._writer_class_changed(None, self.writer_class, self.writer_class)
134 self.writer = self.writer_factory(parent=self)
113 135
114 136
115 137 def start(self, argv=None):
116 """Entrypoint of NbConvert application.
117
118 Parameters
119 ----------
120 argv : list
121 Commandline arguments
122 138 """
123
124 #Parse the commandline options.
125 self.parse_command_line(argv)
139 Entrypoint of NbConvert application.
140 """
126 141
127 142 #Call base
128 143 super(NbConvertApp, self).start()
129 144
130 #The last arguments in list will be used by nbconvert
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 """
191
192 if self.stdout:
193 print(output.encode('utf-8'))
194
195 #Write file output from conversion.
196 if not destination_filename is None:
197 with io.open(destination_filename, 'w') as f:
198 f.write(output)
199
200 #Get the key names used by the extract figure transformer
201 figures_key = extractfigure.FIGURES_KEY
202 binary_key = extractfigure.BINARY_KEY
203 text_key = extractfigure.TEXT_KEY
204
205 #Output any associate figures into the same "root" directory.
206 binkeys = resources.get(figures_key, {}).get(binary_key,{}).keys()
207 textkeys = resources.get(figures_key, {}).get(text_key,{}).keys()
208 if binkeys or textkeys :
209 if not destination_directory is None:
210 for key in binkeys:
211 with io.open(os.path.join(destination_directory, key), 'wb') as f:
212 f.write(resources[figures_key][binary_key][key])
213 for key in textkeys:
214 with io.open(os.path.join(destination_directory, key), 'w') as f:
215 f.write(resources[figures_key][text_key][key])
216
217 #Figures that weren't exported which will need to be created by the
218 #user. Tell the user what figures these are.
219 if self.stdout:
220 print(KEYS_PROMPT_HEAD, file=sys.stderr)
221 print(resources[figures_key].keys(), file=sys.stderr)
222 print(KEYS_PROMPT_BODY , file=sys.stderr)
145 #Export each notebook
146 for notebook_filename in self.notebooks:
147
148 #Get a unique key for the notebook and set it in the resources object.
149 basename = os.path.basename(notebook_filename)
150 notebook_name = basename[:basename.rfind('.')]
151 resources = {}
152 resources['unique_key'] = notebook_name
153
154 #Export & write
155 output, resources = export_by_name(self.export_format,
156 notebook_filename,
157 resources=resources,
158 config=self.config)
159 self.writer.write(output, resources, notebook_name=notebook_name)
160
223 161
224 162 #-----------------------------------------------------------------------------
225 163 # Main entry point
226 164 #-----------------------------------------------------------------------------
227 165
228 166 launch_new_instance = NbConvertApp.launch_instance
229 167
@@ -1,10 +1,12 b''
1 1 # Class base Transformers
2 2 from .activatable import ActivatableTransformer
3 3 from .base import ConfigurableTransformer
4 from .convertfigures import ConvertFiguresTransformer
5 from .convertsvg import ConvertSvgTransformer
4 6 from .extractfigure import ExtractFigureTransformer
5 7 from .revealhelp import RevealHelpTransformer
6 8 from .latex import LatexTransformer
7 9 from .sphinx import SphinxTransformer
8 10
9 11 # decorated function Transformers
10 12 from .coalescestreams import coalesce_streams
@@ -1,99 +1,99 b''
1 1 """
2 2 Module that re-groups transformer that would be applied to ipynb files
3 3 before going through the templating machinery.
4 4
5 5 It exposes a convenient class to inherit from to access configurability.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2013, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from ..utils.config import GlobalConfigurable
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Classes and Functions
23 23 #-----------------------------------------------------------------------------
24 24
25 25 class ConfigurableTransformer(GlobalConfigurable):
26 26 """ A configurable transformer
27 27
28 28 Inherit from this class if you wish to have configurability for your
29 29 transformer.
30 30
31 31 Any configurable traitlets this class exposed will be configurable in profiles
32 32 using c.SubClassName.atribute=value
33 33
34 you can overwrite cell_transform to apply a transformation independently on each cell
34 you can overwrite transform_cell to apply a transformation independently on each cell
35 35 or __call__ if you prefer your own logic. See corresponding docstring for informations.
36 36 """
37 37
38 38 def __init__(self, config=None, **kw):
39 39 """
40 40 Public constructor
41 41
42 42 Parameters
43 43 ----------
44 44 config : Config
45 45 Configuration file structure
46 46 **kw : misc
47 47 Additional arguments
48 48 """
49 49
50 50 super(ConfigurableTransformer, self).__init__(config=config, **kw)
51 51
52 52
53 53 def __call__(self, nb, resources):
54 54 return self.call(nb,resources)
55 55
56 56 def call(self, nb, resources):
57 57 """
58 58 Transformation to apply on each notebook.
59 59
60 60 You should return modified nb, resources.
61 61 If you wish to apply your transform on each cell, you might want to
62 overwrite cell_transform method instead.
62 overwrite transform_cell method instead.
63 63
64 64 Parameters
65 65 ----------
66 66 nb : NotebookNode
67 67 Notebook being converted
68 68 resources : dictionary
69 69 Additional resources used in the conversion process. Allows
70 70 transformers to pass variables into the Jinja engine.
71 71 """
72 72 try :
73 73 for worksheet in nb.worksheets :
74 74 for index, cell in enumerate(worksheet.cells):
75 worksheet.cells[index], resources = self.cell_transform(cell, resources, index)
75 worksheet.cells[index], resources = self.transform_cell(cell, resources, index)
76 76 return nb, resources
77 77 except NotImplementedError:
78 78 raise NotImplementedError('should be implemented by subclass')
79 79
80 80
81 def cell_transform(self, cell, resources, index):
81 def transform_cell(self, cell, resources, index):
82 82 """
83 83 Overwrite if you want to apply a transformation on each cell. You
84 84 should return modified cell and resource dictionary.
85 85
86 86 Parameters
87 87 ----------
88 88 cell : NotebookNode cell
89 89 Notebook cell being processed
90 90 resources : dictionary
91 91 Additional resources used in the conversion process. Allows
92 92 transformers to pass variables into the Jinja engine.
93 93 index : int
94 94 Index of the cell being processed
95 95 """
96 96
97 97 raise NotImplementedError('should be implemented by subclass')
98 98 return cell, resources
99 99
@@ -1,143 +1,97 b''
1 1 """Module containing a transformer that extracts all of the figures from the
2 2 notebook file. The extracted figures are returned in the 'resources' dictionary.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 import itertools
16 15
17 16 from IPython.utils.traitlets import Dict, Unicode
18 17 from .activatable import ActivatableTransformer
19 18
20 19 #-----------------------------------------------------------------------------
21 20 # Constants
22 21 #-----------------------------------------------------------------------------
23 22
24 FIGURES_KEY = "figures"
25 BINARY_KEY = "binary"
26 TEXT_KEY = "text"
23 # win64 is win32 for backwards compatability, for now. See
24 # http://mail.python.org/pipermail/patches/2000-May/000648.html
25 # for the original patch that this decision was made.
26 WINDOWS_PLATFORMS = ['win32']
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Classes
30 30 #-----------------------------------------------------------------------------
31 31
32 32 class ExtractFigureTransformer(ActivatableTransformer):
33 33 """
34 34 Extracts all of the figures from the notebook file. The extracted
35 35 figures are returned in the 'resources' dictionary.
36 36 """
37 37
38 extra_extension_map = Dict({},
39 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 38
47 #TODO: Change this to .format {} syntax
48 default_key_template = Unicode('_fig_{index:02d}.{ext}', config=True)
39 figure_filename_template = Unicode(
40 "{unique_key}_{cell_index}_{index}.{extension}", config=True)
49 41
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
64 # A unique index for association with extracted figures
65 self.index_generator = itertools.count(1)
66 42
67 def cell_transform(self, cell, resources, index):
43 def transform_cell(self, cell, resources, cell_index):
68 44 """
69 45 Apply a transformation on each cell,
70 46
71 47 Parameters
72 48 ----------
73 49 cell : NotebookNode cell
74 50 Notebook cell being processed
75 51 resources : dictionary
76 52 Additional resources used in the conversion process. Allows
77 53 transformers to pass variables into the Jinja engine.
78 index : int
54 cell_index : int
79 55 Index of the cell being processed (see base.py)
80 56 """
57
58 #Get the unique key from the resource dict if it exists. If it does not
59 #exist, use 'figure' as the default.
60 unique_key = resources.get('unique_key', 'figure')
81 61
82 if resources.get(FIGURES_KEY, None) is None :
83 resources[FIGURES_KEY] = {TEXT_KEY:{},BINARY_KEY:{}}
62 #Make sure figures key exists
63 if not 'figures' in resources:
64 resources['figures'] = {}
84 65
85 for out in cell.get('outputs', []):
66 #Loop through all of the outputs in the cell
67 for index, out in enumerate(cell.get('outputs', [])):
68
69 #Get the output in data formats that the template is interested in.
86 70 for out_type in self.display_data_priority:
87
88 71 if out.hasattr(out_type):
89 figname, key, data, binary = self._new_figure(out[out_type], out_type)
90 out['key_'+out_type] = figname
91
92 if binary :
93 resources[FIGURES_KEY][BINARY_KEY][key] = data
94 else :
95 resources[FIGURES_KEY][TEXT_KEY][key] = data
96
97 index += 1
98 return cell, resources
99
100
101 def _get_override_extension(self, extension):
102 """Gets the overriden extension if it exists, else returns extension.
72 data = out[out_type]
103 73
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.
74 #Binary files are base64-encoded, SVG is already XML
75 if out_type in ('png', 'jpg', 'pdf'):
76 data = data.decode('base64')
77 elif sys.platform in WINDOWS_PLATFORMS:
78 data = data.replace('\n', '\r\n')
79
80 #Build a figure name
81 figure_name = self.figure_filename_template.format(
82 unique_key=unique_key,
83 cell_index=cell_index,
84 index=index,
85 extension=out_type)
86
87 #On the cell, make the figure available via
88 # cell.outputs[i].svg_filename ... etc (svg in example)
89 # Where
90 # cell.outputs[i].svg contains the data
91 out[out_type + '_filename'] = figure_name
92
93 #In the resources, make the figure available via
94 # resources['figures']['filename'] = data
95 resources['figures'][figure_name] = data
118 96
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
97 return cell, resources
@@ -1,53 +1,53 b''
1 1 """Module that allows latex output notebooks to be conditioned before
2 2 they are converted.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2013, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from __future__ import print_function, absolute_import
17 17
18 18 # Our own imports
19 19 # Needed to override transformer
20 20 from .activatable import (ActivatableTransformer)
21 21 from IPython.nbconvert import filters
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Classes
25 25 #-----------------------------------------------------------------------------
26 26
27 27 class LatexTransformer(ActivatableTransformer):
28 28 """
29 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 34 Apply a transformation on each cell,
35 35
36 36 Parameters
37 37 ----------
38 38 cell : NotebookNode cell
39 39 Notebook cell being processed
40 40 resources : dictionary
41 41 Additional resources used in the conversion process. Allows
42 42 transformers to pass variables into the Jinja engine.
43 43 index : int
44 44 Modified index of the cell being processed (see base.py)
45 45 """
46 46
47 47 #If the cell is a markdown cell, preprocess the ampersands used to
48 48 #remove the space between them and their contents. Latex will complain
49 49 #if spaces exist between the ampersands and the math content.
50 50 #See filters.latex.rm_math_space for more information.
51 51 if hasattr(cell, "source") and cell.cell_type == "markdown":
52 52 cell.source = filters.rm_math_space(cell.source)
53 53 return cell, resources
@@ -1,62 +1,61 b''
1 1 """Module that pre-processes the notebook for export via Reveal.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2013, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 from .base import ConfigurableTransformer
16 16 from IPython.utils.traitlets import Unicode
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Classes and functions
20 20 #-----------------------------------------------------------------------------
21 21
22 22 class RevealHelpTransformer(ConfigurableTransformer):
23 23
24 24 url_prefix = Unicode('//cdn.jsdelivr.net/reveal.js/2.4.0',
25 25 config=True,
26 26 help="""If you want to use a local reveal.js library,
27 27 use 'url_prefix':'reveal.js' in your config object.""")
28 28
29 29 def call(self, nb, resources):
30 30 """
31 31 Called once to 'transform' contents of the notebook.
32 32
33 33 Parameters
34 34 ----------
35 35 nb : NotebookNode
36 36 Notebook being converted
37 37 resources : dictionary
38 38 Additional resources used in the conversion process. Allows
39 39 transformers to pass variables into the Jinja engine.
40 40 """
41 41
42
43 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 45 #Make sure the cell has slideshow metadata.
47 46 cell.metadata.align_type = cell.get('metadata', {}).get('slideshow', {}).get('align_type', 'Left')
48 47 cell.metadata.slide_type = cell.get('metadata', {}).get('slideshow', {}).get('slide_type', '-')
49 48
50 49 #Get the slide type. If type is start of subslide or slide,
51 50 #end the last subslide/slide.
52 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 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 57 if 'reveal' not in resources:
59 58 resources['reveal'] = {}
60 59 resources['reveal']['url_prefix'] = self.url_prefix
61 60
62 61 return nb, resources
General Comments 0
You need to be logged in to leave comments. Login now