##// END OF EJS Templates
don't do anything if add_anchor fails
MinRK -
Show More
@@ -1,204 +1,212 b''
1 1 # coding: utf-8
2 2 """String filters.
3 3
4 4 Contains a collection of useful string manipulation filters for use in Jinja
5 5 templates.
6 6 """
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2013, the IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import os
20 20 import re
21 21 import textwrap
22 22 try:
23 23 from urllib.parse import quote # Py 3
24 24 except ImportError:
25 25 from urllib2 import quote # Py 2
26 26 from xml.etree import ElementTree
27 27
28 28 from IPython.core.interactiveshell import InteractiveShell
29 29 from IPython.utils import py3compat
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Functions
33 33 #-----------------------------------------------------------------------------
34 34
35 35 __all__ = [
36 36 'wrap_text',
37 37 'html2text',
38 38 'add_anchor',
39 39 'strip_dollars',
40 40 'strip_files_prefix',
41 41 'comment_lines',
42 42 'get_lines',
43 43 'ipython2python',
44 44 'posix_path',
45 45 'path2url',
46 46 'add_prompts'
47 47 ]
48 48
49 49
50 50 def wrap_text(text, width=100):
51 51 """
52 52 Intelligently wrap text.
53 53 Wrap text without breaking words if possible.
54 54
55 55 Parameters
56 56 ----------
57 57 text : str
58 58 Text to wrap.
59 59 width : int, optional
60 60 Number of characters to wrap to, default 100.
61 61 """
62 62
63 63 split_text = text.split('\n')
64 64 wrp = map(lambda x:textwrap.wrap(x,width), split_text)
65 65 wrpd = map('\n'.join, wrp)
66 66 return '\n'.join(wrpd)
67 67
68 68
69 69 def html2text(element):
70 70 """extract inner text from html
71 71
72 72 Analog of jQuery's $(element).text()
73 73 """
74 74 if isinstance(element, py3compat.string_types):
75 element = ElementTree.fromstring(element)
75 try:
76 element = ElementTree.fromstring(element)
77 except Exception:
78 # failed to parse, just return it unmodified
79 return element
76 80
77 81 text = element.text or ""
78 82 for child in element:
79 83 text += html2text(child)
80 84 text += (element.tail or "")
81 85 return text
82 86
83 87
84 88 def add_anchor(html):
85 89 """Add an anchor-link to an html header tag
86 90
87 91 For use in heading cells
88 92 """
89 h = ElementTree.fromstring(py3compat.cast_bytes_py2(html, encoding='utf-8'))
93 try:
94 h = ElementTree.fromstring(py3compat.cast_bytes_py2(html, encoding='utf-8'))
95 except Exception:
96 # failed to parse, just return it unmodified
97 return html
90 98 link = html2text(h).replace(' ', '-')
91 99 h.set('id', link)
92 100 a = ElementTree.Element("a", {"class" : "anchor-link", "href" : "#" + link})
93 101 a.text = u'ΒΆ'
94 102 h.append(a)
95 103
96 104 # Known issue of Python3.x, ElementTree.tostring() returns a byte string
97 105 # instead of a text string. See issue http://bugs.python.org/issue10942
98 106 # Workaround is to make sure the bytes are casted to a string.
99 107 return py3compat.decode(ElementTree.tostring(h), 'utf-8')
100 108
101 109
102 110 def add_prompts(code, first='>>> ', cont='... '):
103 111 """Add prompts to code snippets"""
104 112 new_code = []
105 113 code_list = code.split('\n')
106 114 new_code.append(first + code_list[0])
107 115 for line in code_list[1:]:
108 116 new_code.append(cont + line)
109 117 return '\n'.join(new_code)
110 118
111 119
112 120 def strip_dollars(text):
113 121 """
114 122 Remove all dollar symbols from text
115 123
116 124 Parameters
117 125 ----------
118 126 text : str
119 127 Text to remove dollars from
120 128 """
121 129
122 130 return text.strip('$')
123 131
124 132
125 133 files_url_pattern = re.compile(r'(src|href)\=([\'"]?)files/')
126 134
127 135 def strip_files_prefix(text):
128 136 """
129 137 Fix all fake URLs that start with `files/`,
130 138 stripping out the `files/` prefix.
131 139
132 140 Parameters
133 141 ----------
134 142 text : str
135 143 Text in which to replace 'src="files/real...' with 'src="real...'
136 144 """
137 145 return files_url_pattern.sub(r"\1=\2", text)
138 146
139 147
140 148 def comment_lines(text, prefix='# '):
141 149 """
142 150 Build a Python comment line from input text.
143 151
144 152 Parameters
145 153 ----------
146 154 text : str
147 155 Text to comment out.
148 156 prefix : str
149 157 Character to append to the start of each line.
150 158 """
151 159
152 160 #Replace line breaks with line breaks and comment symbols.
153 161 #Also add a comment symbol at the beginning to comment out
154 162 #the first line.
155 163 return prefix + ('\n'+prefix).join(text.split('\n'))
156 164
157 165
158 166 def get_lines(text, start=None,end=None):
159 167 """
160 168 Split the input text into separate lines and then return the
161 169 lines that the caller is interested in.
162 170
163 171 Parameters
164 172 ----------
165 173 text : str
166 174 Text to parse lines from.
167 175 start : int, optional
168 176 First line to grab from.
169 177 end : int, optional
170 178 Last line to grab from.
171 179 """
172 180
173 181 # Split the input into lines.
174 182 lines = text.split("\n")
175 183
176 184 # Return the right lines.
177 185 return "\n".join(lines[start:end]) #re-join
178 186
179 187 def ipython2python(code):
180 188 """Transform IPython syntax to pure Python syntax
181 189
182 190 Parameters
183 191 ----------
184 192
185 193 code : str
186 194 IPython code, to be transformed to pure Python
187 195 """
188 196 shell = InteractiveShell.instance()
189 197 return shell.input_transformer_manager.transform_cell(code)
190 198
191 199 def posix_path(path):
192 200 """Turn a path into posix-style path/to/etc
193 201
194 202 Mainly for use in latex on Windows,
195 203 where native Windows paths are not allowed.
196 204 """
197 205 if os.path.sep != '/':
198 206 return path.replace(os.path.sep, '/')
199 207 return path
200 208
201 209 def path2url(path):
202 210 """Turn a file path into a URL"""
203 211 parts = path.split(os.path.sep)
204 212 return '/'.join(quote(part) for part in parts)
@@ -1,135 +1,140 b''
1 1 """
2 2 Module with tests for Strings
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 import os
17 17
18 18 from ...tests.base import TestsBase
19 19 from ..strings import (wrap_text, html2text, add_anchor, strip_dollars,
20 20 strip_files_prefix, get_lines, comment_lines, ipython2python, posix_path,
21 21 add_prompts
22 22 )
23 23
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Class
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class TestStrings(TestsBase):
30 30
31 31 def test_wrap_text(self):
32 32 """wrap_text test"""
33 33 test_text = """
34 34 Tush! never tell me; I take it much unkindly
35 35 That thou, Iago, who hast had my purse
36 36 As if the strings were thine, shouldst know of this.
37 37 """
38 38 for length in [30,5,1]:
39 39 self._confirm_wrap_text(test_text, length)
40 40
41 41
42 42 def _confirm_wrap_text(self, text, length):
43 43 for line in wrap_text(text, length).split('\n'):
44 44 assert len(line) <= length
45 45
46 46
47 47 def test_html2text(self):
48 48 """html2text test"""
49 49 #TODO: More tests
50 50 self.assertEqual(html2text('<name>joe</name>'), 'joe')
51 51
52 52
53 53 def test_add_anchor(self):
54 54 """add_anchor test"""
55 55 #TODO: More tests
56 56 results = add_anchor('<b>Hello World!</b>')
57 57 assert 'Hello World!' in results
58 58 assert 'id="' in results
59 59 assert 'class="anchor-link"' in results
60 60 assert '<b' in results
61 61 assert '</b>' in results
62 62
63
63 def test_add_anchor_fail(self):
64 """add_anchor does nothing when it fails"""
65 html = '<h1>Hello <br>World!</h1>'
66 results = add_anchor(html)
67 self.assertEqual(html, results)
68
64 69 def test_strip_dollars(self):
65 70 """strip_dollars test"""
66 71 tests = [
67 72 ('', ''),
68 73 ('$$', ''),
69 74 ('$H$', 'H'),
70 75 ('$He', 'He'),
71 76 ('H$el', 'H$el'),
72 77 ('Hell$', 'Hell'),
73 78 ('Hello', 'Hello'),
74 79 ('W$o$rld', 'W$o$rld')]
75 80 for test in tests:
76 81 self._try_strip_dollars(test[0], test[1])
77 82
78 83
79 84 def _try_strip_dollars(self, test, result):
80 85 self.assertEqual(strip_dollars(test), result)
81 86
82 87
83 88 def test_strip_files_prefix(self):
84 89 """strip_files_prefix test"""
85 90 tests = [
86 91 ('', ''),
87 92 ('/files', '/files'),
88 93 ('test="/files"', 'test="/files"'),
89 94 ('My files are in `files/`', 'My files are in `files/`'),
90 95 ('<a href="files/test.html">files/test.html</a>', '<a href="test.html">files/test.html</a>')]
91 96 for test in tests:
92 97 self._try_files_prefix(test[0], test[1])
93 98
94 99
95 100 def _try_files_prefix(self, test, result):
96 101 self.assertEqual(strip_files_prefix(test), result)
97 102
98 103
99 104 def test_comment_lines(self):
100 105 """comment_lines test"""
101 106 for line in comment_lines('hello\nworld\n!').split('\n'):
102 107 assert line.startswith('# ')
103 108 for line in comment_lines('hello\nworld\n!', 'beep').split('\n'):
104 109 assert line.startswith('beep')
105 110
106 111
107 112 def test_get_lines(self):
108 113 """get_lines test"""
109 114 text = "hello\nworld\n!"
110 115 self.assertEqual(get_lines(text, start=1), "world\n!")
111 116 self.assertEqual(get_lines(text, end=2), "hello\nworld")
112 117 self.assertEqual(get_lines(text, start=2, end=5), "!")
113 118 self.assertEqual(get_lines(text, start=-2), "world\n!")
114 119
115 120
116 121 def test_ipython2python(self):
117 122 """ipython2python test"""
118 123 #TODO: More tests
119 124 results = ipython2python(u'%%pylab\nprint("Hello-World")').replace("u'", "'")
120 125 self.fuzzy_compare(results, u"get_ipython().run_cell_magic('pylab', '', 'print(\"Hello-World\")')",
121 126 ignore_spaces=True, ignore_newlines=True)
122 127
123 128 def test_posix_path(self):
124 129 """posix_path test"""
125 130 path_list = ['foo', 'bar']
126 131 expected = '/'.join(path_list)
127 132 native = os.path.join(*path_list)
128 133 filtered = posix_path(native)
129 134 self.assertEqual(filtered, expected)
130 135
131 136 def test_add_prompts(self):
132 137 """add_prompts test"""
133 138 text1 = """for i in range(10):\n i += 1\n print i"""
134 139 text2 = """>>> for i in range(10):\n... i += 1\n... print i"""
135 140 self.assertEqual(text2, add_prompts(text1))
General Comments 0
You need to be logged in to leave comments. Login now