##// END OF EJS Templates
Moved more code to Strings utilities file
Jonathan Frederic -
Show More
@@ -1,312 +1,306 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
26 import re
27
27
28 # IPython imports
28 # IPython imports
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.nbformat import current as nbformat
30 from IPython.nbformat import current as nbformat
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
31 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Bool
32 from IPython.utils.text import indent
32 from IPython.utils.text import indent
33
33
34 # other libs/dependencies
34 # other libs/dependencies
35 from jinja2 import Environment, FileSystemLoader
35 from jinja2 import Environment, FileSystemLoader
36 from markdown import markdown
36 from markdown import markdown
37
37
38 # local import (pre-transformers)
38 # local import (pre-transformers)
39 from exceptions import ConversionException
39 from exceptions import ConversionException
40 from . import transformers as trans #TODO
40 from . import transformers as trans #TODO
41 from .latex_transformer import (LatexTransformer) #TODO
41 from .latex_transformer import (LatexTransformer) #TODO
42 from .utils import markdown2rst #TODO
42 from .utils import markdown2rst #TODO
43 from .utils import markdown2latex #TODO
43 from .utils import markdown2latex #TODO
44 from .utils import highlight2latex #TODO
44 from .utils import highlight2latex #TODO
45 from .utils import get_lines #TODO
45 from .utils import get_lines #TODO
46 from .utils import remove_ansi #TODO
46 from .utils import remove_ansi #TODO
47 from .utils import highlight, ansi2html #TODO
47 from .utils import highlight, ansi2html #TODO
48 from .latex_transformer import rm_math_space #TODO
48 from .latex_transformer import rm_math_space #TODO
49 from .utils.strings import wrap as _wrap
49 import .utils.strings as strings
50
50
51 #Jinja2 filters
51 #Jinja2 filters
52 from .jinja_filters import (python_comment,
52 from .jinja_filters import (python_comment,
53 rm_fake,
53 rm_fake,
54 escape_tex, FilterDataType,
54 escape_tex, FilterDataType,
55 rm_dollars
55 rm_dollars
56 )
56 )
57
57
58 #Try to import the Sphinx exporter. If the user doesn't have Sphinx isntalled
58 #Try to import the Sphinx exporter. If the user doesn't have Sphinx isntalled
59 #on his/her machine, fail silently.
59 #on his/her machine, fail silently.
60 try:
60 try:
61 from .sphinx_transformer import (SphinxTransformer) #TODO
61 from .sphinx_transformer import (SphinxTransformer) #TODO
62 except ImportError:
62 except ImportError:
63 SphinxTransformer = None
63 SphinxTransformer = None
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Globals and constants
66 # Globals and constants
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68
68
69 #Standard Jinja2 environment constants
69 #Standard Jinja2 environment constants
70 TEMPLATE_PATH = "/../templates/"
70 TEMPLATE_PATH = "/../templates/"
71 TEMPLATE_SKELETON_PATH = "/../templates/skeleton/"
71 TEMPLATE_SKELETON_PATH = "/../templates/skeleton/"
72 TEMPLATE_EXTENSION = ".tpl"
72 TEMPLATE_EXTENSION = ".tpl"
73
73
74 #Latex Jinja2 constants
74 #Latex Jinja2 constants
75 LATEX_TEMPLATE_PATH = "/../templates/tex/"
75 LATEX_TEMPLATE_PATH = "/../templates/tex/"
76 LATEX_TEMPLATE_SKELETON_PATH = "/../templates/tex/skeleton/"
76 LATEX_TEMPLATE_SKELETON_PATH = "/../templates/tex/skeleton/"
77 LATEX_TEMPLATE_EXTENSION = ".tplx"
77 LATEX_TEMPLATE_EXTENSION = ".tplx"
78
78
79 #Special Jinja2 syntax that will not conflict when exporting latex.
79 #Special Jinja2 syntax that will not conflict when exporting latex.
80 LATEX_JINJA_COMMENT_BLOCK = ["((=", "=))"]
80 LATEX_JINJA_COMMENT_BLOCK = ["((=", "=))"]
81 LATEX_JINJA_VARIABLE_BLOCK = ["(((", ")))"]
81 LATEX_JINJA_VARIABLE_BLOCK = ["(((", ")))"]
82 LATEX_JINJA_LOGIC_BLOCK = ["((*", "*))"]
82 LATEX_JINJA_LOGIC_BLOCK = ["((*", "*))"]
83
83
84 #Jinja2 extensions to load.
84 #Jinja2 extensions to load.
85 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
85 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
86
86
87 #Latex substitutions for escaping latex.
87 #Latex substitutions for escaping latex.
88 LATEX_SUBS = (
88 LATEX_SUBS = (
89 (re.compile(r'\\'), r'\\textbackslash'),
89 (re.compile(r'\\'), r'\\textbackslash'),
90 (re.compile(r'([{}_#%&$])'), r'\\\1'),
90 (re.compile(r'([{}_#%&$])'), r'\\\1'),
91 (re.compile(r'~'), r'\~{}'),
91 (re.compile(r'~'), r'\~{}'),
92 (re.compile(r'\^'), r'\^{}'),
92 (re.compile(r'\^'), r'\^{}'),
93 (re.compile(r'"'), r"''"),
93 (re.compile(r'"'), r"''"),
94 (re.compile(r'\.\.\.+'), r'\\ldots'),
94 (re.compile(r'\.\.\.+'), r'\\ldots'),
95 )
95 )
96
96
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98 # Classes and functions
98 # Classes and functions
99 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
100 class Exporter(Configurable):
100 class Exporter(Configurable):
101 """ A Jinja2 base converter templates
101 """ A Jinja2 base converter templates
102
102
103 Preprocess the ipynb files, feed it throug jinja templates,
103 Preprocess the ipynb files, feed it throug jinja templates,
104 and spit an converted files and a data object with other data
104 and spit an converted files and a data object with other data
105 should be mostly configurable
105 should be mostly configurable
106 """
106 """
107
107
108 pre_transformer_order = List(['haspyout_transformer'],
108 pre_transformer_order = List(['haspyout_transformer'],
109 config=True,
109 config=True,
110 help= """
110 help= """
111 An ordered list of pre transformer to apply to the ipynb
111 An ordered list of pre transformer to apply to the ipynb
112 file before running through templates
112 file before running through templates
113 """
113 """
114 )
114 )
115
115
116 tex_environement = Bool(
116 tex_environement = Bool(
117 False,
117 False,
118 config=True,
118 config=True,
119 help=" Whether or not the user is exporting to latex.")
119 help=" Whether or not the user is exporting to latex.")
120
120
121 template_file = Unicode(
121 template_file = Unicode(
122 '', config=True,
122 '', config=True,
123 help="Name of the template file to use")
123 help="Name of the template file to use")
124
124
125 #Processors that process the input data prior to the export, set in the
125 #Processors that process the input data prior to the export, set in the
126 #constructor for this class.
126 #constructor for this class.
127 preprocessors = []
127 preprocessors = []
128
128
129 def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
129 def __init__(self, preprocessors={}, jinja_filters={}, config=None, **kw):
130 """ Init a new converter.
130 """ Init a new converter.
131
131
132 config: the Configurable config object to pass around.
132 config: the Configurable config object to pass around.
133
133
134 preprocessors: dict of **availlable** key/value function to run on
134 preprocessors: dict of **availlable** key/value function to run on
135 ipynb json data before conversion to extract/inline file.
135 ipynb json data before conversion to extract/inline file.
136 See `transformer.py` and `ConfigurableTransformers`
136 See `transformer.py` and `ConfigurableTransformers`
137
137
138 set the order in which the transformers should apply
138 set the order in which the transformers should apply
139 with the `pre_transformer_order` trait of this class
139 with the `pre_transformer_order` trait of this class
140
140
141 transformers registerd by this key will take precedence on
141 transformers registerd by this key will take precedence on
142 default one.
142 default one.
143
143
144 jinja_filters: dict of supplementary jinja filter that should be made
144 jinja_filters: dict of supplementary jinja filter that should be made
145 availlable in template. If those are of Configurable Class type,
145 availlable in template. If those are of Configurable Class type,
146 they will be instanciated with the config object as argument.
146 they will be instanciated with the config object as argument.
147
147
148 user defined filter will overwrite the one availlable by default.
148 user defined filter will overwrite the one availlable by default.
149 """
149 """
150 super(ConverterTemplate, self).__init__(config=config, **kw)
150 super(ConverterTemplate, self).__init__(config=config, **kw)
151
151
152 #Create a Latex environment if the user is exporting latex.
152 #Create a Latex environment if the user is exporting latex.
153 if self.tex_environement:
153 if self.tex_environement:
154 self.ext = LATEX_TEMPLATE_EXTENSION
154 self.ext = LATEX_TEMPLATE_EXTENSION
155 self.env = Environment(
155 self.env = Environment(
156 loader=FileSystemLoader([
156 loader=FileSystemLoader([
157 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_PATH,
157 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_PATH,
158 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_SKELETON_PATH,
158 os.path.dirname(os.path.realpath(__file__)) + LATEX_TEMPLATE_SKELETON_PATH,
159 ]),
159 ]),
160 extensions=JINJA_EXTENSIONS
160 extensions=JINJA_EXTENSIONS
161 )
161 )
162
162
163 #Set special Jinja2 syntax that will not conflict with latex.
163 #Set special Jinja2 syntax that will not conflict with latex.
164 self.env.block_start_string = LATEX_JINJA_LOGIC_BLOCK[0]
164 self.env.block_start_string = LATEX_JINJA_LOGIC_BLOCK[0]
165 self.env.block_end_string = LATEX_JINJA_LOGIC_BLOCK[1]
165 self.env.block_end_string = LATEX_JINJA_LOGIC_BLOCK[1]
166 self.env.variable_start_string = LATEX_JINJA_VARIABLE_BLOCK[0]
166 self.env.variable_start_string = LATEX_JINJA_VARIABLE_BLOCK[0]
167 self.env.variable_end_string = LATEX_JINJA_VARIABLE_BLOCK[1]
167 self.env.variable_end_string = LATEX_JINJA_VARIABLE_BLOCK[1]
168 self.env.comment_start_string = LATEX_JINJA_COMMENT_BLOCK[0]
168 self.env.comment_start_string = LATEX_JINJA_COMMENT_BLOCK[0]
169 self.env.comment_end_string = LATEX_JINJA_COMMENT_BLOCK[1]
169 self.env.comment_end_string = LATEX_JINJA_COMMENT_BLOCK[1]
170
170
171 else: #Standard environment
171 else: #Standard environment
172 self.ext = TEMPLATE_EXTENSION
172 self.ext = TEMPLATE_EXTENSION
173 self.env = Environment(
173 self.env = Environment(
174 loader=FileSystemLoader([
174 loader=FileSystemLoader([
175 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
175 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_PATH,
176 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
176 os.path.dirname(os.path.realpath(__file__)) + TEMPLATE_SKELETON_PATH,
177 ]),
177 ]),
178 extensions=JINJA_EXTENSIONS
178 extensions=JINJA_EXTENSIONS
179 )
179 )
180
180
181 for name in self.pre_transformer_order:
181 for name in self.pre_transformer_order:
182 # get the user-defined transformer first
182 # get the user-defined transformer first
183 transformer = preprocessors.get(name, getattr(trans, name, None))
183 transformer = preprocessors.get(name, getattr(trans, name, None))
184 if isinstance(transformer, MetaHasTraits):
184 if isinstance(transformer, MetaHasTraits):
185 transformer = transformer(config=config)
185 transformer = transformer(config=config)
186 self.preprocessors.append(transformer)
186 self.preprocessors.append(transformer)
187
187
188 #For compatibility, TODO: remove later.
188 #For compatibility, TODO: remove later.
189 self.preprocessors.append(trans.coalesce_streams)
189 self.preprocessors.append(trans.coalesce_streams)
190 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
190 self.preprocessors.append(trans.ExtractFigureTransformer(config=config))
191 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
191 self.preprocessors.append(trans.RevealHelpTransformer(config=config))
192 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
192 self.preprocessors.append(trans.CSSHtmlHeaderTransformer(config=config))
193 self.preprocessors.append(LatexTransformer(config=config))
193 self.preprocessors.append(LatexTransformer(config=config))
194
194
195 #Only load the sphinx transformer if the file reference worked
195 #Only load the sphinx transformer if the file reference worked
196 #(Sphinx dependencies exist on the user's machine.)
196 #(Sphinx dependencies exist on the user's machine.)
197 if SphinxTransformer:
197 if SphinxTransformer:
198 self.preprocessors.append(SphinxTransformer(config=config))
198 self.preprocessors.append(SphinxTransformer(config=config))
199
199
200 #Add filters to the Jinja2 environment
200 #Add filters to the Jinja2 environment
201 self.env.filters['filter_data_type'] = FilterDataType(config=config)
201 self.env.filters['filter_data_type'] = FilterDataType(config=config)
202 self.env.filters['pycomment'] = _python_comment
202 self.env.filters['pycomment'] = _python_comment
203 self.env.filters['indent'] = indent
203 self.env.filters['indent'] = indent
204 self.env.filters['rm_fake'] = _rm_fake
204 self.env.filters['rm_fake'] = _rm_fake
205 self.env.filters['rm_ansi'] = remove_ansi
205 self.env.filters['rm_ansi'] = remove_ansi
206 self.env.filters['markdown'] = markdown
206 self.env.filters['markdown'] = markdown
207 self.env.filters['ansi2html'] = ansi2html
207 self.env.filters['ansi2html'] = ansi2html
208 self.env.filters['markdown2latex'] = markdown2latex
208 self.env.filters['markdown2latex'] = markdown2latex
209 self.env.filters['markdown2rst'] = markdown2rst
209 self.env.filters['markdown2rst'] = markdown2rst
210 self.env.filters['get_lines'] = get_lines
210 self.env.filters['get_lines'] = get_lines
211 self.env.filters['wrap'] = _wrap
211 self.env.filters['wrap'] = strings.wrap
212 self.env.filters['rm_dollars'] = _rm_dollars
212 self.env.filters['rm_dollars'] = strings.strip_dollars
213 self.env.filters['rm_math_space'] = rm_math_space
213 self.env.filters['rm_math_space'] = rm_math_space
214 self.env.filters['highlight2html'] = highlight
214 self.env.filters['highlight2html'] = highlight
215 self.env.filters['highlight2latex'] = highlight2latex
215 self.env.filters['highlight2latex'] = highlight2latex
216
216
217 #Latex specific filters
217 #Latex specific filters
218 if self.tex_environement:
218 if self.tex_environement:
219 self.env.filters['escape_tex'] = _escape_tex
219 self.env.filters['escape_tex'] = _escape_tex
220 self.env.filters['highlight'] = highlight2latex
220 self.env.filters['highlight'] = highlight2latex
221 else:
221 else:
222 self.env.filters['highlight'] = highlight
222 self.env.filters['highlight'] = highlight
223
223
224 #Load user filters. Overwrite existing filters if need be.
224 #Load user filters. Overwrite existing filters if need be.
225 for key, user_filter in jinja_filters.iteritems():
225 for key, user_filter in jinja_filters.iteritems():
226 if isinstance(user_filter, MetaHasTraits):
226 if isinstance(user_filter, MetaHasTraits):
227 self.env.filters[key] = user_filter(config=config)
227 self.env.filters[key] = user_filter(config=config)
228 else:
228 else:
229 self.env.filters[key] = user_filter
229 self.env.filters[key] = user_filter
230
230
231 #Load the template file.
231 #Load the template file.
232 self.template = self.env.get_template(self.template_file+self.ext)
232 self.template = self.env.get_template(self.template_file+self.ext)
233
233
234
234
235 def export(self, nb):
235 def export(self, nb):
236 """Export notebook object
236 """Export notebook object
237
237
238 nb: Notebook object to export.
238 nb: Notebook object to export.
239
239
240 Returns both the converted ipynb file and a dict containing the
240 Returns both the converted ipynb file and a dict containing the
241 resources created along the way via the transformers and Jinja2
241 resources created along the way via the transformers and Jinja2
242 processing.
242 processing.
243 """
243 """
244
244
245 nb, resources = self._preprocess(nb)
245 nb, resources = self._preprocess(nb)
246 return self.template.render(nb=nb, resources=resources), resources
246 return self.template.render(nb=nb, resources=resources), resources
247
247
248
248
249 def from_filename(self, filename):
249 def from_filename(self, filename):
250 """Read and export a notebook from a filename
250 """Read and export a notebook from a filename
251
251
252 filename: Filename of the notebook file to export.
252 filename: Filename of the notebook file to export.
253
253
254 Returns both the converted ipynb file and a dict containing the
254 Returns both the converted ipynb file and a dict containing the
255 resources created along the way via the transformers and Jinja2
255 resources created along the way via the transformers and Jinja2
256 processing.
256 processing.
257 """
257 """
258 with io.open(filename) as f:
258 with io.open(filename) as f:
259 return self.export(nbformat.read(f, 'json'))
259 return self.export(nbformat.read(f, 'json'))
260
260
261
261
262 def from_file(self, file_stream):
262 def from_file(self, file_stream):
263 """Read and export a notebook from a filename
263 """Read and export a notebook from a filename
264
264
265 file_stream: File handle of file that contains notebook data.
265 file_stream: File handle of file that contains notebook data.
266
266
267 Returns both the converted ipynb file and a dict containing the
267 Returns both the converted ipynb file and a dict containing the
268 resources created along the way via the transformers and Jinja2
268 resources created along the way via the transformers and Jinja2
269 processing.
269 processing.
270 """
270 """
271
271
272 return self.export(nbformat.read(file_stream, 'json'))
272 return self.export(nbformat.read(file_stream, 'json'))
273
273
274
274
275 def _preprocess(self, nb):
275 def _preprocess(self, nb):
276 """ Preprocess the notebook using the transformers specific
276 """ Preprocess the notebook using the transformers specific
277 for the current export format.
277 for the current export format.
278
278
279 nb: Notebook to preprocess
279 nb: Notebook to preprocess
280 """
280 """
281
281
282 #Dict of 'resources' that can be filled by the preprocessors.
282 #Dict of 'resources' that can be filled by the preprocessors.
283 resources = {}
283 resources = {}
284
284
285 #Run each transformer on the notebook. Carry the output along
285 #Run each transformer on the notebook. Carry the output along
286 #to each transformer
286 #to each transformer
287 for transformer in self.preprocessors:
287 for transformer in self.preprocessors:
288 nb, resources = transformer(nb, resources)
288 nb, resources = transformer(nb, resources)
289 return nb, resources
289 return nb, resources
290
290
291
291
292 #TODO: Comment me.
292 #TODO: Comment me.
293 def _rm_fake(strng):
293 def _rm_fake(strng):
294 return strng.replace('/files/', '')
294 return strng.replace('/files/', '')
295
295
296
297 #TODO: Comment me.
298 def _rm_dollars(strng):
299 return strng.strip('$')
300
301
302 #TODO: Comment me.
296 #TODO: Comment me.
303 def _python_comment(string):
297 def _python_comment(string):
304 return '# '+'\n# '.join(string.split('\n'))
298 return '# '+'\n# '.join(string.split('\n'))
305
299
306
300
307 #TODO: Comment me.
301 #TODO: Comment me.
308 def _escape_tex(value):
302 def _escape_tex(value):
309 newval = value
303 newval = value
310 for pattern, replacement in LATEX_SUBS:
304 for pattern, replacement in LATEX_SUBS:
311 newval = pattern.sub(replacement, newval)
305 newval = pattern.sub(replacement, newval)
312 return newval No newline at end of file
306 return newval
@@ -1,29 +1,35 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 """ Try to detect and wrap paragraph"""
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) No newline at end of file
29 return '\n'.join(wrpd)
30
31
32 def strip_dollars(text):
33 """Remove all dollar symbols from text"""
34
35 return text.strip('$') No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now