##// END OF EJS Templates
Merge pull request #4505 from mrmagooey/nbconvert-latex-markdown-images2...
MinRK -
r13871:52b12218 merge
parent child Browse files
Show More
@@ -1,63 +1,63 b''
1 """Latex filters.
1 """Latex filters.
2
2
3 Module of useful filters for processing Latex within Jinja latex templates.
3 Module of useful filters for processing Latex within Jinja latex 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 import re
16 import re
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Globals and constants
19 # Globals and constants
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 LATEX_RE_SUBS = (
22 LATEX_RE_SUBS = (
23 (re.compile(r'\.\.\.+'), r'\\ldots'),
23 (re.compile(r'\.\.\.+'), r'\\ldots'),
24 )
24 )
25
25
26 # Latex substitutions for escaping latex.
26 # Latex substitutions for escaping latex.
27 # see: http://stackoverflow.com/questions/16259923/how-can-i-escape-latex-special-characters-inside-django-templates
27 # see: http://stackoverflow.com/questions/16259923/how-can-i-escape-latex-special-characters-inside-django-templates
28
28
29 LATEX_SUBS = {
29 LATEX_SUBS = {
30 '&': r'\&',
30 '&': r'\&',
31 '%': r'\%',
31 '%': r'\%',
32 '$': r'\$',
32 '$': r'\$',
33 '#': r'\#',
33 '#': r'\#',
34 '_': r'\_',
34 '_': r'\_',
35 '{': r'\{',
35 '{': r'\{',
36 '}': r'\}',
36 '}': r'\}',
37 '~': r'\textasciitilde{}',
37 '~': r'\textasciitilde{}',
38 '^': r'\^{}',
38 '^': r'\^{}',
39 '\\': r'\textbackslash{}',
39 '\\': r'\textbackslash{}',
40 }
40 }
41
41
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Functions
44 # Functions
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 __all__ = ['escape_latex']
47 __all__ = ['escape_latex']
48
48
49 def escape_latex(text):
49 def escape_latex(text):
50 """
50 """
51 Escape characters that may conflict with latex.
51 Escape characters that may conflict with latex.
52
52
53 Parameters
53 Parameters
54 ----------
54 ----------
55 text : str
55 text : str
56 Text containing characters that may conflict with Latex
56 Text containing characters that may conflict with Latex
57 """
57 """
58 text = ''.join(LATEX_SUBS.get(c, c) for c in text)
58 text = ''.join(LATEX_SUBS.get(c, c) for c in text)
59 for pattern, replacement in LATEX_RE_SUBS:
59 for pattern, replacement in LATEX_RE_SUBS:
60 text = pattern.sub(replacement, text)
60 text = pattern.sub(replacement, text)
61
61
62 return text
62 return text
63
63
@@ -1,204 +1,207 b''
1 # coding: utf-8
1 # coding: utf-8
2 """String filters.
2 """String filters.
3
3
4 Contains a collection of useful string manipulation filters for use in Jinja
4 Contains a collection of useful string manipulation filters for use in Jinja
5 templates.
5 templates.
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2013, the IPython Development Team.
8 # Copyright (c) 2013, the IPython Development Team.
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import os
19 import os
20 import re
20 import re
21 import textwrap
21 import textwrap
22 try:
22 try:
23 from urllib.parse import quote # Py 3
23 from urllib.parse import quote # Py 3
24 except ImportError:
24 except ImportError:
25 from urllib2 import quote # Py 2
25 from urllib2 import quote # Py 2
26 from xml.etree import ElementTree
26 from xml.etree import ElementTree
27
27
28 from IPython.core.interactiveshell import InteractiveShell
28 from IPython.core.interactiveshell import InteractiveShell
29 from IPython.utils import py3compat
29 from IPython.utils import py3compat
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Functions
32 # Functions
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 __all__ = [
35 __all__ = [
36 'wrap_text',
36 'wrap_text',
37 'html2text',
37 'html2text',
38 'add_anchor',
38 'add_anchor',
39 'strip_dollars',
39 'strip_dollars',
40 'strip_files_prefix',
40 'strip_files_prefix',
41 'comment_lines',
41 'comment_lines',
42 'get_lines',
42 'get_lines',
43 'ipython2python',
43 'ipython2python',
44 'posix_path',
44 'posix_path',
45 'path2url',
45 'path2url',
46 'add_prompts'
46 'add_prompts'
47 ]
47 ]
48
48
49
49
50 def wrap_text(text, width=100):
50 def wrap_text(text, width=100):
51 """
51 """
52 Intelligently wrap text.
52 Intelligently wrap text.
53 Wrap text without breaking words if possible.
53 Wrap text without breaking words if possible.
54
54
55 Parameters
55 Parameters
56 ----------
56 ----------
57 text : str
57 text : str
58 Text to wrap.
58 Text to wrap.
59 width : int, optional
59 width : int, optional
60 Number of characters to wrap to, default 100.
60 Number of characters to wrap to, default 100.
61 """
61 """
62
62
63 split_text = text.split('\n')
63 split_text = text.split('\n')
64 wrp = map(lambda x:textwrap.wrap(x,width), split_text)
64 wrp = map(lambda x:textwrap.wrap(x,width), split_text)
65 wrpd = map('\n'.join, wrp)
65 wrpd = map('\n'.join, wrp)
66 return '\n'.join(wrpd)
66 return '\n'.join(wrpd)
67
67
68
68
69 def html2text(element):
69 def html2text(element):
70 """extract inner text from html
70 """extract inner text from html
71
71
72 Analog of jQuery's $(element).text()
72 Analog of jQuery's $(element).text()
73 """
73 """
74 if isinstance(element, py3compat.string_types):
74 if isinstance(element, py3compat.string_types):
75 element = ElementTree.fromstring(element)
75 element = ElementTree.fromstring(element)
76
76
77 text = element.text or ""
77 text = element.text or ""
78 for child in element:
78 for child in element:
79 text += html2text(child)
79 text += html2text(child)
80 text += (element.tail or "")
80 text += (element.tail or "")
81 return text
81 return text
82
82
83
83
84 def add_anchor(html):
84 def add_anchor(html):
85 """Add an anchor-link to an html header tag
85 """Add an anchor-link to an html header tag
86
86
87 For use in heading cells
87 For use in heading cells
88 """
88 """
89 h = ElementTree.fromstring(py3compat.cast_bytes_py2(html, encoding='utf-8'))
89 h = ElementTree.fromstring(py3compat.cast_bytes_py2(html, encoding='utf-8'))
90 link = html2text(h).replace(' ', '-')
90 link = html2text(h).replace(' ', '-')
91 h.set('id', link)
91 h.set('id', link)
92 a = ElementTree.Element("a", {"class" : "anchor-link", "href" : "#" + link})
92 a = ElementTree.Element("a", {"class" : "anchor-link", "href" : "#" + link})
93 a.text = u'ΒΆ'
93 a.text = u'ΒΆ'
94 h.append(a)
94 h.append(a)
95
95
96 # Known issue of Python3.x, ElementTree.tostring() returns a byte string
96 # Known issue of Python3.x, ElementTree.tostring() returns a byte string
97 # instead of a text string. See issue http://bugs.python.org/issue10942
97 # instead of a text string. See issue http://bugs.python.org/issue10942
98 # Workaround is to make sure the bytes are casted to a string.
98 # Workaround is to make sure the bytes are casted to a string.
99 return py3compat.decode(ElementTree.tostring(h), 'utf-8')
99 return py3compat.decode(ElementTree.tostring(h), 'utf-8')
100
100
101
101
102 def add_prompts(code, first='>>> ', cont='... '):
102 def add_prompts(code, first='>>> ', cont='... '):
103 """Add prompts to code snippets"""
103 """Add prompts to code snippets"""
104 new_code = []
104 new_code = []
105 code_list = code.split('\n')
105 code_list = code.split('\n')
106 new_code.append(first + code_list[0])
106 new_code.append(first + code_list[0])
107 for line in code_list[1:]:
107 for line in code_list[1:]:
108 new_code.append(cont + line)
108 new_code.append(cont + line)
109 return '\n'.join(new_code)
109 return '\n'.join(new_code)
110
110
111
111
112 def strip_dollars(text):
112 def strip_dollars(text):
113 """
113 """
114 Remove all dollar symbols from text
114 Remove all dollar symbols from text
115
115
116 Parameters
116 Parameters
117 ----------
117 ----------
118 text : str
118 text : str
119 Text to remove dollars from
119 Text to remove dollars from
120 """
120 """
121
121
122 return text.strip('$')
122 return text.strip('$')
123
123
124
124
125 files_url_pattern = re.compile(r'(src|href)\=([\'"]?)files/')
125 files_url_pattern = re.compile(r'(src|href)\=([\'"]?)/?files/')
126 markdown_url_pattern = re.compile(r'(!?)\[(?P<caption>.*?)\]\(/?files/(?P<location>.*?)\)')
126
127
127 def strip_files_prefix(text):
128 def strip_files_prefix(text):
128 """
129 """
129 Fix all fake URLs that start with `files/`,
130 Fix all fake URLs that start with `files/`, stripping out the `files/` prefix.
130 stripping out the `files/` prefix.
131 Applies to both urls (for html) and relative paths (for markdown paths).
131
132
132 Parameters
133 Parameters
133 ----------
134 ----------
134 text : str
135 text : str
135 Text in which to replace 'src="files/real...' with 'src="real...'
136 Text in which to replace 'src="files/real...' with 'src="real...'
136 """
137 """
137 return files_url_pattern.sub(r"\1=\2", text)
138 cleaned_text = files_url_pattern.sub(r"\1=\2", text)
139 cleaned_text = markdown_url_pattern.sub(r'\1[\2](\3)', cleaned_text)
140 return cleaned_text
138
141
139
142
140 def comment_lines(text, prefix='# '):
143 def comment_lines(text, prefix='# '):
141 """
144 """
142 Build a Python comment line from input text.
145 Build a Python comment line from input text.
143
146
144 Parameters
147 Parameters
145 ----------
148 ----------
146 text : str
149 text : str
147 Text to comment out.
150 Text to comment out.
148 prefix : str
151 prefix : str
149 Character to append to the start of each line.
152 Character to append to the start of each line.
150 """
153 """
151
154
152 #Replace line breaks with line breaks and comment symbols.
155 #Replace line breaks with line breaks and comment symbols.
153 #Also add a comment symbol at the beginning to comment out
156 #Also add a comment symbol at the beginning to comment out
154 #the first line.
157 #the first line.
155 return prefix + ('\n'+prefix).join(text.split('\n'))
158 return prefix + ('\n'+prefix).join(text.split('\n'))
156
159
157
160
158 def get_lines(text, start=None,end=None):
161 def get_lines(text, start=None,end=None):
159 """
162 """
160 Split the input text into separate lines and then return the
163 Split the input text into separate lines and then return the
161 lines that the caller is interested in.
164 lines that the caller is interested in.
162
165
163 Parameters
166 Parameters
164 ----------
167 ----------
165 text : str
168 text : str
166 Text to parse lines from.
169 Text to parse lines from.
167 start : int, optional
170 start : int, optional
168 First line to grab from.
171 First line to grab from.
169 end : int, optional
172 end : int, optional
170 Last line to grab from.
173 Last line to grab from.
171 """
174 """
172
175
173 # Split the input into lines.
176 # Split the input into lines.
174 lines = text.split("\n")
177 lines = text.split("\n")
175
178
176 # Return the right lines.
179 # Return the right lines.
177 return "\n".join(lines[start:end]) #re-join
180 return "\n".join(lines[start:end]) #re-join
178
181
179 def ipython2python(code):
182 def ipython2python(code):
180 """Transform IPython syntax to pure Python syntax
183 """Transform IPython syntax to pure Python syntax
181
184
182 Parameters
185 Parameters
183 ----------
186 ----------
184
187
185 code : str
188 code : str
186 IPython code, to be transformed to pure Python
189 IPython code, to be transformed to pure Python
187 """
190 """
188 shell = InteractiveShell.instance()
191 shell = InteractiveShell.instance()
189 return shell.input_transformer_manager.transform_cell(code)
192 return shell.input_transformer_manager.transform_cell(code)
190
193
191 def posix_path(path):
194 def posix_path(path):
192 """Turn a path into posix-style path/to/etc
195 """Turn a path into posix-style path/to/etc
193
196
194 Mainly for use in latex on Windows,
197 Mainly for use in latex on Windows,
195 where native Windows paths are not allowed.
198 where native Windows paths are not allowed.
196 """
199 """
197 if os.path.sep != '/':
200 if os.path.sep != '/':
198 return path.replace(os.path.sep, '/')
201 return path.replace(os.path.sep, '/')
199 return path
202 return path
200
203
201 def path2url(path):
204 def path2url(path):
202 """Turn a file path into a URL"""
205 """Turn a file path into a URL"""
203 parts = path.split(os.path.sep)
206 parts = path.split(os.path.sep)
204 return '/'.join(quote(part) for part in parts)
207 return '/'.join(quote(part) for part in parts)
@@ -1,45 +1,43 b''
1 """
1 """
2 Module with tests for Latex
2 Module with tests for Latex
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 ..latex import escape_latex
18 from ..latex import escape_latex
19
19
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Class
22 # Class
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 class TestLatex(TestsBase):
25 class TestLatex(TestsBase):
26
26
27
27
28 def test_escape_latex(self):
28 def test_escape_latex(self):
29 """escape_latex test"""
29 """escape_latex test"""
30 tests = [
30 tests = [
31 (r'How are \you doing today?', r'How are \textbackslash{}you doing today?'),
31 (r'How are \you doing today?', r'How are \textbackslash{}you doing today?'),
32 (r'\escapechar=`\A\catcode`\|=0 |string|foo', r'\textbackslash{}escapechar=`\textbackslash{}A\textbackslash{}catcode`\textbackslash{}|=0 |string|foo'),
32 (r'\escapechar=`\A\catcode`\|=0 |string|foo', r'\textbackslash{}escapechar=`\textbackslash{}A\textbackslash{}catcode`\textbackslash{}|=0 |string|foo'),
33 (r'# $ % & ~ _ ^ \ { }', r'\# \$ \% \& \textasciitilde{} \_ \^{} \textbackslash{} \{ \}'),
33 (r'# $ % & ~ _ ^ \ { }', r'\# \$ \% \& \textasciitilde{} \_ \^{} \textbackslash{} \{ \}'),
34 ('...', r'\ldots'),
34 ('...', r'\ldots'),
35 ('','')]
35 ('','')]
36
36
37 for test in tests:
37 for test in tests:
38 self._try_escape_latex(test[0], test[1])
38 self._try_escape_latex(test[0], test[1])
39
39
40
40
41 def _try_escape_latex(self, test, result):
41 def _try_escape_latex(self, test, result):
42 """Try to remove latex from string"""
42 """Try to remove latex from string"""
43 self.assertEqual(escape_latex(test), result)
43 self.assertEqual(escape_latex(test), result)
44
45
@@ -1,135 +1,148 b''
1 """
1 """
2 Module with tests for Strings
2 Module with tests for Strings
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 import os
16 import os
17
17
18 from ...tests.base import TestsBase
18 from ...tests.base import TestsBase
19 from ..strings import (wrap_text, html2text, add_anchor, strip_dollars,
19 from ..strings import (wrap_text, html2text, add_anchor, strip_dollars,
20 strip_files_prefix, get_lines, comment_lines, ipython2python, posix_path,
20 strip_files_prefix, get_lines, comment_lines, ipython2python, posix_path,
21 add_prompts
21 add_prompts
22 )
22 )
23
23
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Class
26 # Class
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 class TestStrings(TestsBase):
29 class TestStrings(TestsBase):
30
30
31 def test_wrap_text(self):
31 def test_wrap_text(self):
32 """wrap_text test"""
32 """wrap_text test"""
33 test_text = """
33 test_text = """
34 Tush! never tell me; I take it much unkindly
34 Tush! never tell me; I take it much unkindly
35 That thou, Iago, who hast had my purse
35 That thou, Iago, who hast had my purse
36 As if the strings were thine, shouldst know of this.
36 As if the strings were thine, shouldst know of this.
37 """
37 """
38 for length in [30,5,1]:
38 for length in [30,5,1]:
39 self._confirm_wrap_text(test_text, length)
39 self._confirm_wrap_text(test_text, length)
40
40
41
41
42 def _confirm_wrap_text(self, text, length):
42 def _confirm_wrap_text(self, text, length):
43 for line in wrap_text(text, length).split('\n'):
43 for line in wrap_text(text, length).split('\n'):
44 assert len(line) <= length
44 assert len(line) <= length
45
45
46
46
47 def test_html2text(self):
47 def test_html2text(self):
48 """html2text test"""
48 """html2text test"""
49 #TODO: More tests
49 #TODO: More tests
50 self.assertEqual(html2text('<name>joe</name>'), 'joe')
50 self.assertEqual(html2text('<name>joe</name>'), 'joe')
51
51
52
52
53 def test_add_anchor(self):
53 def test_add_anchor(self):
54 """add_anchor test"""
54 """add_anchor test"""
55 #TODO: More tests
55 #TODO: More tests
56 results = add_anchor('<b>Hello World!</b>')
56 results = add_anchor('<b>Hello World!</b>')
57 assert 'Hello World!' in results
57 assert 'Hello World!' in results
58 assert 'id="' in results
58 assert 'id="' in results
59 assert 'class="anchor-link"' in results
59 assert 'class="anchor-link"' in results
60 assert '<b' in results
60 assert '<b' in results
61 assert '</b>' in results
61 assert '</b>' in results
62
62
63
63
64 def test_strip_dollars(self):
64 def test_strip_dollars(self):
65 """strip_dollars test"""
65 """strip_dollars test"""
66 tests = [
66 tests = [
67 ('', ''),
67 ('', ''),
68 ('$$', ''),
68 ('$$', ''),
69 ('$H$', 'H'),
69 ('$H$', 'H'),
70 ('$He', 'He'),
70 ('$He', 'He'),
71 ('H$el', 'H$el'),
71 ('H$el', 'H$el'),
72 ('Hell$', 'Hell'),
72 ('Hell$', 'Hell'),
73 ('Hello', 'Hello'),
73 ('Hello', 'Hello'),
74 ('W$o$rld', 'W$o$rld')]
74 ('W$o$rld', 'W$o$rld')]
75 for test in tests:
75 for test in tests:
76 self._try_strip_dollars(test[0], test[1])
76 self._try_strip_dollars(test[0], test[1])
77
77
78
78
79 def _try_strip_dollars(self, test, result):
79 def _try_strip_dollars(self, test, result):
80 self.assertEqual(strip_dollars(test), result)
80 self.assertEqual(strip_dollars(test), result)
81
81
82
82
83 def test_strip_files_prefix(self):
83 def test_strip_files_prefix(self):
84 """strip_files_prefix test"""
84 """strip_files_prefix test"""
85 tests = [
85 tests = [
86 ('', ''),
86 ('', ''),
87 ('/files', '/files'),
87 ('/files', '/files'),
88 ('test="/files"', 'test="/files"'),
88 ('test="/files"', 'test="/files"'),
89 ('My files are in `files/`', 'My files are in `files/`'),
89 ('My files are in `files/`', 'My files are in `files/`'),
90 ('<a href="files/test.html">files/test.html</a>', '<a href="test.html">files/test.html</a>')]
90 ('<a href="files/test.html">files/test.html</a>', '<a href="test.html">files/test.html</a>'),
91 ('<a href="/files/test.html">files/test.html</a>', '<a href="test.html">files/test.html</a>'),
92 ("<a href='files/test.html'>files/test.html</a>", "<a href='test.html'>files/test.html</a>"),
93 ('<img src="files/url/location.gif">', '<img src="url/location.gif">'),
94 ('<img src="/files/url/location.gif">', '<img src="url/location.gif">'),
95 ('hello![caption]', 'hello![caption]'),
96 ('hello![caption](/url/location.gif)', 'hello![caption](/url/location.gif)'),
97 ('hello![caption](url/location.gif)', 'hello![caption](url/location.gif)'),
98 ('hello![caption](url/location.gif)', 'hello![caption](url/location.gif)'),
99 ('hello![caption](files/url/location.gif)', 'hello![caption](url/location.gif)'),
100 ('hello![caption](/files/url/location.gif)', 'hello![caption](url/location.gif)'),
101 ('hello [text](/files/url/location.gif)', 'hello [text](url/location.gif)'),
102 ('hello [text space](files/url/location.gif)', 'hello [text space](url/location.gif)'),
103 ]
91 for test in tests:
104 for test in tests:
92 self._try_files_prefix(test[0], test[1])
105 self._try_files_prefix(test[0], test[1])
93
106
94
107
95 def _try_files_prefix(self, test, result):
108 def _try_files_prefix(self, test, result):
96 self.assertEqual(strip_files_prefix(test), result)
109 self.assertEqual(strip_files_prefix(test), result)
97
110
98
111
99 def test_comment_lines(self):
112 def test_comment_lines(self):
100 """comment_lines test"""
113 """comment_lines test"""
101 for line in comment_lines('hello\nworld\n!').split('\n'):
114 for line in comment_lines('hello\nworld\n!').split('\n'):
102 assert line.startswith('# ')
115 assert line.startswith('# ')
103 for line in comment_lines('hello\nworld\n!', 'beep').split('\n'):
116 for line in comment_lines('hello\nworld\n!', 'beep').split('\n'):
104 assert line.startswith('beep')
117 assert line.startswith('beep')
105
118
106
119
107 def test_get_lines(self):
120 def test_get_lines(self):
108 """get_lines test"""
121 """get_lines test"""
109 text = "hello\nworld\n!"
122 text = "hello\nworld\n!"
110 self.assertEqual(get_lines(text, start=1), "world\n!")
123 self.assertEqual(get_lines(text, start=1), "world\n!")
111 self.assertEqual(get_lines(text, end=2), "hello\nworld")
124 self.assertEqual(get_lines(text, end=2), "hello\nworld")
112 self.assertEqual(get_lines(text, start=2, end=5), "!")
125 self.assertEqual(get_lines(text, start=2, end=5), "!")
113 self.assertEqual(get_lines(text, start=-2), "world\n!")
126 self.assertEqual(get_lines(text, start=-2), "world\n!")
114
127
115
128
116 def test_ipython2python(self):
129 def test_ipython2python(self):
117 """ipython2python test"""
130 """ipython2python test"""
118 #TODO: More tests
131 #TODO: More tests
119 results = ipython2python(u'%%pylab\nprint("Hello-World")').replace("u'", "'")
132 results = ipython2python(u'%%pylab\nprint("Hello-World")').replace("u'", "'")
120 self.fuzzy_compare(results, u"get_ipython().run_cell_magic('pylab', '', 'print(\"Hello-World\")')",
133 self.fuzzy_compare(results, u"get_ipython().run_cell_magic('pylab', '', 'print(\"Hello-World\")')",
121 ignore_spaces=True, ignore_newlines=True)
134 ignore_spaces=True, ignore_newlines=True)
122
135
123 def test_posix_path(self):
136 def test_posix_path(self):
124 """posix_path test"""
137 """posix_path test"""
125 path_list = ['foo', 'bar']
138 path_list = ['foo', 'bar']
126 expected = '/'.join(path_list)
139 expected = '/'.join(path_list)
127 native = os.path.join(*path_list)
140 native = os.path.join(*path_list)
128 filtered = posix_path(native)
141 filtered = posix_path(native)
129 self.assertEqual(filtered, expected)
142 self.assertEqual(filtered, expected)
130
143
131 def test_add_prompts(self):
144 def test_add_prompts(self):
132 """add_prompts test"""
145 """add_prompts test"""
133 text1 = """for i in range(10):\n i += 1\n print i"""
146 text1 = """for i in range(10):\n i += 1\n print i"""
134 text2 = """>>> for i in range(10):\n... i += 1\n... print i"""
147 text2 = """>>> for i in range(10):\n... i += 1\n... print i"""
135 self.assertEqual(text2, add_prompts(text1))
148 self.assertEqual(text2, add_prompts(text1))
@@ -1,223 +1,223 b''
1 ((= Latex base template (must inherit)
1 ((= Latex base template (must inherit)
2 This template builds upon the abstract template, adding common latex output
2 This template builds upon the abstract template, adding common latex output
3 functions. Figures, data_text,
3 functions. Figures, data_text,
4 This template does not define a docclass, the inheriting class must define this.=))
4 This template does not define a docclass, the inheriting class must define this.=))
5
5
6 ((*- extends 'display_priority.tplx' -*))
6 ((*- extends 'display_priority.tplx' -*))
7
7
8 %===============================================================================
8 %===============================================================================
9 % Abstract overrides
9 % Abstract overrides
10 %===============================================================================
10 %===============================================================================
11
11
12 ((* block header *))
12 ((* block header *))
13 ((* block docclass *))((* endblock docclass *))
13 ((* block docclass *))((* endblock docclass *))
14
14
15 ((* block packages *))
15 ((* block packages *))
16 \usepackage{graphicx} % Used to insert images
16 \usepackage{graphicx} % Used to insert images
17 \usepackage{adjustbox} % Used to constrain images to a maximum size
17 \usepackage{adjustbox} % Used to constrain images to a maximum size
18 \usepackage{color} % Allow colors to be defined
18 \usepackage{color} % Allow colors to be defined
19 \usepackage{enumerate} % Needed for markdown enumerations to work
19 \usepackage{enumerate} % Needed for markdown enumerations to work
20 \usepackage{geometry} % Used to adjust the document margins
20 \usepackage{geometry} % Used to adjust the document margins
21 \usepackage{amsmath} % Equations
21 \usepackage{amsmath} % Equations
22 \usepackage{amssymb} % Equations
22 \usepackage{amssymb} % Equations
23 \usepackage[utf8]{inputenc} % Allow utf-8 characters in the tex document
23 \usepackage[utf8]{inputenc} % Allow utf-8 characters in the tex document
24 \usepackage[mathletters]{ucs} % Extended unicode (utf-8) support
24 \usepackage[mathletters]{ucs} % Extended unicode (utf-8) support
25 \usepackage{fancyvrb} % verbatim replacement that allows latex
25 \usepackage{fancyvrb} % verbatim replacement that allows latex
26 \usepackage{grffile} % extends the file name processing of package graphics
26 \usepackage{grffile} % extends the file name processing of package graphics
27 % to support a larger range
27 % to support a larger range
28 % The hyperref package gives us a pdf with properly built
28 % The hyperref package gives us a pdf with properly built
29 % internal navigation ('pdf bookmarks' for the table of contents,
29 % internal navigation ('pdf bookmarks' for the table of contents,
30 % internal cross-reference links, web links for URLs, etc.)
30 % internal cross-reference links, web links for URLs, etc.)
31 \usepackage{hyperref}
31 \usepackage{hyperref}
32 \usepackage{longtable} % longtable support required by pandoc >1.10
32 \usepackage{longtable} % longtable support required by pandoc >1.10
33 ((* endblock packages *))
33 ((* endblock packages *))
34
34
35 ((* block definitions *))
35 ((* block definitions *))
36 \definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
36 \definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
37 \definecolor{darkorange}{rgb}{.71,0.21,0.01}
37 \definecolor{darkorange}{rgb}{.71,0.21,0.01}
38 \definecolor{darkgreen}{rgb}{.12,.54,.11}
38 \definecolor{darkgreen}{rgb}{.12,.54,.11}
39 \definecolor{myteal}{rgb}{.26, .44, .56}
39 \definecolor{myteal}{rgb}{.26, .44, .56}
40 \definecolor{gray}{gray}{0.45}
40 \definecolor{gray}{gray}{0.45}
41 \definecolor{lightgray}{gray}{.95}
41 \definecolor{lightgray}{gray}{.95}
42 \definecolor{mediumgray}{gray}{.8}
42 \definecolor{mediumgray}{gray}{.8}
43 \definecolor{inputbackground}{rgb}{.95, .95, .85}
43 \definecolor{inputbackground}{rgb}{.95, .95, .85}
44 \definecolor{outputbackground}{rgb}{.95, .95, .95}
44 \definecolor{outputbackground}{rgb}{.95, .95, .95}
45 \definecolor{traceback}{rgb}{1, .95, .95}
45 \definecolor{traceback}{rgb}{1, .95, .95}
46 % ansi colors
46 % ansi colors
47 \definecolor{red}{rgb}{.6,0,0}
47 \definecolor{red}{rgb}{.6,0,0}
48 \definecolor{green}{rgb}{0,.65,0}
48 \definecolor{green}{rgb}{0,.65,0}
49 \definecolor{brown}{rgb}{0.6,0.6,0}
49 \definecolor{brown}{rgb}{0.6,0.6,0}
50 \definecolor{blue}{rgb}{0,.145,.698}
50 \definecolor{blue}{rgb}{0,.145,.698}
51 \definecolor{purple}{rgb}{.698,.145,.698}
51 \definecolor{purple}{rgb}{.698,.145,.698}
52 \definecolor{cyan}{rgb}{0,.698,.698}
52 \definecolor{cyan}{rgb}{0,.698,.698}
53 \definecolor{lightgray}{gray}{0.5}
53 \definecolor{lightgray}{gray}{0.5}
54
54
55 % bright ansi colors
55 % bright ansi colors
56 \definecolor{darkgray}{gray}{0.25}
56 \definecolor{darkgray}{gray}{0.25}
57 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
57 \definecolor{lightred}{rgb}{1.0,0.39,0.28}
58 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
58 \definecolor{lightgreen}{rgb}{0.48,0.99,0.0}
59 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
59 \definecolor{lightblue}{rgb}{0.53,0.81,0.92}
60 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
60 \definecolor{lightpurple}{rgb}{0.87,0.63,0.87}
61 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
61 \definecolor{lightcyan}{rgb}{0.5,1.0,0.83}
62
62
63 % commands and environments needed by pandoc snippets
63 % commands and environments needed by pandoc snippets
64 % extracted from the output of `pandoc -s`
64 % extracted from the output of `pandoc -s`
65
65
66 \DefineShortVerb[commandchars=\\\{\}]{\|}
66 \DefineShortVerb[commandchars=\\\{\}]{\|}
67 \DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
67 \DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
68 % Add ',fontsize=\small' for more characters per line
68 % Add ',fontsize=\small' for more characters per line
69 \newenvironment{Shaded}{}{}
69 \newenvironment{Shaded}{}{}
70 \newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}}
70 \newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}}
71 \newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{{#1}}}
71 \newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{{#1}}}
72 \newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
72 \newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
73 \newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
73 \newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
74 \newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
74 \newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
75 \newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
75 \newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
76 \newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
76 \newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
77 \newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}}
77 \newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}}
78 \newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}}
78 \newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}}
79 \newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
79 \newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
80 \newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}}
80 \newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}}
81 \newcommand{\RegionMarkerTok}[1]{{#1}}
81 \newcommand{\RegionMarkerTok}[1]{{#1}}
82 \newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
82 \newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
83 \newcommand{\NormalTok}[1]{{#1}}
83 \newcommand{\NormalTok}[1]{{#1}}
84
84
85 % Define a nice break command that doesn't care if a line doesn't already
85 % Define a nice break command that doesn't care if a line doesn't already
86 % exist.
86 % exist.
87 \def\br{\hspace*{\fill} \\* }
87 \def\br{\hspace*{\fill} \\* }
88 % Math Jax compatability definitions
88 % Math Jax compatability definitions
89 \def\gt{>}
89 \def\gt{>}
90 \def\lt{<}
90 \def\lt{<}
91 % Document parameters
91 % Document parameters
92 ((* block title *))\title{((( resources.metadata.name | escape_latex )))}((* endblock title *))
92 ((* block title *))\title{((( resources.metadata.name | escape_latex )))}((* endblock title *))
93 ((* block date *))((* endblock date *))
93 ((* block date *))((* endblock date *))
94 ((* block author *))((* endblock author *))
94 ((* block author *))((* endblock author *))
95 ((* endblock definitions *))
95 ((* endblock definitions *))
96
96
97 ((* block commands *))
97 ((* block commands *))
98 % Prevent overflowing lines due to hard-to-break entities
98 % Prevent overflowing lines due to hard-to-break entities
99 \sloppy
99 \sloppy
100 % Setup hyperref package
100 % Setup hyperref package
101 \hypersetup{
101 \hypersetup{
102 breaklinks=true, % so long urls are correctly broken across lines
102 breaklinks=true, % so long urls are correctly broken across lines
103 colorlinks=true,
103 colorlinks=true,
104 urlcolor=blue,
104 urlcolor=blue,
105 linkcolor=darkorange,
105 linkcolor=darkorange,
106 citecolor=darkgreen,
106 citecolor=darkgreen,
107 }
107 }
108 % Slightly bigger margins than the latex defaults
108 % Slightly bigger margins than the latex defaults
109 ((* block margins *))
109 ((* block margins *))
110 \geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
110 \geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}
111 ((* endblock margins *))
111 ((* endblock margins *))
112 ((* endblock commands *))
112 ((* endblock commands *))
113 ((* endblock header *))
113 ((* endblock header *))
114
114
115 ((* block body *))
115 ((* block body *))
116 \begin{document}
116 \begin{document}
117
117
118 ((* block predoc *))
118 ((* block predoc *))
119 ((* block maketitle *))\maketitle((* endblock maketitle *))
119 ((* block maketitle *))\maketitle((* endblock maketitle *))
120 ((* block abstract *))((* endblock abstract *))
120 ((* block abstract *))((* endblock abstract *))
121 ((* endblock predoc *))
121 ((* endblock predoc *))
122
122
123 ((( super() )))
123 ((( super() )))
124
124
125 % Add a bibliography block to the postdoc
125 % Add a bibliography block to the postdoc
126 ((* block postdoc *))
126 ((* block postdoc *))
127 ((* block bibliography *))((* endblock bibliography *))
127 ((* block bibliography *))((* endblock bibliography *))
128 ((* endblock postdoc *))
128 ((* endblock postdoc *))
129 \end{document}
129 \end{document}
130 ((* endblock body *))
130 ((* endblock body *))
131
131
132 %===============================================================================
132 %===============================================================================
133 % Support blocks
133 % Support blocks
134 %===============================================================================
134 %===============================================================================
135
135
136 % Displaying simple data text
136 % Displaying simple data text
137 ((* block data_text *))
137 ((* block data_text *))
138 \begin{verbatim}
138 \begin{verbatim}
139 ((( output.text )))
139 ((( output.text )))
140 \end{verbatim}
140 \end{verbatim}
141 ((* endblock data_text *))
141 ((* endblock data_text *))
142
142
143 % Display python error text as-is
143 % Display python error text as-is
144 ((* block pyerr *))
144 ((* block pyerr *))
145 \begin{Verbatim}[commandchars=\\\{\}]
145 \begin{Verbatim}[commandchars=\\\{\}]
146 ((( super() )))
146 ((( super() )))
147 \end{Verbatim}
147 \end{Verbatim}
148 ((* endblock pyerr *))
148 ((* endblock pyerr *))
149 ((* block traceback_line *))
149 ((* block traceback_line *))
150 ((( line | indent | strip_ansi | escape_latex )))
150 ((( line | indent | strip_ansi | escape_latex )))
151 ((* endblock traceback_line *))
151 ((* endblock traceback_line *))
152
152
153 % Display stream ouput with coloring
153 % Display stream ouput with coloring
154 ((* block stream *))
154 ((* block stream *))
155 \begin{Verbatim}[commandchars=\\\{\}]
155 \begin{Verbatim}[commandchars=\\\{\}]
156 ((( output.text | escape_latex | ansi2latex )))
156 ((( output.text | escape_latex | ansi2latex )))
157 \end{Verbatim}
157 \end{Verbatim}
158 ((* endblock stream *))
158 ((* endblock stream *))
159
159
160 % Display latex
160 % Display latex
161 ((* block data_latex -*))
161 ((* block data_latex -*))
162 ((*- if output.latex.startswith('$'): -*))
162 ((*- if output.latex.startswith('$'): -*))
163 ((= Replace $ symbols with more explicit, equation block. =))
163 ((= Replace $ symbols with more explicit, equation block. =))
164 \begin{equation*}
164 \begin{equation*}
165 ((( output.latex | strip_dollars )))
165 ((( output.latex | strip_dollars )))
166 \end{equation*}
166 \end{equation*}
167 ((*- else -*))
167 ((*- else -*))
168 ((( output.latex )))
168 ((( output.latex )))
169 ((*- endif *))
169 ((*- endif *))
170 ((* endblock data_latex *))
170 ((* endblock data_latex *))
171
171
172 % Default mechanism for rendering figures
172 % Default mechanism for rendering figures
173 ((*- block data_png -*))((( draw_figure(output.png_filename) )))((*- endblock -*))
173 ((*- block data_png -*))((( draw_figure(output.png_filename) )))((*- endblock -*))
174 ((*- block data_jpg -*))((( draw_figure(output.jpeg_filename) )))((*- endblock -*))
174 ((*- block data_jpg -*))((( draw_figure(output.jpeg_filename) )))((*- endblock -*))
175 ((*- block data_svg -*))((( draw_figure(output.svg_filename) )))((*- endblock -*))
175 ((*- block data_svg -*))((( draw_figure(output.svg_filename) )))((*- endblock -*))
176 ((*- block data_pdf -*))((( draw_figure(output.pdf_filename) )))((*- endblock -*))
176 ((*- block data_pdf -*))((( draw_figure(output.pdf_filename) )))((*- endblock -*))
177
177
178 % Draw a figure using the graphicx package.
178 % Draw a figure using the graphicx package.
179 ((* macro draw_figure(filename) -*))
179 ((* macro draw_figure(filename) -*))
180 ((* set filename = filename | posix_path *))
180 ((* set filename = filename | posix_path *))
181 ((*- block figure scoped -*))
181 ((*- block figure scoped -*))
182 \begin{center}
182 \begin{center}
183 \adjustimage{max size={0.9\linewidth}{0.9\paperheight}}{((( filename )))}
183 \adjustimage{max size={0.9\linewidth}{0.9\paperheight}}{((( filename )))}
184 \end{center}
184 \end{center}
185 { \hspace*{\fill} \\}
185 { \hspace*{\fill} \\}
186 ((*- endblock figure -*))
186 ((*- endblock figure -*))
187 ((*- endmacro *))
187 ((*- endmacro *))
188
188
189 % Draw heading cell. Explicitly map different cell levels.
189 % Draw heading cell. Explicitly map different cell levels.
190 ((* block headingcell scoped *))
190 ((* block headingcell scoped *))
191
191
192 ((* if cell.level == 1 -*))
192 ((* if cell.level == 1 -*))
193 ((* block h1 -*))\section((* endblock h1 -*))
193 ((* block h1 -*))\section((* endblock h1 -*))
194 ((* elif cell.level == 2 -*))
194 ((* elif cell.level == 2 -*))
195 ((* block h2 -*))\subsection((* endblock h2 -*))
195 ((* block h2 -*))\subsection((* endblock h2 -*))
196 ((* elif cell.level == 3 -*))
196 ((* elif cell.level == 3 -*))
197 ((* block h3 -*))\subsubsection((* endblock h3 -*))
197 ((* block h3 -*))\subsubsection((* endblock h3 -*))
198 ((* elif cell.level == 4 -*))
198 ((* elif cell.level == 4 -*))
199 ((* block h4 -*))\paragraph((* endblock h4 -*))
199 ((* block h4 -*))\paragraph((* endblock h4 -*))
200 ((* elif cell.level == 5 -*))
200 ((* elif cell.level == 5 -*))
201 ((* block h5 -*))\subparagraph((* endblock h5 -*))
201 ((* block h5 -*))\subparagraph((* endblock h5 -*))
202 ((* elif cell.level == 6 -*))
202 ((* elif cell.level == 6 -*))
203 ((* block h6 -*))\\*\textit((* endblock h6 -*))
203 ((* block h6 -*))\\*\textit((* endblock h6 -*))
204 ((*- endif -*))
204 ((*- endif -*))
205 {((( cell.source | replace('\n', ' ') | citation2latex | markdown2latex )))}
205 {((( cell.source | replace('\n', ' ') | citation2latex | strip_files_prefix | markdown2latex )))}
206
206
207 ((* endblock headingcell *))
207 ((* endblock headingcell *))
208
208
209 % Redirect pyout to display data priority.
209 % Redirect pyout to display data priority.
210 ((* block pyout scoped *))
210 ((* block pyout scoped *))
211 ((* block data_priority scoped *))
211 ((* block data_priority scoped *))
212 ((( super() )))
212 ((( super() )))
213 ((* endblock *))
213 ((* endblock *))
214 ((* endblock pyout *))
214 ((* endblock pyout *))
215
215
216 % Render markdown
216 % Render markdown
217 ((* block markdowncell scoped *))
217 ((* block markdowncell scoped *))
218 ((( cell.source | citation2latex | markdown2latex )))
218 ((( cell.source | citation2latex | strip_files_prefix | markdown2latex )))
219 ((* endblock markdowncell *))
219 ((* endblock markdowncell *))
220
220
221 % Don't display unknown types
221 % Don't display unknown types
222 ((* block unknowncell scoped *))
222 ((* block unknowncell scoped *))
223 ((* endblock unknowncell *))
223 ((* endblock unknowncell *))
General Comments 0
You need to be logged in to leave comments. Login now