Show More
@@ -0,0 +1,104 | |||||
|
1 | """This preprocessor detect cells using a different language through | |||
|
2 | magic extensions such as `%%R` or `%%octave`. Cell's metadata is marked | |||
|
3 | so that the appropriate highlighter can be used in the `highlight` | |||
|
4 | filter. | |||
|
5 | """ | |||
|
6 | ||||
|
7 | #----------------------------------------------------------------------------- | |||
|
8 | # Copyright (c) 2013, the IPython Development Team. | |||
|
9 | # | |||
|
10 | # Distributed under the terms of the Modified BSD License. | |||
|
11 | # | |||
|
12 | # The full license is in the file COPYING.txt, distributed with this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
|
19 | from __future__ import print_function, absolute_import | |||
|
20 | ||||
|
21 | import re | |||
|
22 | ||||
|
23 | # Our own imports | |||
|
24 | # Needed to override preprocessor | |||
|
25 | from .base import (Preprocessor) | |||
|
26 | from IPython.utils.traitlets import Dict | |||
|
27 | ||||
|
28 | #----------------------------------------------------------------------------- | |||
|
29 | # Classes | |||
|
30 | #----------------------------------------------------------------------------- | |||
|
31 | ||||
|
32 | ||||
|
33 | class HighlightMagicsPreprocessor(Preprocessor): | |||
|
34 | """ | |||
|
35 | Detects and tags code cells that use a different languages than Python. | |||
|
36 | """ | |||
|
37 | ||||
|
38 | # list of magic language extensions and their associated pygment lexers | |||
|
39 | languages = Dict( | |||
|
40 | default_value={ | |||
|
41 | '%%R': 'r', | |||
|
42 | '%%bash': 'bash', | |||
|
43 | '%%octave': 'octave', | |||
|
44 | '%%perl': 'perl', | |||
|
45 | '%%ruby': 'ruby'}, | |||
|
46 | config=True, | |||
|
47 | help=("Syntax highlighting for magic's extension languages. " | |||
|
48 | "Each item associates a language magic extension such as %%R, " | |||
|
49 | "with a pygments lexer such as r.")) | |||
|
50 | ||||
|
51 | def __init__(self, config=None, **kw): | |||
|
52 | """Public constructor""" | |||
|
53 | ||||
|
54 | super(HighlightMagicsPreprocessor, self).__init__(config=config, **kw) | |||
|
55 | ||||
|
56 | # build a regular expression to catch language extensions and choose | |||
|
57 | # an adequate pygments lexer | |||
|
58 | any_language = "|".join(self.languages.keys()) | |||
|
59 | self.re_magic_language = re.compile( | |||
|
60 | r'^\s*({0})\s+'.format(any_language)) | |||
|
61 | ||||
|
62 | def which_magic_language(self, source): | |||
|
63 | """ | |||
|
64 | When a cell uses another language through a magic extension, | |||
|
65 | the other language is returned. | |||
|
66 | If no language magic is detected, this function returns None. | |||
|
67 | ||||
|
68 | Parameters | |||
|
69 | ---------- | |||
|
70 | source: str | |||
|
71 | Source code of the cell to highlight | |||
|
72 | """ | |||
|
73 | ||||
|
74 | m = self.re_magic_language.match(source) | |||
|
75 | ||||
|
76 | if m: | |||
|
77 | # By construction of the re, the matched language must be in the | |||
|
78 | # languages dictionnary | |||
|
79 | assert(m.group(1) in self.languages) | |||
|
80 | return self.languages[m.group(1)] | |||
|
81 | else: | |||
|
82 | return None | |||
|
83 | ||||
|
84 | def preprocess_cell(self, cell, resources, cell_index): | |||
|
85 | """ | |||
|
86 | Tags cells using a magic extension language | |||
|
87 | ||||
|
88 | Parameters | |||
|
89 | ---------- | |||
|
90 | cell : NotebookNode cell | |||
|
91 | Notebook cell being processed | |||
|
92 | resources : dictionary | |||
|
93 | Additional resources used in the conversion process. Allows | |||
|
94 | preprocessors to pass variables into the Jinja engine. | |||
|
95 | cell_index : int | |||
|
96 | Index of the cell being processed (see base.py) | |||
|
97 | """ | |||
|
98 | ||||
|
99 | # Only tag code cells | |||
|
100 | if hasattr(cell, "input") and cell.cell_type == "code": | |||
|
101 | magic_language = self.which_magic_language(cell.input) | |||
|
102 | if magic_language: | |||
|
103 | cell['metadata']['magics_language'] = magic_language | |||
|
104 | return cell, resources |
@@ -0,0 +1,68 | |||||
|
1 | """ | |||
|
2 | Module with tests for the HighlightMagics preprocessor | |||
|
3 | """ | |||
|
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 | from .base import PreprocessorTestsBase | |||
|
18 | from ..highlightmagics import HighlightMagicsPreprocessor | |||
|
19 | ||||
|
20 | ||||
|
21 | #----------------------------------------------------------------------------- | |||
|
22 | # Class | |||
|
23 | #----------------------------------------------------------------------------- | |||
|
24 | ||||
|
25 | class TestHighlightMagics(PreprocessorTestsBase): | |||
|
26 | """Contains test functions for highlightmagics.py""" | |||
|
27 | ||||
|
28 | ||||
|
29 | def build_preprocessor(self): | |||
|
30 | """Make an instance of a preprocessor""" | |||
|
31 | preprocessor = HighlightMagicsPreprocessor() | |||
|
32 | preprocessor.enabled = True | |||
|
33 | return preprocessor | |||
|
34 | ||||
|
35 | def test_constructor(self): | |||
|
36 | """Can a HighlightMagicsPreprocessor be constructed?""" | |||
|
37 | self.build_preprocessor() | |||
|
38 | ||||
|
39 | def test_tagging(self): | |||
|
40 | """Test the HighlightMagicsPreprocessor tagging""" | |||
|
41 | nb = self.build_notebook() | |||
|
42 | res = self.build_resources() | |||
|
43 | preprocessor = self.build_preprocessor() | |||
|
44 | nb.worksheets[0].cells[0].input = """%%R -i x,y -o XYcoef | |||
|
45 | lm.fit <- lm(y~x) | |||
|
46 | par(mfrow=c(2,2)) | |||
|
47 | print(summary(lm.fit)) | |||
|
48 | plot(lm.fit) | |||
|
49 | XYcoef <- coef(lm.fit)""" | |||
|
50 | ||||
|
51 | nb, res = preprocessor(nb, res) | |||
|
52 | ||||
|
53 | assert('magics_language' in nb.worksheets[0].cells[0]['metadata']) | |||
|
54 | ||||
|
55 | self.assertEqual(nb.worksheets[0].cells[0]['metadata']['magics_language'], 'r') | |||
|
56 | ||||
|
57 | def test_no_false_positive(self): | |||
|
58 | """Test that HighlightMagicsPreprocessor does not tag false positives""" | |||
|
59 | nb = self.build_notebook() | |||
|
60 | res = self.build_resources() | |||
|
61 | preprocessor = self.build_preprocessor() | |||
|
62 | nb.worksheets[0].cells[0].input = """# this should not be detected | |||
|
63 | print(\""" | |||
|
64 | %%R -i x, y | |||
|
65 | \""")""" | |||
|
66 | nb, res = preprocessor(nb, res) | |||
|
67 | ||||
|
68 | assert('magics_language' not in nb.worksheets[0].cells[0]['metadata']) No newline at end of file |
@@ -68,7 +68,8 class Exporter(LoggingConfigurable): | |||||
68 | nbpreprocessors.CSSHTMLHeaderPreprocessor, |
|
68 | nbpreprocessors.CSSHTMLHeaderPreprocessor, | |
69 | nbpreprocessors.RevealHelpPreprocessor, |
|
69 | nbpreprocessors.RevealHelpPreprocessor, | |
70 | nbpreprocessors.LatexPreprocessor, |
|
70 | nbpreprocessors.LatexPreprocessor, | |
71 |
nbpreprocessors.SphinxPreprocessor |
|
71 | nbpreprocessors.SphinxPreprocessor, | |
|
72 | nbpreprocessors.HighlightMagicsPreprocessor], | |||
72 | config=True, |
|
73 | config=True, | |
73 | help="""List of preprocessors available by default, by name, namespace, |
|
74 | help="""List of preprocessors available by default, by name, namespace, | |
74 | instance, or type.""") |
|
75 | instance, or type.""") |
@@ -46,7 +46,10 class HTMLExporter(TemplateExporter): | |||||
46 | c = Config({ |
|
46 | c = Config({ | |
47 | 'CSSHTMLHeaderPreprocessor':{ |
|
47 | 'CSSHTMLHeaderPreprocessor':{ | |
48 | 'enabled':True |
|
48 | 'enabled':True | |
49 |
} |
|
49 | }, | |
|
50 | 'HighlightMagicsPreprocessor': { | |||
|
51 | 'enabled':True | |||
|
52 | } | |||
50 | }) |
|
53 | }) | |
51 | c.merge(super(HTMLExporter,self).default_config) |
|
54 | c.merge(super(HTMLExporter,self).default_config) | |
52 | return c |
|
55 | return c |
@@ -85,6 +85,9 class LatexExporter(TemplateExporter): | |||||
85 | }, |
|
85 | }, | |
86 | 'SphinxPreprocessor': { |
|
86 | 'SphinxPreprocessor': { | |
87 | 'enabled':True |
|
87 | 'enabled':True | |
|
88 | }, | |||
|
89 | 'HighlightMagicsPreprocessor': { | |||
|
90 | 'enabled':True | |||
88 | } |
|
91 | } | |
89 | }) |
|
92 | }) | |
90 | c.merge(super(LatexExporter,self).default_config) |
|
93 | c.merge(super(LatexExporter,self).default_config) |
@@ -7,6 +7,7 from .revealhelp import RevealHelpPreprocessor | |||||
7 | from .latex import LatexPreprocessor |
|
7 | from .latex import LatexPreprocessor | |
8 | from .sphinx import SphinxPreprocessor |
|
8 | from .sphinx import SphinxPreprocessor | |
9 | from .csshtmlheader import CSSHTMLHeaderPreprocessor |
|
9 | from .csshtmlheader import CSSHTMLHeaderPreprocessor | |
|
10 | from .highlightmagics import HighlightMagicsPreprocessor | |||
10 |
|
11 | |||
11 | # decorated function Preprocessors |
|
12 | # decorated function Preprocessors | |
12 | from .coalescestreams import coalesce_streams |
|
13 | from .coalescestreams import coalesce_streams |
General Comments 0
You need to be logged in to leave comments.
Login now