##// END OF EJS Templates
Post code-review, extended refactor.
Jonathan Frederic -
Show More
@@ -0,0 +1,23 b''
1 """Latex transformer.
2
3 Module that allows latex output notebooks to be conditioned before
4 they are converted.
5 """
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
8 #
9 # Distributed under the terms of the Modified BSD License.
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
13
14 #-----------------------------------------------------------------------------
15 # Functions
16 #-----------------------------------------------------------------------------
17 def export_sphinx_report(nb, config=None):
18 pass
19 def export_sphinx_report(nb, fileName, config=None):
20 pass
21
22 #TODO: Add basic export/import utility functions.
23 __author__ = 'root'
@@ -0,0 +1,82 b''
1 # ANSI color functions:
2 import re
3 def remove_ansi(src):
4 """Strip all ANSI color escape sequences from input string.
5
6 Parameters
7 ----------
8 src : string
9
10 Returns
11 -------
12 string
13 """
14 return re.sub(r'\033\[(0|\d;\d\d)m', '', src)
15
16
17 def ansi2html(txt):
18 """Render ANSI colors as HTML colors
19
20 This is equivalent to util.fixConsole in utils.js
21
22 Parameters
23 ----------
24 txt : string
25
26 Returns
27 -------
28 string
29 """
30
31 ansi_colormap = {
32 '30': 'ansiblack',
33 '31': 'ansired',
34 '32': 'ansigreen',
35 '33': 'ansiyellow',
36 '34': 'ansiblue',
37 '35': 'ansipurple',
38 '36': 'ansicyan',
39 '37': 'ansigrey',
40 '01': 'ansibold',
41 }
42
43 # do ampersand first
44 txt = txt.replace('&', '&')
45 html_escapes = {
46 '<': '&lt;',
47 '>': '&gt;',
48 "'": '&apos;',
49 '"': '&quot;',
50 '`': '&#96;',
51 }
52 for c, escape in html_escapes.iteritems():
53 txt = txt.replace(c, escape)
54
55 ansi_re = re.compile('\x1b' + r'\[([\dA-Fa-f;]*?)m')
56 m = ansi_re.search(txt)
57 opened = False
58 cmds = []
59 opener = ''
60 closer = ''
61 while m:
62 cmds = m.groups()[0].split(';')
63 closer = '</span>' if opened else ''
64 # True if there is there more than one element in cmds, *or*
65 # if there is only one but it is not equal to a string of zeroes.
66 opened = len(cmds) > 1 or cmds[0] != '0' * len(cmds[0])
67 classes = []
68 for cmd in cmds:
69 if cmd in ansi_colormap:
70 classes.append(ansi_colormap.get(cmd))
71
72 if classes:
73 opener = '<span class="%s">' % (' '.join(classes))
74 else:
75 opener = ''
76 txt = re.sub(ansi_re, closer + opener, txt, 1)
77
78 m = ansi_re.search(txt)
79
80 if opened:
81 txt += '</span>'
82 return txt
@@ -0,0 +1,39 b''
1 # Our own imports
2 from utils.lexers import IPythonLexer
3
4 #-----------------------------------------------------------------------------
5 # Globals and constants
6 #-----------------------------------------------------------------------------
7 _multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json']
8
9
10 #-----------------------------------------------------------------------------
11 # Utility functions
12 #-----------------------------------------------------------------------------
13 def highlight(src, lang='ipython'):
14 """
15 Return a syntax-highlighted version of the input source as html output.
16 """
17 from pygments.formatters import HtmlFormatter
18 return pygment_highlight(src, HtmlFormatter(), lang)
19
20 def highlight2latex(src, lang='ipython'):
21 """
22 Return a syntax-highlighted version of the input source as latex output.
23 """
24 from pygments.formatters import LatexFormatter
25 return pygment_highlight(src, LatexFormatter(), lang)
26
27 def pygment_highlight(src, output_formatter, lang='ipython'):
28 """
29 Return a syntax-highlighted version of the input source
30 """
31 from pygments import highlight
32 from pygments.lexers import get_lexer_by_name
33
34 if lang == 'ipython':
35 lexer = IPythonLexer()
36 else:
37 lexer = get_lexer_by_name(lang, stripall=True)
38
39 return highlight(src, lexer, output_formatter)
@@ -0,0 +1,43 b''
1
2 def cell_preprocessor(function):
3 """ wrap a function to be executed on all cells of a notebook
4
5 wrapped function parameters :
6 cell : the cell
7 other : external resources
8 index : index of the cell
9 """
10 def wrappedfunc(nb, other):
11 for worksheet in nb.worksheets :
12 for index, cell in enumerate(worksheet.cells):
13 worksheet.cells[index], other = function(cell, other, index)
14 return nb, other
15 return wrappedfunc
16
17
18 @cell_preprocessor
19 def coalesce_streams(cell, other, count):
20 """merge consecutive sequences of stream output into single stream
21
22 to prevent extra newlines inserted at flush calls
23
24 TODO: handle \r deletion
25 """
26 outputs = cell.get('outputs', [])
27 if not outputs:
28 return cell, other
29 new_outputs = []
30 last = outputs[0]
31 new_outputs = [last]
32 for output in outputs[1:]:
33 if (output.output_type == 'stream' and
34 last.output_type == 'stream' and
35 last.stream == output.stream
36 ):
37 last.text += output.text
38 else:
39 new_outputs.append(output)
40
41 cell.outputs = new_outputs
42 return cell, other
43
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
@@ -1,333 +1,266 b''
1 """Exporter for the notebook conversion pipeline.
1 """Exporter for the notebook conversion pipeline.
2
2
3 This module defines Exporter, a highly configurable converter
3 This module defines Exporter, a highly configurable converter
4 that uses Jinja2 to export notebook files into different format.
4 that uses Jinja2 to export notebook files into different format.
5
5
6 You can register both pre-transformers that will act on the notebook format
6 You can register both pre-transformers that will act on the notebook format
7 befor conversion and jinja filter that would then be availlable in the templates
7 befor conversion and jinja filter that would then be availlable in the templates
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (c) 2013, the IPython Development Team.
11 # Copyright (c) 2013, the IPython Development Team.
12 #
12 #
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14 #
14 #
15 # The full license is in the file COPYING.txt, distributed with this software.
15 # The full license is in the file COPYING.txt, distributed with this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 from __future__ import print_function, absolute_import
21 from __future__ import print_function, absolute_import
22
22
23 # Stdlib imports
23 # Stdlib imports
24 import io
24 import io
25 import os
25 import os
26 import re
27
26
28 # IPython imports
27 # IPython imports
29 from IPython.config.configurable import Configurable
28 from IPython.config.configurable import Configurable
30 from IPython.nbformat import current as nbformat
29 from IPython.nbformat import current as nbformat
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
30 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
32 from IPython.utils.text import indent
31 from IPython.utils.text import indent
33
32
34 # other libs/dependencies
33 # other libs/dependencies
35 from jinja2 import Environment, FileSystemLoader
34 from jinja2 import Environment, FileSystemLoader
36 from markdown import markdown
35 from markdown import markdown
37
36
38 # local import (pre-transformers)
37 # local import
39 from exceptions import ConversionException
38 import filters.strings
40 from . import transformers as trans #TODO
39 import filters.markdown
41 from .utils import get_lines #TODO
40 import filters.latex
42 from .utils import remove_ansi #TODO
41 import filters.datatypefilter
43 from .utils import highlight, ansi2html #TODO
42 import filters.pygments
43 import filters.ansi
44
45 import transformers.extractfigure
46 import transformers.csshtmlheader
47 import transformers.revealhelp
48 import transformers.coalescestreams
44
49
45 import .utils.strings as strings
46 import .utils.markdown as markdown_utils
47 import .utils.datatypefilter.DataTypeFilter as DataTypeFilter
48
50
49 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
50 # Globals and constants
52 # Globals and constants
51 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
52
54
53 #Standard Jinja2 environment constants
55 #Standard Jinja2 environment constants
54 TEMPLATE_PATH = "/../templates/"
56 TEMPLATE_PATH = "/../templates/"
55 TEMPLATE_SKELETON_PATH = "/../templates/skeleton/"
57 TEMPLATE_SKELETON_PATH = "/../templates/skeleton/"
56 TEMPLATE_EXTENSION = ".tpl"
58 TEMPLATE_EXTENSION = ".tpl"
57
59
58 #Jinja2 extensions to load.
60 #Jinja2 extensions to load.
59 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
61 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
60
62
61 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
62 # Classes and functions
64 # Classes and functions
63 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
64 class Exporter(Configurable):
66 class Exporter(Configurable):
65 """ A Jinja2 base converter templates
67 """ A Jinja2 base converter templates
66
68
67 Preprocess the ipynb files, feed it throug jinja templates,
69 Pre-process the IPYNB files, feed it through Jinja2 templates,
68 and spit an converted files and a data object with other data
70 and spit an converted files and a data object with other data
69 should be mostly configurable
71 should be mostly configurable
70 """
72 """
71
73
72 pre_transformer_order = List(['haspyout_transformer'],
74 pre_transformer_order = List(['haspyout_transformer'],
73 config=True,
75 config=True,
74 help= """
76 help= """
75 An ordered list of pre transformer to apply to the ipynb
77 An ordered list of pre-transformer to apply to the IPYNB
76 file before running through templates
78 file before running through templates
77 """
79 """
78 )
80 )
79
81
80 #TODO: Flagged for removal.
81 tex_environement = Bool(
82 False,
83 config=True,
84 help=" Whether or not the user is exporting to latex.")
85
86 template_file = Unicode(
82 template_file = Unicode(
87 '', config=True,
83 '', config=True,
88 help="Name of the template file to use")
84 help="Name of the template file to use")
89
85
90 fileext = Unicode(
86 fileext = Unicode(
91 'txt', config=True,
87 'txt', config=True,
92 help="Extension of the file that should be written to disk"
88 help="Extension of the file that should be written to disk"
93 )
89 )
94
90
95 stdout = Bool(
91 stdout = Bool(
96 True, config=True,
92 True, config=True,
97 help="""Whether to print the converted ipynb file to stdout
93 help="""Whether to print the converted IPYNB file to stdout
98 "use full do diff files without actually writing a new file"""
94 "use full do diff files without actually writing a new file"""
99 )
95 )
100
96
101 write = Bool(
97 write = Bool(
102 False, config=True,
98 False, config=True,
103 help="""Should the converted notebook file be written to disk
99 help="""Should the converted notebook file be written to disk
104 along with potential extracted resources."""
100 along with potential extracted resources."""
105 )
101 )
106
102
107 #Processors that process the input data prior to the export, set in the
103 #Processors that process the input data prior to the export, set in the
108 #constructor for this class.
104 #constructor for this class.
109 preprocessors = []
105 preprocessors = []
110
106
111 def __init__(self, preprocessors={}, jinja_filters={}, config=None, export_format, **kw):
107 def __init__(self, preprocessors={}, jinja_filters={}, config=None, export_format, **kw):
112 """ Init a new converter.
108 """ Init a new converter.
113
109
114 config: the Configurable config object to pass around.
110 config: the Configurable config object to pass around.
115
111
116 preprocessors: dict of **availlable** key/value function to run on
112 preprocessors: dict of **availlable** key/value function to run on
117 ipynb json data before conversion to extract/inline file.
113 ipynb json data before conversion to extract/inline file.
118 See `transformer.py` and `ConfigurableTransformers`
114 See `transformer.py` and `ConfigurableTransformers`
119
115
120 set the order in which the transformers should apply
116 set the order in which the transformers should apply
121 with the `pre_transformer_order` trait of this class
117 with the `pre_transformer_order` trait of this class
122
118
123 transformers registerd by this key will take precedence on
119 transformers registerd by this key will take precedence on
124 default one.
120 default one.
125
121
126 jinja_filters: dict of supplementary jinja filter that should be made
122 jinja_filters: dict of supplementary jinja filter that should be made
127 availlable in template. If those are of Configurable Class type,
123 availlable in template. If those are of Configurable Class type,
128 they will be instanciated with the config object as argument.
124 they will be instanciated with the config object as argument.
129
125
130 user defined filter will overwrite the one availlable by default.
126 user defined filter will overwrite the one availlable by default.
131 """
127 """
132
128
133 #Merge default config options with user specific override options.
129 #Set the default options for the exporter.
134 default_config = self._get_default_options()
130 default_config = self.config
131
132 #Set properties that must be set in the config class in order to
133 #propagate to other classes.
134 default_config.GlobalConfigurable.display_data_priority =['svg', 'png', 'latex', 'jpg', 'jpeg','text']
135 default_config.ExtractFigureTransformer.display_data_priority=['svg', 'png', 'latex', 'jpg', 'jpeg','text']
136
137 #Set default properties of the exporter.
138 #For most (or all cases), the template file name matches the format name.
139 self.display_data_priority= ['svg', 'png', 'latex', 'jpg', 'jpeg','text']
140 self.template_file = export_format
141
135 if not config == None:
142 if not config == None:
136 default_config._merge(config)
143 default_config._merge(config)
137 config = default_config
144 config = default_config
138
145
139 #Call the base class constructor
146 #Call the base class constructor
140 super(Exporter, self).__init__(config=config, **kw)
147 super(Exporter, self).__init__(config=config, **kw)
141
148
142 #Standard environment
149 #Standard environment
143 self.ext = TEMPLATE_EXTENSION
150 self.ext = TEMPLATE_EXTENSION
144 self.env = Environment(
151 self._init_environment()
145 loader=FileSystemLoader([
146 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
147 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
148 ]),
149 extensions=JINJA_EXTENSIONS
150 )
151
152
152 for name in self.pre_transformer_order:
153 #TODO: Implement reflection style methods to get user transformers.
153 # get the user-defined transformer first
154 #for name in self.pre_transformer_order:
154 transformer = preprocessors.get(name, getattr(trans, name, None))
155 # # get the user-defined transformer first
155 if isinstance(transformer, MetaHasTraits):
156 # transformer = preprocessors.get(name, getattr(trans, name, None))
156 transformer = transformer(config=config)
157 # if isinstance(transformer, MetaHasTraits):
157 self.preprocessors.append(transformer)
158 # transformer = transformer(config=config)
159 # self.preprocessors.append(transformer)
158
160
159 #For compatibility, TODO: remove later.
161 #For compatibility, TODO: remove later.
160 self.preprocessors.append(trans.coalesce_streams)
162 self.preprocessors.append(transformers.coalescestreams.coalesce_streams)
161 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
163 self.preprocessors.append(transformers.extractfigure.ExtractFigureTransformer(config=config))
162 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
164 self.preprocessors.append(transformers.revealhelp.RevealHelpTransformer(config=config))
163 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
165 self.preprocessors.append(transformers.csshtmlheader.CSSHtmlHeaderTransformer(config=config))
164 self.preprocessors.append(LatexTransformer(config=config))
165
166 #Only load the sphinx transformer if the file reference worked
167 #(Sphinx dependencies exist on the user's machine.)
168 if SphinxTransformer:
169 self.preprocessors.append(SphinxTransformer(config=config))
170
166
171 #Add filters to the Jinja2 environment
167 #Add filters to the Jinja2 environment
172 self.env.filters['filter_data_type'] = DataTypeFilter(config=config)
168 self._register_filters(config)
173 self.env.filters['pycomment'] = _python_comment
174 self.env.filters['indent'] = indent
175 self.env.filters['rm_fake'] = _rm_fake
176 self.env.filters['rm_ansi'] = remove_ansi
177 self.env.filters['markdown'] = markdown
178 self.env.filters['ansi2html'] = ansi2html
179 self.env.filters['markdown2latex'] = markdown_utils.markdown2latex
180 self.env.filters['markdown2rst'] = markdown_utils.markdown2rst
181 self.env.filters['get_lines'] = get_lines
182 self.env.filters['wrap'] = strings.wrap
183 self.env.filters['rm_dollars'] = strings.strip_dollars
184 self.env.filters['rm_math_space'] = rm_math_space
185 self.env.filters['highlight2html'] = highlight
186 self.env.filters['highlight2latex'] = highlight2latex
187
188 #Latex specific filters
189 if self.tex_environement:
190 self.env.filters['escape_tex'] = _escape_tex
191 self.env.filters['highlight'] = highlight2latex
192 else:
193 self.env.filters['highlight'] = highlight
194
169
195 #Load user filters. Overwrite existing filters if need be.
170 #Load user filters. Overwrite existing filters if need be.
196 for key, user_filter in jinja_filters.iteritems():
171 for key, user_filter in jinja_filters.iteritems():
197 if isinstance(user_filter, MetaHasTraits):
172 if isinstance(user_filter, MetaHasTraits):
198 self.env.filters[key] = user_filter(config=config)
173 self.env.filters[key] = user_filter(config=config)
199 else:
174 else:
200 self.env.filters[key] = user_filter
175 self.env.filters[key] = user_filter
201
176
202 #Load the template file.
177 #Load the template file.
203 self.template = self.env.get_template(self.template_file+self.ext)
178 self.template = self.env.get_template(self.template_file+self.ext)
204
179
205
180
206 def export(self, nb):
181 def export(self, nb):
207 """Export notebook object
182 """Export notebook object
208
183
209 nb: Notebook object to export.
184 nb: Notebook object to export.
210
185
211 Returns both the converted ipynb file and a dict containing the
186 Returns both the converted ipynb file and a dict containing the
212 resources created along the way via the transformers and Jinja2
187 resources created along the way via the transformers and Jinja2
213 processing.
188 processing.
214 """
189 """
215
190
216 nb, resources = self._preprocess(nb)
191 nb, resources = self._preprocess(nb)
217 return self.template.render(nb=nb, resources=resources), resources
192 return self.template.render(nb=nb, resources=resources), resources
218
193
219
194
220 def from_filename(self, filename):
195 def from_filename(self, filename):
221 """Read and export a notebook from a filename
196 """Read and export a notebook from a filename
222
197
223 filename: Filename of the notebook file to export.
198 filename: Filename of the notebook file to export.
224
199
225 Returns both the converted ipynb file and a dict containing the
200 Returns both the converted ipynb file and a dict containing the
226 resources created along the way via the transformers and Jinja2
201 resources created along the way via the transformers and Jinja2
227 processing.
202 processing.
228 """
203 """
229 with io.open(filename) as f:
204 with io.open(filename) as f:
230 return self.export(nbformat.read(f, 'json'))
205 return self.export(nbformat.read(f, 'json'))
231
206
232
207
233 def from_file(self, file_stream):
208 def from_file(self, file_stream):
234 """Read and export a notebook from a filename
209 """Read and export a notebook from a filename
235
210
236 file_stream: File handle of file that contains notebook data.
211 file_stream: File handle of file that contains notebook data.
237
212
238 Returns both the converted ipynb file and a dict containing the
213 Returns both the converted ipynb file and a dict containing the
239 resources created along the way via the transformers and Jinja2
214 resources created along the way via the transformers and Jinja2
240 processing.
215 processing.
241 """
216 """
242
217
243 return self.export(nbformat.read(file_stream, 'json'))
218 return self.export(nbformat.read(file_stream, 'json'))
244
219
245
220
221 def _init_environment(self):
222 self.env = Environment(
223 loader=FileSystemLoader([
224 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
225 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
226 ]),
227 extensions=JINJA_EXTENSIONS
228 )
229
230
231 def _register_filters(self, config):
232 self.env.filters['indent'] = indent
233 self.env.filters['markdown'] = markdown
234
235 self.env.filters['ansi2html'] = filters.ansi.ansi2html
236 self.env.filters['filter_data_type'] = filters.datatypefilter.DataTypeFilter(config=config)
237 self.env.filters['get_lines'] = filters.strings.get_lines
238 self.env.filters['highlight'] = filters.pygments.highlight
239 self.env.filters['highlight2html'] = filters.pygments.highlight
240 self.env.filters['highlight2latex'] = filters.pygments.highlight2latex
241 self.env.filters['markdown2latex'] = filters.markdown.markdown2latex
242 self.env.filters['markdown2rst'] = filters.markdown.markdown2rst
243 self.env.filters['pycomment'] = filters.strings.python_comment
244 self.env.filters['rm_ansi'] = filters.ansi.remove_ansi
245 self.env.filters['rm_dollars'] = filters.strings.strip_dollars
246 self.env.filters['rm_fake'] = filters.strings.rm_fake
247 self.env.filters['rm_math_space'] = filters.latex.rm_math_space
248 self.env.filters['wrap'] = filters.strings.wrap
249
250
246 def _preprocess(self, nb):
251 def _preprocess(self, nb):
247 """ Preprocess the notebook using the transformers specific
252 """ Preprocess the notebook using the transformers specific
248 for the current export format.
253 for the current export format.
249
254
250 nb: Notebook to preprocess
255 nb: Notebook to preprocess
251 """
256 """
252
257
253 #Dict of 'resources' that can be filled by the preprocessors.
258 #Dict of 'resources' that can be filled by the preprocessors.
254 resources = {}
259 resources = {}
255
260
256 #Run each transformer on the notebook. Carry the output along
261 #Run each transformer on the notebook. Carry the output along
257 #to each transformer
262 #to each transformer
258 for transformer in self.preprocessors:
263 for transformer in self.preprocessors:
259 nb, resources = transformer(nb, resources)
264 nb, resources = transformer(nb, resources)
260 return nb, resources
265 return nb, resources
261
266
262
263 def _get_default_options(self, export_format):
264 """ Load the default options for built in formats.
265
266 export_format: Format being exported to.
267 """
268
269 c = get_config()
270
271 #Set default data extraction priorities.
272 c.GlobalConfigurable.display_data_priority =['svg', 'png', 'latex', 'jpg', 'jpeg','text']
273 c.ExtractFigureTransformer.display_data_priority=['svg', 'png', 'latex', 'jpg', 'jpeg','text']
274 c.ConverterTemplate.display_data_priority= ['svg', 'png', 'latex', 'jpg', 'jpeg','text']
275
276 #For most (or all cases), the template file name matches the format name.
277 c.ConverterTemplate.template_file = export_format
278
279 if export_format == "basichtml" or "fullhtml" or "reveal":
280 c.CSSHtmlHeaderTransformer.enabled=True
281 if export_format == 'reveal'
282 c.NbconvertApp.fileext='reveal.html'
283 else:
284 c.NbconvertApp.fileext='html'
285
286 elif export_format == "latex_sphinx_howto" or export_format == "latex_sphinx_manual":
287
288 #Turn on latex environment
289 c.ConverterTemplate.tex_environement=True
290
291 #Standard latex extension
292 c.NbconvertApp.fileext='tex'
293
294 #Prioritize latex extraction for latex exports.
295 c.GlobalConfigurable.display_data_priority =['latex', 'svg', 'png', 'jpg', 'jpeg' , 'text']
296 c.ExtractFigureTransformer.display_data_priority=['latex', 'svg', 'png', 'jpg', 'jpeg']
297 c.ExtractFigureTransformer.extra_ext_map={'svg':'pdf'}
298 c.ExtractFigureTransformer.enabled=True
299
300 # Enable latex transformers (make markdown2latex work with math $.)
301 c.LatexTransformer.enabled=True
302 c.SphinxTransformer.enabled = True
303
304 elif export_format == 'markdown':
305 c.NbconvertApp.fileext='md'
306 c.ExtractFigureTransformer.enabled=True
307
308 elif export_format == 'python':
309 c.NbconvertApp.fileext='py'
310
311
312 elif export_format == 'rst':
313 c.NbconvertApp.fileext='rst'
314 c.ExtractFigureTransformer.enabled=True
315 return c
316
317
318 #TODO: Comment me.
319 def _rm_fake(strng):
320 return strng.replace('/files/', '')
321
322
323 #TODO: Comment me.
324 def _python_comment(string):
325 return '# '+'\n# '.join(string.split('\n'))
326
327
328 #TODO: Comment me.
329 def _escape_tex(value):
330 newval = value
331 for pattern, replacement in LATEX_SUBS:
332 newval = pattern.sub(replacement, newval)
333 return newval No newline at end of file
@@ -1,295 +1,150 b''
1
1 """Latex exporter for the notebook conversion pipeline.
2 """Latex exporter for the notebook conversion pipeline.
3
2
4 This module defines Exporter, a highly configurable converter
3 This module defines Exporter, a highly configurable converter
5 that uses Jinja2 to export notebook files into different format.
4 that uses Jinja2 to export notebook files into different format.
6
5
7 You can register both pre-transformers that will act on the notebook format
6 You can register both pre-transformers that will act on the notebook format
8 befor conversion and jinja filter that would then be availlable in the templates
7 befor conversion and jinja filter that would then be availlable in the templates
9 """
8 """
10
9
11 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
12 # Copyright (c) 2013, the IPython Development Team.
11 # Copyright (c) 2013, the IPython Development Team.
13 #
12 #
14 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
15 #
14 #
16 # The full license is in the file COPYING.txt, distributed with this software.
15 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
18
17
19 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
20 # Imports
19 # Imports
21 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
22 from .utils import highlight2latex #TODO
21 import base.Exporter as Exporter
23
24 from .transformers.latex import LatexTransformer, rm_math_space #TODO: rm_math_space from filters
25
22
26 #Try to import the Sphinx exporter. If the user doesn't have Sphinx isntalled
23 #Try to import the Sphinx exporter. If the user doesn't have Sphinx isntalled
27 #on his/her machine, fail silently.
24 #on his/her machine, fail silently.
28 try:
25 try:
29 from .sphinx_transformer import (SphinxTransformer) #TODO
26 from .sphinx_transformer import (SphinxTransformer) #TODO
30 except ImportError:
27 except ImportError:
31 SphinxTransformer = None
28 SphinxTransformer = None
32
29
33 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
34 # Globals and constants
31 # Globals and constants
35 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
36
33
37 #Latex Jinja2 constants
34 #Latex Jinja2 constants
38 LATEX_TEMPLATE_PATH = "/../templates/tex/"
35 LATEX_TEMPLATE_PATH = "/../templates/tex/"
39 LATEX_TEMPLATE_SKELETON_PATH = "/../templates/tex/skeleton/"
36 LATEX_TEMPLATE_SKELETON_PATH = "/../templates/tex/skeleton/"
40 LATEX_TEMPLATE_EXTENSION = ".tplx"
37 LATEX_TEMPLATE_EXTENSION = ".tplx"
41
38
42 #Special Jinja2 syntax that will not conflict when exporting latex.
39 #Special Jinja2 syntax that will not conflict when exporting latex.
43 LATEX_JINJA_COMMENT_BLOCK = ["((=", "=))"]
40 LATEX_JINJA_COMMENT_BLOCK = ["((=", "=))"]
44 LATEX_JINJA_VARIABLE_BLOCK = ["(((", ")))"]
41 LATEX_JINJA_VARIABLE_BLOCK = ["(((", ")))"]
45 LATEX_JINJA_LOGIC_BLOCK = ["((*", "*))"]
42 LATEX_JINJA_LOGIC_BLOCK = ["((*", "*))"]
46
43
47 #Latex substitutions for escaping latex.
48 LATEX_SUBS = (
49 (re.compile(r'\\'), r'\\textbackslash'),
50 (re.compile(r'([{}_#%&$])'), r'\\\1'),
51 (re.compile(r'~'), r'\~{}'),
52 (re.compile(r'\^'), r'\^{}'),
53 (re.compile(r'"'), r"''"),
54 (re.compile(r'\.\.\.+'), r'\\ldots'),
55 )
56
57 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
58 # Classes and functions
45 # Classes and functions
59 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
60 class LatexExporter(Configurable):
47 class LatexExporter(Exporter):
61 """ A Jinja2 base converter templates
48 """ A Jinja2 base converter templates
62
49
63 Preprocess the ipynb files, feed it throug jinja templates,
50 Preprocess the ipynb files, feed it throug jinja templates,
64 and spit an converted files and a data object with other data
51 and spit an converted files and a data object with other data
65 should be mostly configurable
52 should be mostly configurable
66 """
53 """
67
54
68 #Processors that process the input data prior to the export, set in the
55 #Processors that process the input data prior to the export, set in the
69 #constructor for this class.
56 #constructor for this class.
70 preprocessors = []
57 preprocessors = []
71
58
72 def __init__(self, preprocessors={}, jinja_filters={}, config=None, export_format, **kw):
59 def __init__(self, preprocessors={}, jinja_filters={}, config=None, export_format, **kw):
73 """ Init a new converter.
60 """ Init a new converter.
74
61
75 config: the Configurable config object to pass around.
62 config: the Configurable config object to pass around.
76
63
77 preprocessors: dict of **availlable** key/value function to run on
64 preprocessors: dict of **availlable** key/value function to run on
78 ipynb json data before conversion to extract/inline file.
65 ipynb json data before conversion to extract/inline file.
79 See `transformer.py` and `ConfigurableTransformers`
66 See `transformer.py` and `ConfigurableTransformers`
80
67
81 set the order in which the transformers should apply
68 set the order in which the transformers should apply
82 with the `pre_transformer_order` trait of this class
69 with the `pre_transformer_order` trait of this class
83
70
84 transformers registerd by this key will take precedence on
71 transformers registerd by this key will take precedence on
85 default one.
72 default one.
86
73
87 jinja_filters: dict of supplementary jinja filter that should be made
74 jinja_filters: dict of supplementary jinja filter that should be made
88 availlable in template. If those are of Configurable Class type,
75 availlable in template. If those are of Configurable Class type,
89 they will be instanciated with the config object as argument.
76 they will be instanciated with the config object as argument.
90
77
91 user defined filter will overwrite the one availlable by default.
78 user defined filter will overwrite the one availlable by default.
92 """
79 """
93
80
94 #Merge default config options with user specific override options.
81 #Merge default config options with user specific override options.
95 default_config = self._get_default_options()
82 default_config = self._get_default_options()
96 if not config == None:
83 if not config == None:
97 default_config._merge(config)
84 default_config._merge(config)
98 config = default_config
85 config = default_config
99
86
100 #Call the base class constructor
87 #Call the base class constructor
101 super(Exporter, self).__init__(config=config, **kw)
88 super(Exporter, self).__init__(config=config, **kw)
102
89
103 #Create a Latex environment if the user is exporting latex.
90 #Create a Latex environment if the user is exporting latex.
104 if self.tex_environement:
91 if self.tex_environement:
105 self.ext = LATEX_TEMPLATE_EXTENSION
92 self.ext = LATEX_TEMPLATE_EXTENSION
106 self.env = Environment(
93 self.env = Environment(
107 loader=FileSystemLoader([
94 loader=FileSystemLoader([
108 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_PATH,
95 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_PATH,
109 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_SKELETON_PATH,
96 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_SKELETON_PATH,
110 ]),
97 ]),
111 extensions=JINJA_EXTENSIONS
98 extensions=JINJA_EXTENSIONS
112 )
99 )
113
100
114 #Set special Jinja2 syntax that will not conflict with latex.
101 #Set special Jinja2 syntax that will not conflict with latex.
115 self.env.block_start_string = LATEX_JINJA_LOGIC_BLOCK[0]
102 self.env.block_start_string = LATEX_JINJA_LOGIC_BLOCK[0]
116 self.env.block_end_string = LATEX_JINJA_LOGIC_BLOCK[1]
103 self.env.block_end_string = LATEX_JINJA_LOGIC_BLOCK[1]
117 self.env.variable_start_string = LATEX_JINJA_VARIABLE_BLOCK[0]
104 self.env.variable_start_string = LATEX_JINJA_VARIABLE_BLOCK[0]
118 self.env.variable_end_string = LATEX_JINJA_VARIABLE_BLOCK[1]
105 self.env.variable_end_string = LATEX_JINJA_VARIABLE_BLOCK[1]
119 self.env.comment_start_string = LATEX_JINJA_COMMENT_BLOCK[0]
106 self.env.comment_start_string = LATEX_JINJA_COMMENT_BLOCK[0]
120 self.env.comment_end_string = LATEX_JINJA_COMMENT_BLOCK[1]
107 self.env.comment_end_string = LATEX_JINJA_COMMENT_BLOCK[1]
121
108
122 else: #Standard environment
109 else: #Standard environment
123 self.ext = TEMPLATE_EXTENSION
110 self.ext = TEMPLATE_EXTENSION
124 self.env = Environment(
111 self.env = Environment(
125 loader=FileSystemLoader([
112 loader=FileSystemLoader([
126 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
113 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
127 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
114 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
128 ]),
115 ]),
129 extensions=JINJA_EXTENSIONS
116 extensions=JINJA_EXTENSIONS
130 )
117 )
131
118
132 for name in self.pre_transformer_order:
119 for name in self.pre_transformer_order:
133 # get the user-defined transformer first
120 # get the user-defined transformer first
134 transformer = preprocessors.get(name, getattr(trans, name, None))
121 transformer = preprocessors.get(name, getattr(trans, name, None))
135 if isinstance(transformer, MetaHasTraits):
122 if isinstance(transformer, MetaHasTraits):
136 transformer = transformer(config=config)
123 transformer = transformer(config=config)
137 self.preprocessors.append(transformer)
124 self.preprocessors.append(transformer)
138
125
139 #For compatibility, TODO: remove later.
126 #For compatibility, TODO: remove later.
140 self.preprocessors.append(trans.coalesce_streams)
127 self.preprocessors.append(trans.coalesce_streams)
141 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
128 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
142 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
129 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
143 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
130 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
144 self.preprocessors.append(LatexTransformer(config=config))
131 self.preprocessors.append(LatexTransformer(config=config))
145
132
146 #Only load the sphinx transformer if the file reference worked
133 #Only load the sphinx transformer if the file reference worked
147 #(Sphinx dependencies exist on the user's machine.)
134 #(Sphinx dependencies exist on the user's machine.)
148 if SphinxTransformer:
135 if SphinxTransformer:
149 self.preprocessors.append(SphinxTransformer(config=config))
136 self.preprocessors.append(SphinxTransformer(config=config))
150
137
151 #Add filters to the Jinja2 environment
138 #Add filters to the Jinja2 environment
152 self.env.filters['filter_data_type'] = DataTypeFilter(config=config)
139 self.env.filters['escape_tex'] = filters.latex.escape_tex
153 self.env.filters['pycomment'] = _python_comment
140 self.env.filters['highlight'] = filters.pygments.highlight2latex
154 self.env.filters['indent'] = indent
141
155 self.env.filters['rm_fake'] = _rm_fake
156 self.env.filters['rm_ansi'] = remove_ansi
157 self.env.filters['markdown'] = markdown
158 self.env.filters['ansi2html'] = ansi2html
159 self.env.filters['markdown2latex'] = markdown_utils.markdown2latex
160 self.env.filters['markdown2rst'] = markdown_utils.markdown2rst
161 self.env.filters['get_lines'] = get_lines
162 self.env.filters['wrap'] = strings.wrap
163 self.env.filters['rm_dollars'] = strings.strip_dollars
164 self.env.filters['rm_math_space'] = rm_math_space
165 self.env.filters['highlight2html'] = highlight
166 self.env.filters['highlight2latex'] = highlight2latex
167
168 #Latex specific filters
169 if self.tex_environement:
170 self.env.filters['escape_tex'] = _escape_tex
171 self.env.filters['highlight'] = highlight2latex
172 else:
173 self.env.filters['highlight'] = highlight
174
175 #Load user filters. Overwrite existing filters if need be.
142 #Load user filters. Overwrite existing filters if need be.
176 for key, user_filter in jinja_filters.iteritems():
143 for key, user_filter in jinja_filters.iteritems():
177 if isinstance(user_filter, MetaHasTraits):
144 if isinstance(user_filter, MetaHasTraits):
178 self.env.filters[key] = user_filter(config=config)
145 self.env.filters[key] = user_filter(config=config)
179 else:
146 else:
180 self.env.filters[key] = user_filter
147 self.env.filters[key] = user_filter
181
148
182 #Load the template file.
149 #Load the template file.
183 self.template = self.env.get_template(self.template_file+self.ext)
150 self.template = self.env.get_template(self.template_file+self.ext)
184
185
186 def export(self, nb):
187 """Export notebook object
188
189 nb: Notebook object to export.
190
191 Returns both the converted ipynb file and a dict containing the
192 resources created along the way via the transformers and Jinja2
193 processing.
194 """
195
196 nb, resources = self._preprocess(nb)
197 return self.template.render(nb=nb, resources=resources), resources
198
199
200 def from_filename(self, filename):
201 """Read and export a notebook from a filename
202
203 filename: Filename of the notebook file to export.
204
205 Returns both the converted ipynb file and a dict containing the
206 resources created along the way via the transformers and Jinja2
207 processing.
208 """
209 with io.open(filename) as f:
210 return self.export(nbformat.read(f, 'json'))
211
212
213 def from_file(self, file_stream):
214 """Read and export a notebook from a filename
215
216 file_stream: File handle of file that contains notebook data.
217
218 Returns both the converted ipynb file and a dict containing the
219 resources created along the way via the transformers and Jinja2
220 processing.
221 """
222
223 return self.export(nbformat.read(file_stream, 'json'))
224
225
226 def _preprocess(self, nb):
227 """ Preprocess the notebook using the transformers specific
228 for the current export format.
229
230 nb: Notebook to preprocess
231 """
232
233 #Dict of 'resources' that can be filled by the preprocessors.
234 resources = {}
235
236 #Run each transformer on the notebook. Carry the output along
237 #to each transformer
238 for transformer in self.preprocessors:
239 nb, resources = transformer(nb, resources)
240 return nb, resources
241
242
243 def _get_default_options(self, export_format):
244 """ Load the default options for built in formats.
245
246 export_format: Format being exported to.
247 """
248
249 c = get_config()
250
251 #Set default data extraction priorities.
252 c.GlobalConfigurable.display_data_priority =['svg', 'png', 'latex', 'jpg', 'jpeg','text']
253 c.ExtractFigureTransformer.display_data_priority=['svg', 'png', 'latex', 'jpg', 'jpeg','text']
254 c.ConverterTemplate.display_data_priority= ['svg', 'png', 'latex', 'jpg', 'jpeg','text']
255
256 #For most (or all cases), the template file name matches the format name.
257 c.ConverterTemplate.template_file = export_format
258
259 if export_format == "basichtml" or "fullhtml" or "reveal":
260 c.CSSHtmlHeaderTransformer.enabled=True
261 if export_format == 'reveal'
262 c.NbconvertApp.fileext='reveal.html'
263 else:
264 c.NbconvertApp.fileext='html'
265
266 elif export_format == "latex_sphinx_howto" or export_format == "latex_sphinx_manual":
267
268 #Turn on latex environment
269 c.ConverterTemplate.tex_environement=True
270
271 #Standard latex extension
272 c.NbconvertApp.fileext='tex'
273
274 #Prioritize latex extraction for latex exports.
275 c.GlobalConfigurable.display_data_priority =['latex', 'svg', 'png', 'jpg', 'jpeg' , 'text']
276 c.ExtractFigureTransformer.display_data_priority=['latex', 'svg', 'png', 'jpg', 'jpeg']
277 c.ExtractFigureTransformer.extra_ext_map={'svg':'pdf'}
278 c.ExtractFigureTransformer.enabled=True
279
280 # Enable latex transformers (make markdown2latex work with math $.)
281 c.LatexTransformer.enabled=True
282 c.SphinxTransformer.enabled = True
283
284 elif export_format == 'markdown':
285 c.NbconvertApp.fileext='md'
286 c.ExtractFigureTransformer.enabled=True
287
288 elif export_format == 'python':
289 c.NbconvertApp.fileext='py'
290
291
292 elif export_format == 'rst':
293 c.NbconvertApp.fileext='rst'
294 c.ExtractFigureTransformer.enabled=True
295 return c No newline at end of file
@@ -1,31 +1,31 b''
1 """Filter used to select the first prefered output format available.
1 """Filter used to select the first prefered output format available.
2
2
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 GlobalConfigurable.display_data_priority
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (c) 2013, the IPython Development Team.
9 # Copyright (c) 2013, the IPython Development Team.
10 #
10 #
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12 #
12 #
13 # The full license is in the file COPYING.txt, distributed with this software.
13 # The full license is in the file COPYING.txt, distributed with this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Classes and functions
17 # Classes and functions
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 class DataTypeFilter(GlobalConfigurable):
19 class DataTypeFilter(GlobalConfigurable):
20 """ Returns the prefered display format """
20 """ Returns the prefered display format """
21
21
22 def __init__(self, config=None, **kw):
22 def __init__(self, config=None, **kw):
23 super(FilterDataType, self).__init__(config=config, **kw)
23 super(DataTypeFilter, self).__init__(config=config, **kw)
24
24
25 def __call__(self, output):
25 def __call__(self, output):
26 """ Return the first available format in the priority """
26 """ Return the first available format in the priority """
27
27
28 for fmt in self.display_data_priority:
28 for fmt in self.display_data_priority:
29 if fmt in output:
29 if fmt in output:
30 return [fmt]
30 return [fmt]
31 return [] No newline at end of file
31 return []
@@ -1,72 +1,95 b''
1 """Latex transformer.
1 """Latex transformer.
2
2
3 Module that allows latex output notebooks to be conditioned before
3 Module that allows latex output notebooks to be conditioned before
4 they are converted.
4 they are converted.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
7 # Copyright (c) 2013, the IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 from __future__ import print_function
17 import re
18
19 #-----------------------------------------------------------------------------
20 # Globals and constants
21 #-----------------------------------------------------------------------------
22
23 #Latex substitutions for escaping latex.
24 LATEX_SUBS = (
25 (re.compile(r'\\'), r'\\textbackslash'),
26 (re.compile(r'([{}_#%&$])'), r'\\\1'),
27 (re.compile(r'~'), r'\~{}'),
28 (re.compile(r'\^'), r'\^{}'),
29 (re.compile(r'"'), r"''"),
30 (re.compile(r'\.\.\.+'), r'\\ldots'),
31 )
18
32
19 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
20 # Functions
34 # Functions
21 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
37 #TODO: Comment me.
38 def escape_tex(value):
39 newval = value
40 for pattern, replacement in LATEX_SUBS:
41 newval = pattern.sub(replacement, newval)
42 return newval
43
44
22 def rm_math_space(text):
45 def rm_math_space(text):
23 """
46 """
24 Remove the space between latex math commands and enclosing $ symbols.
47 Remove the space between latex math commands and enclosing $ symbols.
25 """
48 """
26
49
27 # First, scan through the markdown looking for $. If
50 # First, scan through the markdown looking for $. If
28 # a $ symbol is found, without a preceding \, assume
51 # a $ symbol is found, without a preceding \, assume
29 # it is the start of a math block. UNLESS that $ is
52 # it is the start of a math block. UNLESS that $ is
30 # not followed by another within two math_lines.
53 # not followed by another within two math_lines.
31 math_regions = []
54 math_regions = []
32 math_lines = 0
55 math_lines = 0
33 within_math = False
56 within_math = False
34 math_start_index = 0
57 math_start_index = 0
35 ptext = ''
58 ptext = ''
36 last_character = ""
59 last_character = ""
37 skip = False
60 skip = False
38 for index, char in enumerate(text):
61 for index, char in enumerate(text):
39
62
40 #Make sure the character isn't preceeded by a backslash
63 #Make sure the character isn't preceeded by a backslash
41 if (char == "$" and last_character != "\\"):
64 if (char == "$" and last_character != "\\"):
42
65
43 # Close the math region if this is an ending $
66 # Close the math region if this is an ending $
44 if within_math:
67 if within_math:
45 within_math = False
68 within_math = False
46 skip = True
69 skip = True
47 ptext = ptext+'$'+text[math_start_index+1:index].strip()+'$'
70 ptext = ptext+'$'+text[math_start_index+1:index].strip()+'$'
48 math_regions.append([math_start_index, index+1])
71 math_regions.append([math_start_index, index+1])
49 else:
72 else:
50
73
51 # Start a new math region
74 # Start a new math region
52 within_math = True
75 within_math = True
53 math_start_index = index
76 math_start_index = index
54 math_lines = 0
77 math_lines = 0
55
78
56 # If we are in a math region, count the number of lines parsed.
79 # If we are in a math region, count the number of lines parsed.
57 # Cancel the math region if we find two line breaks!
80 # Cancel the math region if we find two line breaks!
58 elif char == "\n":
81 elif char == "\n":
59 if within_math:
82 if within_math:
60 math_lines += 1
83 math_lines += 1
61 if math_lines > 1:
84 if math_lines > 1:
62 within_math = False
85 within_math = False
63 ptext = ptext+text[math_start_index:index]
86 ptext = ptext+text[math_start_index:index]
64
87
65 # Remember the last character so we can easily watch
88 # Remember the last character so we can easily watch
66 # for backslashes
89 # for backslashes
67 last_character = char
90 last_character = char
68 if not within_math and not skip:
91 if not within_math and not skip:
69 ptext = ptext+char
92 ptext = ptext+char
70 if skip:
93 if skip:
71 skip = False
94 skip = False
72 return ptext
95 return ptext
@@ -1,75 +1,77 b''
1 """Markdown utilities
1 """Markdown utilities
2
2
3 This file contains a collection of utility functions for dealing with
3 This file contains a collection of utility functions for dealing with
4 markdown.
4 markdown.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
7 # Copyright (c) 2013, the IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 from __future__ import print_function
17 from __future__ import print_function
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import sys
20 import subprocess
21 import subprocess
21
22
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23 # Functions
24 # Functions
24 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
25 # Pandoc-dependent code
27 # Pandoc-dependent code
26 def markdown2latex(src):
28 def markdown2latex(src):
27 """Convert a markdown string to LaTeX via pandoc.
29 """Convert a markdown string to LaTeX via pandoc.
28
30
29 This function will raise an error if pandoc is not installed.
31 This function will raise an error if pandoc is not installed.
30
32
31 Any error messages generated by pandoc are printed to stderr.
33 Any error messages generated by pandoc are printed to stderr.
32
34
33 Parameters
35 Parameters
34 ----------
36 ----------
35 src : string
37 src : string
36 Input string, assumed to be valid markdown.
38 Input string, assumed to be valid markdown.
37
39
38 Returns
40 Returns
39 -------
41 -------
40 out : string
42 out : string
41 Output as returned by pandoc.
43 Output as returned by pandoc.
42 """
44 """
43 p = subprocess.Popen('pandoc -f markdown -t latex'.split(),
45 p = subprocess.Popen('pandoc -f markdown -t latex'.split(),
44 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
46 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
45 out, err = p.communicate(src.encode('utf-8'))
47 out, err = p.communicate(src.encode('utf-8'))
46 if err:
48 if err:
47 print(err, file=sys.stderr)
49 print(err, file=sys.stderr)
48 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
50 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
49 return unicode(out, 'utf-8')
51 return unicode(out, 'utf-8')
50
52
51
53
52 def markdown2rst(src):
54 def markdown2rst(src):
53 """Convert a markdown string to LaTeX via pandoc.
55 """Convert a markdown string to LaTeX via pandoc.
54
56
55 This function will raise an error if pandoc is not installed.
57 This function will raise an error if pandoc is not installed.
56
58
57 Any error messages generated by pandoc are printed to stderr.
59 Any error messages generated by pandoc are printed to stderr.
58
60
59 Parameters
61 Parameters
60 ----------
62 ----------
61 src : string
63 src : string
62 Input string, assumed to be valid markdown.
64 Input string, assumed to be valid markdown.
63
65
64 Returns
66 Returns
65 -------
67 -------
66 out : string
68 out : string
67 Output as returned by pandoc.
69 Output as returned by pandoc.
68 """
70 """
69 p = subprocess.Popen('pandoc -f markdown -t rst'.split(),
71 p = subprocess.Popen('pandoc -f markdown -t rst'.split(),
70 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
72 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
71 out, err = p.communicate(src.encode('utf-8'))
73 out, err = p.communicate(src.encode('utf-8'))
72 if err:
74 if err:
73 print(err, file=sys.stderr)
75 print(err, file=sys.stderr)
74 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
76 #print('*'*20+'\n', out, '\n'+'*'*20) # dbg
75 return unicode(out, 'utf-8') No newline at end of file
77 return unicode(out, 'utf-8')
@@ -1,35 +1,57 b''
1 """String utilities.
1 """String utilities.
2
2
3 Contains a collection of usefull string manipulations functions.
3 Contains a collection of usefull string manipulations functions.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 # Our own imports
17 # Our own imports
18 import textwrap #TODO
18 import textwrap #TODO
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Functions
21 # Functions
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 def wrap(text, width=100):
23 def wrap(text, width=100):
24 """ Intelligently wrap text"""
24 """ Intelligently wrap text"""
25
25
26 splitt = text.split('\n')
26 splitt = text.split('\n')
27 wrp = map(lambda x:textwrap.wrap(x,width),splitt)
27 wrp = map(lambda x:textwrap.wrap(x,width),splitt)
28 wrpd = map('\n'.join, wrp)
28 wrpd = map('\n'.join, wrp)
29 return '\n'.join(wrpd)
29 return '\n'.join(wrpd)
30
30
31
31
32 def strip_dollars(text):
32 def strip_dollars(text):
33 """Remove all dollar symbols from text"""
33 """Remove all dollar symbols from text"""
34
34
35 return text.strip('$') No newline at end of file
35 return text.strip('$')
36
37
38 #TODO: Comment me.
39 def rm_fake(strng):
40 return strng.replace('/files/', '')
41
42
43 #TODO: Comment me.
44 def python_comment(string):
45 return '# '+'\n# '.join(string.split('\n'))
46
47 def get_lines(src, start=None,end=None):
48 """
49 Split the input text into separate lines and then return the
50 lines that the caller is interested in.
51 """
52
53 # Split the input into lines.
54 lines = src.split("\n")
55
56 # Return the right lines.
57 return "\n".join(lines[start:end]) #re-join
@@ -1,18 +1,19 b''
1
1 from transformers.base import ConfigurableTransformers
2
3
2 class ActivatableTransformer(ConfigurableTransformers):
4 class ActivatableTransformer(ConfigurableTransformers):
3 """A simple ConfigurableTransformers that have an enabled flag
5 """A simple ConfigurableTransformers that have an enabled flag
4
6
5 Inherit from that if you just want to have a transformer which is
7 Inherit from that if you just want to have a transformer which is
6 no-op by default but can be activated in profiles with
8 no-op by default but can be activated in profiles with
7
9
8 c.YourTransformerName.enabled = True
10 c.YourTransformerName.enabled = True
9 """
11 """
10
12
11 enabled = Bool(False, config=True)
13 enabled = Bool(False, config=True)
12
14
13 def __call__(self, nb, other):
15 def __call__(self, nb, other):
14 if not self.enabled :
16 if not self.enabled :
15 return nb, other
17 return nb, other
16 else :
18 else :
17 return super(ActivatableTransformer, self).__call__(nb, other)
19 return super(ActivatableTransformer, self).__call__(nb, other)
18
@@ -1,120 +1,121 b''
1 """
1 """
2 Module that regroups transformer that woudl be applied to ipynb files
2 Module that regroups transformer that woudl be applied to ipynb files
3 before going through the templating machinery.
3 before going through the templating machinery.
4
4
5 It exposes convenient classes to inherit from to access configurability
5 It exposes convenient classes to inherit from to access configurability
6 as well as decorator to simplify tasks.
6 as well as decorator to simplify tasks.
7 """
7 """
8
8
9 from __future__ import print_function, absolute_import
9 from __future__ import print_function, absolute_import
10
10
11 from IPython.config.configurable import Configurable
11 from IPython.config.configurable import Configurable
12 from IPython.utils.traitlets import Unicode, Bool, Dict, List
12 from IPython.utils.traitlets import Unicode, Bool, Dict, List
13
13
14 from .config import GlobalConfigurable
14 from .config import GlobalConfigurable
15
15
16 class ConfigurableTransformers(GlobalConfigurable):
16 class ConfigurableTransformers(GlobalConfigurable):
17 """ A configurable transformer
17 """ A configurable transformer
18
18
19 Inherit from this class if you wish to have configurability for your
19 Inherit from this class if you wish to have configurability for your
20 transformer.
20 transformer.
21
21
22 Any configurable traitlets this class exposed will be configurable in profiles
22 Any configurable traitlets this class exposed will be configurable in profiles
23 using c.SubClassName.atribute=value
23 using c.SubClassName.atribute=value
24
24
25 you can overwrite cell_transform to apply a transformation independently on each cell
25 you can overwrite cell_transform to apply a transformation independently on each cell
26 or __call__ if you prefer your own logic. See orresponding docstring for informations.
26 or __call__ if you prefer your own logic. See orresponding docstring for informations.
27
27
28
28
29 """
29 """
30
30
31 def __init__(self, config=None, **kw):
31 def __init__(self, config=None, **kw):
32 super(ConfigurableTransformers, self).__init__(config=config, **kw)
32 super(ConfigurableTransformers, self).__init__(config=config, **kw)
33
33
34 def __call__(self, nb, other):
34 def __call__(self, nb, other):
35 """transformation to apply on each notebook.
35 """transformation to apply on each notebook.
36
36
37 received a handle to the current notebook as well as a dict of resources
37 received a handle to the current notebook as well as a dict of resources
38 which structure depends on the transformer.
38 which structure depends on the transformer.
39
39
40 You should return modified nb, other.
40 You should return modified nb, other.
41
41
42 If you wish to apply on each cell, you might want to overwrite cell_transform method.
42 If you wish to apply on each cell, you might want to overwrite cell_transform method.
43 """
43 """
44 try :
44 try :
45 for worksheet in nb.worksheets :
45 for worksheet in nb.worksheets :
46 for index, cell in enumerate(worksheet.cells):
46 for index, cell in enumerate(worksheet.cells):
47 worksheet.cells[index], other = self.cell_transform(cell, other, 100*index)
47 worksheet.cells[index], other = self.cell_transform(cell, other, 100*index)
48 return nb, other
48 return nb, other
49 except NotImplementedError:
49 except NotImplementedError:
50 raise NotImplementedError('should be implemented by subclass')
50 raise NotImplementedError('should be implemented by subclass')
51
51
52 def cell_transform(self, cell, other, index):
52 def cell_transform(self, cell, other, index):
53 """
53 """
54 Overwrite if you want to apply a transformation on each cell,
54 Overwrite if you want to apply a transformation on each cell,
55
55
56 receive the current cell, the resource dict and the index of current cell as parameter.
56 receive the current cell, the resource dict and the index of current cell as parameter.
57
57
58 You should return modified cell and resource dict.
58 You should return modified cell and resource dict.
59 """
59 """
60
60 raise NotImplementedError('should be implemented by subclass')
61 raise NotImplementedError('should be implemented by subclass')
61 return cell, other
62 return cell, other
62
63
63 def cell_preprocessor(function):
64 def cell_preprocessor(function):
64 """ wrap a function to be executed on all cells of a notebook
65 """ wrap a function to be executed on all cells of a notebook
65
66
66 wrapped function parameters :
67 wrapped function parameters :
67 cell : the cell
68 cell : the cell
68 other : external resources
69 other : external resources
69 index : index of the cell
70 index : index of the cell
70 """
71 """
71 def wrappedfunc(nb, other):
72 def wrappedfunc(nb, other):
72 for worksheet in nb.worksheets :
73 for worksheet in nb.worksheets :
73 for index, cell in enumerate(worksheet.cells):
74 for index, cell in enumerate(worksheet.cells):
74 worksheet.cells[index], other = function(cell, other, index)
75 worksheet.cells[index], other = function(cell, other, index)
75 return nb, other
76 return nb, other
76 return wrappedfunc
77 return wrappedfunc
77
78
78
79
79 @cell_preprocessor
80 @cell_preprocessor
80 def haspyout_transformer(cell, other, count):
81 def haspyout_transformer(cell, other, count):
81 """
82 """
82 Add a haspyout flag to cell that have it
83 Add a haspyout flag to cell that have it
83
84
84 Easier for templating, where you can't know in advance
85 Easier for templating, where you can't know in advance
85 wether to write the out prompt
86 wether to write the out prompt
86
87
87 """
88 """
88 cell.type = cell.cell_type
89 cell.type = cell.cell_type
89 cell.haspyout = False
90 cell.haspyout = False
90 for out in cell.get('outputs', []):
91 for out in cell.get('outputs', []):
91 if out.output_type == 'pyout':
92 if out.output_type == 'pyout':
92 cell.haspyout = True
93 cell.haspyout = True
93 break
94 break
94 return cell, other
95 return cell, other
95
96
96 @cell_preprocessor
97 @cell_preprocessor
97 def coalesce_streams(cell, other, count):
98 def coalesce_streams(cell, other, count):
98 """merge consecutive sequences of stream output into single stream
99 """merge consecutive sequences of stream output into single stream
99
100
100 to prevent extra newlines inserted at flush calls
101 to prevent extra newlines inserted at flush calls
101
102
102 TODO: handle \r deletion
103 TODO: handle \r deletion
103 """
104 """
104 outputs = cell.get('outputs', [])
105 outputs = cell.get('outputs', [])
105 if not outputs:
106 if not outputs:
106 return cell, other
107 return cell, other
107 new_outputs = []
108 new_outputs = []
108 last = outputs[0]
109 last = outputs[0]
109 new_outputs = [last]
110 new_outputs = [last]
110 for output in outputs[1:]:
111 for output in outputs[1:]:
111 if (output.output_type == 'stream' and
112 if (output.output_type == 'stream' and
112 last.output_type == 'stream' and
113 last.output_type == 'stream' and
113 last.stream == output.stream
114 last.stream == output.stream
114 ):
115 ):
115 last.text += output.text
116 last.text += output.text
116 else:
117 else:
117 new_outputs.append(output)
118 new_outputs.append(output)
118
119
119 cell.outputs = new_outputs
120 cell.outputs = new_outputs
120 return cell, other
121 return cell, other
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
1 NO CONTENT: modified file chmod 100644 => 100755, file renamed from nbconvert/transformers/reavealhelp.py to nbconvert/transformers/revealhelp.py
NO CONTENT: modified file chmod 100644 => 100755, file renamed from nbconvert/transformers/reavealhelp.py to nbconvert/transformers/revealhelp.py
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
1 NO CONTENT: file renamed from nbconvert1/converters/lexers.py to nbconvert/utils/lexers.py
NO CONTENT: file renamed from nbconvert1/converters/lexers.py to nbconvert/utils/lexers.py
General Comments 0
You need to be logged in to leave comments. Login now