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