##// END OF EJS Templates
Merge pull request #4403 from Carreau/global-high...
Min RK -
r13561:94a3c168 merge
parent child Browse files
Show More
@@ -1,312 +1,312 b''
1 """This module defines Exporter, a highly configurable converter
1 """This module defines Exporter, a highly configurable converter
2 that uses Jinja2 to export notebook files into different formats.
2 that uses Jinja2 to export notebook files into different formats.
3 """
3 """
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 from __future__ import print_function, absolute_import
17 from __future__ import print_function, absolute_import
18
18
19 # Stdlib imports
19 # Stdlib imports
20 import os
20 import os
21
21
22 # other libs/dependencies
22 # other libs/dependencies
23 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
23 from jinja2 import Environment, FileSystemLoader, ChoiceLoader, TemplateNotFound
24
24
25 # IPython imports
25 # IPython imports
26 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any
26 from IPython.utils.traitlets import MetaHasTraits, Unicode, List, Dict, Any
27 from IPython.utils.importstring import import_item
27 from IPython.utils.importstring import import_item
28 from IPython.utils import py3compat, text
28 from IPython.utils import py3compat, text
29
29
30 from IPython.nbconvert import filters
30 from IPython.nbconvert import filters
31 from .exporter import Exporter
31 from .exporter import Exporter
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Globals and constants
34 # Globals and constants
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 #Jinja2 extensions to load.
37 #Jinja2 extensions to load.
38 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
38 JINJA_EXTENSIONS = ['jinja2.ext.loopcontrols']
39
39
40 default_filters = {
40 default_filters = {
41 'indent': text.indent,
41 'indent': text.indent,
42 'markdown2html': filters.markdown2html,
42 'markdown2html': filters.markdown2html,
43 'ansi2html': filters.ansi2html,
43 'ansi2html': filters.ansi2html,
44 'filter_data_type': filters.DataTypeFilter,
44 'filter_data_type': filters.DataTypeFilter,
45 'get_lines': filters.get_lines,
45 'get_lines': filters.get_lines,
46 'highlight2html': filters.highlight2html,
46 'highlight2html': filters.Highlight2Html,
47 'highlight2latex': filters.highlight2latex,
47 'highlight2latex': filters.Highlight2Latex,
48 'ipython2python': filters.ipython2python,
48 'ipython2python': filters.ipython2python,
49 'posix_path': filters.posix_path,
49 'posix_path': filters.posix_path,
50 'markdown2latex': filters.markdown2latex,
50 'markdown2latex': filters.markdown2latex,
51 'markdown2rst': filters.markdown2rst,
51 'markdown2rst': filters.markdown2rst,
52 'comment_lines': filters.comment_lines,
52 'comment_lines': filters.comment_lines,
53 'strip_ansi': filters.strip_ansi,
53 'strip_ansi': filters.strip_ansi,
54 'strip_dollars': filters.strip_dollars,
54 'strip_dollars': filters.strip_dollars,
55 'strip_files_prefix': filters.strip_files_prefix,
55 'strip_files_prefix': filters.strip_files_prefix,
56 'html2text' : filters.html2text,
56 'html2text' : filters.html2text,
57 'add_anchor': filters.add_anchor,
57 'add_anchor': filters.add_anchor,
58 'ansi2latex': filters.ansi2latex,
58 'ansi2latex': filters.ansi2latex,
59 'wrap_text': filters.wrap_text,
59 'wrap_text': filters.wrap_text,
60 'escape_latex': filters.escape_latex,
60 'escape_latex': filters.escape_latex,
61 'citation2latex': filters.citation2latex,
61 'citation2latex': filters.citation2latex,
62 'path2url': filters.path2url,
62 'path2url': filters.path2url,
63 'add_prompts': filters.add_prompts,
63 'add_prompts': filters.add_prompts,
64 }
64 }
65
65
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67 # Class
67 # Class
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69
69
70 class TemplateExporter(Exporter):
70 class TemplateExporter(Exporter):
71 """
71 """
72 Exports notebooks into other file formats. Uses Jinja 2 templating engine
72 Exports notebooks into other file formats. Uses Jinja 2 templating engine
73 to output new formats. Inherit from this class if you are creating a new
73 to output new formats. Inherit from this class if you are creating a new
74 template type along with new filters/preprocessors. If the filters/
74 template type along with new filters/preprocessors. If the filters/
75 preprocessors provided by default suffice, there is no need to inherit from
75 preprocessors provided by default suffice, there is no need to inherit from
76 this class. Instead, override the template_file and file_extension
76 this class. Instead, override the template_file and file_extension
77 traits via a config file.
77 traits via a config file.
78
78
79 {filters}
79 {filters}
80 """
80 """
81
81
82 # finish the docstring
82 # finish the docstring
83 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
83 __doc__ = __doc__.format(filters = '- '+'\n - '.join(default_filters.keys()))
84
84
85
85
86 template_file = Unicode(u'default',
86 template_file = Unicode(u'default',
87 config=True,
87 config=True,
88 help="Name of the template file to use")
88 help="Name of the template file to use")
89 def _template_file_changed(self, name, old, new):
89 def _template_file_changed(self, name, old, new):
90 if new == 'default':
90 if new == 'default':
91 self.template_file = self.default_template
91 self.template_file = self.default_template
92 else:
92 else:
93 self.template_file = new
93 self.template_file = new
94 self.template = None
94 self.template = None
95 self._load_template()
95 self._load_template()
96
96
97 default_template = Unicode(u'')
97 default_template = Unicode(u'')
98 template = Any()
98 template = Any()
99 environment = Any()
99 environment = Any()
100
100
101 template_path = List(['.'], config=True)
101 template_path = List(['.'], config=True)
102 def _template_path_changed(self, name, old, new):
102 def _template_path_changed(self, name, old, new):
103 self._load_template()
103 self._load_template()
104
104
105 default_template_path = Unicode(
105 default_template_path = Unicode(
106 os.path.join("..", "templates"),
106 os.path.join("..", "templates"),
107 help="Path where the template files are located.")
107 help="Path where the template files are located.")
108
108
109 template_skeleton_path = Unicode(
109 template_skeleton_path = Unicode(
110 os.path.join("..", "templates", "skeleton"),
110 os.path.join("..", "templates", "skeleton"),
111 help="Path where the template skeleton files are located.")
111 help="Path where the template skeleton files are located.")
112
112
113 #Jinja block definitions
113 #Jinja block definitions
114 jinja_comment_block_start = Unicode("", config=True)
114 jinja_comment_block_start = Unicode("", config=True)
115 jinja_comment_block_end = Unicode("", config=True)
115 jinja_comment_block_end = Unicode("", config=True)
116 jinja_variable_block_start = Unicode("", config=True)
116 jinja_variable_block_start = Unicode("", config=True)
117 jinja_variable_block_end = Unicode("", config=True)
117 jinja_variable_block_end = Unicode("", config=True)
118 jinja_logic_block_start = Unicode("", config=True)
118 jinja_logic_block_start = Unicode("", config=True)
119 jinja_logic_block_end = Unicode("", config=True)
119 jinja_logic_block_end = Unicode("", config=True)
120
120
121 #Extension that the template files use.
121 #Extension that the template files use.
122 template_extension = Unicode(".tpl", config=True)
122 template_extension = Unicode(".tpl", config=True)
123
123
124 filters = Dict(config=True,
124 filters = Dict(config=True,
125 help="""Dictionary of filters, by name and namespace, to add to the Jinja
125 help="""Dictionary of filters, by name and namespace, to add to the Jinja
126 environment.""")
126 environment.""")
127
127
128
128
129 def __init__(self, config=None, extra_loaders=None, **kw):
129 def __init__(self, config=None, extra_loaders=None, **kw):
130 """
130 """
131 Public constructor
131 Public constructor
132
132
133 Parameters
133 Parameters
134 ----------
134 ----------
135 config : config
135 config : config
136 User configuration instance.
136 User configuration instance.
137 extra_loaders : list[of Jinja Loaders]
137 extra_loaders : list[of Jinja Loaders]
138 ordered list of Jinja loader to find templates. Will be tried in order
138 ordered list of Jinja loader to find templates. Will be tried in order
139 before the default FileSystem ones.
139 before the default FileSystem ones.
140 template : str (optional, kw arg)
140 template : str (optional, kw arg)
141 Template to use when exporting.
141 Template to use when exporting.
142 """
142 """
143 super(TemplateExporter, self).__init__(config=config, **kw)
143 super(TemplateExporter, self).__init__(config=config, **kw)
144
144
145 #Init
145 #Init
146 self._init_template()
146 self._init_template()
147 self._init_environment(extra_loaders=extra_loaders)
147 self._init_environment(extra_loaders=extra_loaders)
148 self._init_preprocessors()
148 self._init_preprocessors()
149 self._init_filters()
149 self._init_filters()
150
150
151
151
152 def _load_template(self):
152 def _load_template(self):
153 """Load the Jinja template object from the template file
153 """Load the Jinja template object from the template file
154
154
155 This is a no-op if the template attribute is already defined,
155 This is a no-op if the template attribute is already defined,
156 or the Jinja environment is not setup yet.
156 or the Jinja environment is not setup yet.
157
157
158 This is triggered by various trait changes that would change the template.
158 This is triggered by various trait changes that would change the template.
159 """
159 """
160 if self.template is not None:
160 if self.template is not None:
161 return
161 return
162 # called too early, do nothing
162 # called too early, do nothing
163 if self.environment is None:
163 if self.environment is None:
164 return
164 return
165 # Try different template names during conversion. First try to load the
165 # Try different template names during conversion. First try to load the
166 # template by name with extension added, then try loading the template
166 # template by name with extension added, then try loading the template
167 # as if the name is explicitly specified, then try the name as a
167 # as if the name is explicitly specified, then try the name as a
168 # 'flavor', and lastly just try to load the template by module name.
168 # 'flavor', and lastly just try to load the template by module name.
169 module_name = self.__module__.rsplit('.', 1)[-1]
169 module_name = self.__module__.rsplit('.', 1)[-1]
170 try_names = []
170 try_names = []
171 if self.template_file:
171 if self.template_file:
172 try_names.extend([
172 try_names.extend([
173 self.template_file + self.template_extension,
173 self.template_file + self.template_extension,
174 self.template_file,
174 self.template_file,
175 module_name + '_' + self.template_file + self.template_extension,
175 module_name + '_' + self.template_file + self.template_extension,
176 ])
176 ])
177 try_names.append(module_name + self.template_extension)
177 try_names.append(module_name + self.template_extension)
178 for try_name in try_names:
178 for try_name in try_names:
179 self.log.debug("Attempting to load template %s", try_name)
179 self.log.debug("Attempting to load template %s", try_name)
180 try:
180 try:
181 self.template = self.environment.get_template(try_name)
181 self.template = self.environment.get_template(try_name)
182 except (TemplateNotFound, IOError):
182 except (TemplateNotFound, IOError):
183 pass
183 pass
184 except Exception as e:
184 except Exception as e:
185 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
185 self.log.warn("Unexpected exception loading template: %s", try_name, exc_info=True)
186 else:
186 else:
187 self.log.info("Loaded template %s", try_name)
187 self.log.info("Loaded template %s", try_name)
188 break
188 break
189
189
190 def from_notebook_node(self, nb, resources=None, **kw):
190 def from_notebook_node(self, nb, resources=None, **kw):
191 """
191 """
192 Convert a notebook from a notebook node instance.
192 Convert a notebook from a notebook node instance.
193
193
194 Parameters
194 Parameters
195 ----------
195 ----------
196 nb : Notebook node
196 nb : Notebook node
197 resources : dict (**kw)
197 resources : dict (**kw)
198 of additional resources that can be accessed read/write by
198 of additional resources that can be accessed read/write by
199 preprocessors and filters.
199 preprocessors and filters.
200 """
200 """
201 nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
201 nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
202
202
203 self._load_template()
203 self._load_template()
204
204
205 if self.template is not None:
205 if self.template is not None:
206 output = self.template.render(nb=nb_copy, resources=resources)
206 output = self.template.render(nb=nb_copy, resources=resources)
207 else:
207 else:
208 raise IOError('template file "%s" could not be found' % self.template_file)
208 raise IOError('template file "%s" could not be found' % self.template_file)
209 return output, resources
209 return output, resources
210
210
211
211
212 def register_filter(self, name, jinja_filter):
212 def register_filter(self, name, jinja_filter):
213 """
213 """
214 Register a filter.
214 Register a filter.
215 A filter is a function that accepts and acts on one string.
215 A filter is a function that accepts and acts on one string.
216 The filters are accesible within the Jinja templating engine.
216 The filters are accesible within the Jinja templating engine.
217
217
218 Parameters
218 Parameters
219 ----------
219 ----------
220 name : str
220 name : str
221 name to give the filter in the Jinja engine
221 name to give the filter in the Jinja engine
222 filter : filter
222 filter : filter
223 """
223 """
224 if jinja_filter is None:
224 if jinja_filter is None:
225 raise TypeError('filter')
225 raise TypeError('filter')
226 isclass = isinstance(jinja_filter, type)
226 isclass = isinstance(jinja_filter, type)
227 constructed = not isclass
227 constructed = not isclass
228
228
229 #Handle filter's registration based on it's type
229 #Handle filter's registration based on it's type
230 if constructed and isinstance(jinja_filter, py3compat.string_types):
230 if constructed and isinstance(jinja_filter, py3compat.string_types):
231 #filter is a string, import the namespace and recursively call
231 #filter is a string, import the namespace and recursively call
232 #this register_filter method
232 #this register_filter method
233 filter_cls = import_item(jinja_filter)
233 filter_cls = import_item(jinja_filter)
234 return self.register_filter(name, filter_cls)
234 return self.register_filter(name, filter_cls)
235
235
236 if constructed and hasattr(jinja_filter, '__call__'):
236 if constructed and hasattr(jinja_filter, '__call__'):
237 #filter is a function, no need to construct it.
237 #filter is a function, no need to construct it.
238 self.environment.filters[name] = jinja_filter
238 self.environment.filters[name] = jinja_filter
239 return jinja_filter
239 return jinja_filter
240
240
241 elif isclass and isinstance(jinja_filter, MetaHasTraits):
241 elif isclass and isinstance(jinja_filter, MetaHasTraits):
242 #filter is configurable. Make sure to pass in new default for
242 #filter is configurable. Make sure to pass in new default for
243 #the enabled flag if one was specified.
243 #the enabled flag if one was specified.
244 filter_instance = jinja_filter(parent=self)
244 filter_instance = jinja_filter(parent=self)
245 self.register_filter(name, filter_instance )
245 self.register_filter(name, filter_instance )
246
246
247 elif isclass:
247 elif isclass:
248 #filter is not configurable, construct it
248 #filter is not configurable, construct it
249 filter_instance = jinja_filter()
249 filter_instance = jinja_filter()
250 self.register_filter(name, filter_instance)
250 self.register_filter(name, filter_instance)
251
251
252 else:
252 else:
253 #filter is an instance of something without a __call__
253 #filter is an instance of something without a __call__
254 #attribute.
254 #attribute.
255 raise TypeError('filter')
255 raise TypeError('filter')
256
256
257
257
258 def _init_template(self):
258 def _init_template(self):
259 """
259 """
260 Make sure a template name is specified. If one isn't specified, try to
260 Make sure a template name is specified. If one isn't specified, try to
261 build one from the information we know.
261 build one from the information we know.
262 """
262 """
263 self._template_file_changed('template_file', self.template_file, self.template_file)
263 self._template_file_changed('template_file', self.template_file, self.template_file)
264
264
265
265
266 def _init_environment(self, extra_loaders=None):
266 def _init_environment(self, extra_loaders=None):
267 """
267 """
268 Create the Jinja templating environment.
268 Create the Jinja templating environment.
269 """
269 """
270 here = os.path.dirname(os.path.realpath(__file__))
270 here = os.path.dirname(os.path.realpath(__file__))
271 loaders = []
271 loaders = []
272 if extra_loaders:
272 if extra_loaders:
273 loaders.extend(extra_loaders)
273 loaders.extend(extra_loaders)
274
274
275 paths = self.template_path
275 paths = self.template_path
276 paths.extend([os.path.join(here, self.default_template_path),
276 paths.extend([os.path.join(here, self.default_template_path),
277 os.path.join(here, self.template_skeleton_path)])
277 os.path.join(here, self.template_skeleton_path)])
278 loaders.append(FileSystemLoader(paths))
278 loaders.append(FileSystemLoader(paths))
279
279
280 self.environment = Environment(
280 self.environment = Environment(
281 loader= ChoiceLoader(loaders),
281 loader= ChoiceLoader(loaders),
282 extensions=JINJA_EXTENSIONS
282 extensions=JINJA_EXTENSIONS
283 )
283 )
284
284
285 #Set special Jinja2 syntax that will not conflict with latex.
285 #Set special Jinja2 syntax that will not conflict with latex.
286 if self.jinja_logic_block_start:
286 if self.jinja_logic_block_start:
287 self.environment.block_start_string = self.jinja_logic_block_start
287 self.environment.block_start_string = self.jinja_logic_block_start
288 if self.jinja_logic_block_end:
288 if self.jinja_logic_block_end:
289 self.environment.block_end_string = self.jinja_logic_block_end
289 self.environment.block_end_string = self.jinja_logic_block_end
290 if self.jinja_variable_block_start:
290 if self.jinja_variable_block_start:
291 self.environment.variable_start_string = self.jinja_variable_block_start
291 self.environment.variable_start_string = self.jinja_variable_block_start
292 if self.jinja_variable_block_end:
292 if self.jinja_variable_block_end:
293 self.environment.variable_end_string = self.jinja_variable_block_end
293 self.environment.variable_end_string = self.jinja_variable_block_end
294 if self.jinja_comment_block_start:
294 if self.jinja_comment_block_start:
295 self.environment.comment_start_string = self.jinja_comment_block_start
295 self.environment.comment_start_string = self.jinja_comment_block_start
296 if self.jinja_comment_block_end:
296 if self.jinja_comment_block_end:
297 self.environment.comment_end_string = self.jinja_comment_block_end
297 self.environment.comment_end_string = self.jinja_comment_block_end
298
298
299
299
300 def _init_filters(self):
300 def _init_filters(self):
301 """
301 """
302 Register all of the filters required for the exporter.
302 Register all of the filters required for the exporter.
303 """
303 """
304
304
305 #Add default filters to the Jinja2 environment
305 #Add default filters to the Jinja2 environment
306 for key, value in default_filters.items():
306 for key, value in default_filters.items():
307 self.register_filter(key, value)
307 self.register_filter(key, value)
308
308
309 #Load user filters. Overwrite existing filters if need be.
309 #Load user filters. Overwrite existing filters if need be.
310 if self.filters:
310 if self.filters:
311 for key, user_filter in self.filters.items():
311 for key, user_filter in self.filters.items():
312 self.register_filter(key, user_filter)
312 self.register_filter(key, user_filter)
@@ -1,110 +1,121 b''
1 """
1 """
2 Module containing filter functions that allow code to be highlighted
2 Module containing filter functions that allow code to be highlighted
3 from within Jinja templates.
3 from within Jinja templates.
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 from pygments import highlight as pygements_highlight
17 from pygments import highlight as pygements_highlight
18 from pygments.lexers import get_lexer_by_name
18 from pygments.lexers import get_lexer_by_name
19 from pygments.formatters import HtmlFormatter
19 from pygments.formatters import HtmlFormatter
20 from pygments.formatters import LatexFormatter
20 from pygments.formatters import LatexFormatter
21
21
22
22 # Our own imports
23 # Our own imports
23 from IPython.nbconvert.utils.lexers import IPythonLexer
24 from IPython.nbconvert.utils.lexers import IPythonLexer
25 from IPython.nbconvert.utils.base import NbConvertBase
24
26
25 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
26 # Globals and constants
28 # Globals and constants
27 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
28
30
29 MULTILINE_OUTPUTS = ['text', 'html', 'svg', 'latex', 'javascript', 'json']
31 MULTILINE_OUTPUTS = ['text', 'html', 'svg', 'latex', 'javascript', 'json']
30
32
31 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
32 # Utility functions
34 # Utility functions
33 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
34
36
35 __all__ = [
37 __all__ = [
36 'highlight2html',
38 'Highlight2Html',
37 'highlight2latex'
39 'Highlight2Latex'
38 ]
40 ]
39
41
40
42
41 def highlight2html(source, language='ipython', metadata=None):
43 class Highlight2Html(NbConvertBase):
42 """
44
43 Return a syntax-highlighted version of the input source as html output.
45 def __call__(self, source, language=None, metadata=None):
44
46 """
45 Parameters
47 Return a syntax-highlighted version of the input source as html output.
46 ----------
48
47 source : str
49 Parameters
48 source of the cell to highlight
50 ----------
49 language : str
51 source : str
50 language to highlight the syntax of
52 source of the cell to highlight
51 metadata : NotebookNode cell metadata
53 language : str
52 metadata of the cell to highlight
54 language to highlight the syntax of
53 """
55 metadata : NotebookNode cell metadata
54
56 metadata of the cell to highlight
55 return _pygment_highlight(source, HtmlFormatter(), language, metadata)
57 """
56
58 if not language:
57
59 language=self.default_language
58 def highlight2latex(source, language='ipython', metadata=None, strip_verbatim=False):
60
59 """
61 return _pygment_highlight(source, HtmlFormatter(), language, metadata)
60 Return a syntax-highlighted version of the input source as latex output.
62
61
63
62 Parameters
64 class Highlight2Latex(NbConvertBase):
63 ----------
65
64 source : str
66 def __call__(self, source, language=None, metadata=None, strip_verbatim=False):
65 source of the cell to highlight
67 """
66 language : str
68 Return a syntax-highlighted version of the input source as latex output.
67 language to highlight the syntax of
69
68 metadata : NotebookNode cell metadata
70 Parameters
69 metadata of the cell to highlight
71 ----------
70 strip_verbatim : bool
72 source : str
71 remove the Verbatim environment that pygments provides by default
73 source of the cell to highlight
72 """
74 language : str
73 latex = _pygment_highlight(source, LatexFormatter(), language, metadata)
75 language to highlight the syntax of
74 if strip_verbatim:
76 metadata : NotebookNode cell metadata
75 latex = latex.replace(r'\begin{Verbatim}[commandchars=\\\{\}]' + '\n', '')
77 metadata of the cell to highlight
76 return latex.replace('\n\\end{Verbatim}\n', '')
78 strip_verbatim : bool
77 else:
79 remove the Verbatim environment that pygments provides by default
78 return latex
80 """
81 if not language:
82 language=self.default_language
83
84 latex = _pygment_highlight(source, LatexFormatter(), language, metadata)
85 if strip_verbatim:
86 latex = latex.replace(r'\begin{Verbatim}[commandchars=\\\{\}]' + '\n', '')
87 return latex.replace('\n\\end{Verbatim}\n', '')
88 else:
89 return latex
79
90
80
91
81
92
82 def _pygment_highlight(source, output_formatter, language='ipython', metadata=None):
93 def _pygment_highlight(source, output_formatter, language='ipython', metadata=None):
83 """
94 """
84 Return a syntax-highlighted version of the input source
95 Return a syntax-highlighted version of the input source
85
96
86 Parameters
97 Parameters
87 ----------
98 ----------
88 source : str
99 source : str
89 source of the cell to highlight
100 source of the cell to highlight
90 output_formatter : Pygments formatter
101 output_formatter : Pygments formatter
91 language : str
102 language : str
92 language to highlight the syntax of
103 language to highlight the syntax of
93 metadata : NotebookNode cell metadata
104 metadata : NotebookNode cell metadata
94 metadata of the cell to highlight
105 metadata of the cell to highlight
95 """
106 """
96
107
97 # If the cell uses a magic extension language,
108 # If the cell uses a magic extension language,
98 # use the magic language instead.
109 # use the magic language instead.
99 if language == 'ipython' \
110 if language == 'ipython' \
100 and metadata \
111 and metadata \
101 and 'magics_language' in metadata:
112 and 'magics_language' in metadata:
102
113
103 language = metadata['magics_language']
114 language = metadata['magics_language']
104
115
105 if language == 'ipython':
116 if language == 'ipython':
106 lexer = IPythonLexer()
117 lexer = IPythonLexer()
107 else:
118 else:
108 lexer = get_lexer_by_name(language, stripall=True)
119 lexer = get_lexer_by_name(language, stripall=True)
109
120
110 return pygements_highlight(source, lexer, output_formatter)
121 return pygements_highlight(source, lexer, output_formatter)
@@ -1,65 +1,88 b''
1 """
1 """
2 Module with tests for Highlight
2 Module with tests for Highlight
3 """
3 """
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 from ...tests.base import TestsBase
17 from ...tests.base import TestsBase
18 from ..highlight import highlight2html, highlight2latex
18 from ..highlight import Highlight2Html, Highlight2Latex
19
19 from IPython.config import Config
20 import xml
20
21
21 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
22 # Class
23 # Class
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24
25
26 highlight2html = Highlight2Html()
27 highlight2latex = Highlight2Latex()
28 c = Config()
29 c.Highlight2Html.default_language='ruby'
30 highlight2html_ruby = Highlight2Html(config=c)
31
25 class TestHighlight(TestsBase):
32 class TestHighlight(TestsBase):
26 """Contains test functions for highlight.py"""
33 """Contains test functions for highlight.py"""
27
34
28 #Hello world test, magics test, blank string test
35 #Hello world test, magics test, blank string test
29 tests = [
36 tests = [
30 """
37 """
31 #Hello World Example
38 #Hello World Example
32
39
33 def say(text):
40 def say(text):
34 print(text)
41 print(text)
35
42
43 end
44
36 say('Hello World!')
45 say('Hello World!')
37 """,
46 """,
38 """
47 """
39 %%pylab
48 %%pylab
40 plot(x,y, 'r')
49 plot(x,y, 'r')
41 """
50 """
42 ]
51 ]
43
52
44 tokens = [
53 tokens = [
45 ['Hello World Example', 'say', 'text', 'print', 'def'],
54 ['Hello World Example', 'say', 'text', 'print', 'def'],
46 ['pylab', 'plot']]
55 ['pylab', 'plot']]
47
56
48
57
49 def test_highlight2html(self):
58 def test_highlight2html(self):
50 """highlight2html test"""
59 """highlight2html test"""
51 for index, test in enumerate(self.tests):
60 for index, test in enumerate(self.tests):
52 self._try_highlight(highlight2html, test, self.tokens[index])
61 self._try_highlight(highlight2html, test, self.tokens[index])
53
62
54
63
55 def test_highlight2latex(self):
64 def test_highlight2latex(self):
56 """highlight2latex test"""
65 """highlight2latex test"""
57 for index, test in enumerate(self.tests):
66 for index, test in enumerate(self.tests):
58 self._try_highlight(highlight2latex, test, self.tokens[index])
67 self._try_highlight(highlight2latex, test, self.tokens[index])
59
68
69 def test_parse_html_many_lang(self):
70
71 ht = highlight2html(self.tests[0])
72 rb = highlight2html_ruby(self.tests[0])
73
74 for lang,tkns in [
75 ( ht, ('def','print') ),
76 ( rb, ('def','end' ) )
77 ]:
78 root = xml.etree.ElementTree.fromstring(lang)
79 assert self._extract_tokens(root,'k') == set(tkns)
80
81 def _extract_tokens(self, root, cls):
82 return set(map(lambda x:x.text,root.findall(".//*[@class='"+cls+"']")))
60
83
61 def _try_highlight(self, method, test, tokens):
84 def _try_highlight(self, method, test, tokens):
62 """Try highlighting source, look for key tokens"""
85 """Try highlighting source, look for key tokens"""
63 results = method(test)
86 results = method(test)
64 for token in tokens:
87 for token in tokens:
65 assert token in results
88 assert token in results
@@ -1,37 +1,40 b''
1 """Global configuration class."""
1 """Global configuration class."""
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2013, the IPython Development Team.
3 # Copyright (c) 2013, the IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 from IPython.utils.traitlets import List
14 from IPython.utils.traitlets import List
15 from IPython.config.configurable import LoggingConfigurable
15 from IPython.config.configurable import LoggingConfigurable
16 from IPython.utils.traitlets import Unicode
16
17
17 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
18 # Classes and functions
19 # Classes and functions
19 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
20
21
21 class NbConvertBase(LoggingConfigurable):
22 class NbConvertBase(LoggingConfigurable):
22 """Global configurable class for shared config
23 """Global configurable class for shared config
23
24
24 Usefull for display data priority that might be use by many trasnformers
25 Usefull for display data priority that might be use by many trasnformers
25 """
26 """
26
27
27 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
28 display_data_priority = List(['html', 'pdf', 'svg', 'latex', 'png', 'jpg', 'jpeg' , 'text'],
28 config=True,
29 config=True,
29 help= """
30 help= """
30 An ordered list of prefered output type, the first
31 An ordered list of prefered output type, the first
31 encounterd will usually be used when converting discarding
32 encounterd will usually be used when converting discarding
32 the others.
33 the others.
33 """
34 """
34 )
35 )
35
36
37 default_language = Unicode('ipython', config=True, help='default highlight language')
38
36 def __init__(self, **kw):
39 def __init__(self, **kw):
37 super(NbConvertBase, self).__init__(**kw)
40 super(NbConvertBase, self).__init__(**kw)
General Comments 0
You need to be logged in to leave comments. Login now