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