| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ebeffd7 commit a2a934c
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -118,23 +118,41 @@ def runsource(self, source, filename=None, symbol='single', | |||
| 118 | 118 | ||
| 119 | 119 | In Python 3, source must be a unicode string | |
| 120 | 120 | In Python 2, source may be latin-1 bytestring or unicode string, | |
| 121 | - following the interface of code.InteractiveInterpreter""" | ||
| 122 | - if encode == 'auto': | ||
| 123 | - encode = filename is None | ||
| 124 | - if encode and not py3: | ||
| 125 | - if isinstance(source, str): | ||
| 126 | - # encoding only makes sense for bytestrings | ||
| 127 | - assert isinstance(source, str) | ||
| 128 | - source = b'# coding: %s\n\n%s' % (self.encoding, source) | ||
| 129 | - else: | ||
| 130 | - # 2 blank lines still need to be added because this | ||
| 131 | - # interpreter always adds 2 lines to stack trace line | ||
| 121 | + following the interface of code.InteractiveInterpreter. | ||
| 122 | + | ||
| 123 | + Because adding an encoding comment to a unicode string in Python 2 | ||
| 124 | + would cause a syntax error to be thrown which would reference code | ||
| 125 | + the user did not write, setting encoding to True when source is a | ||
| 126 | + unicode string in Python 2 will throw a ValueError.""" | ||
| 127 | + # str means bytestring in Py2 | ||
| 128 | + if encode and not py3 and isinstance(source, unicode): | ||
| 129 | + if encode != 'auto': | ||
| 130 | + raise ValueError("can't add encoding line to unicode input") | ||
| 131 | + encode = False | ||
| 132 | + if encode and filename is not None: | ||
| 133 | + # files have encoding comments or implicit encoding of ASCII | ||
| 134 | + if encode != 'auto': | ||
| 135 | + raise ValueError("shouldn't add encoding line to file contents") | ||
| 136 | + encode = False | ||
| 137 | + | ||
| 138 | + if encode and not py3 and isinstance(source, str): | ||
| 139 | + # encoding makes sense for bytestrings, so long as there | ||
| 140 | + # isn't already an encoding comment | ||
| 141 | + comment = inspection.get_encoding_comment(source) | ||
| 142 | + if comment: | ||
| 143 | + # keep the existing encoding comment, but add two lines | ||
| 144 | + # because this interp always adds 2 to stack trace line | ||
| 132 | 145 | # numbers in Python 2 | |
| 133 | - comment = inspection.get_encoding_comment(source) | ||
| 134 | - if comment: | ||
| 135 | - source = source.replace(comment, u'%s\n\n' % comment, 1) | ||
| 136 | - else: | ||
| 137 | - source = u'\n\n' + source | ||
| 146 | + source = source.replace(comment, b'%s\n\n' % comment, 1) | ||
| 147 | + else: | ||
| 148 | + source = b'# coding: %s\n\n%s' % (self.encoding, source) | ||
| 149 | + elif not py3 and filename is None: | ||
| 150 | + # 2 blank lines still need to be added | ||
| 151 | + # because this interpreter always adds 2 to stack trace line | ||
| 152 | + # numbers in Python 2 when the filename is "<input>" | ||
| 153 | + newlines = u'\n\n' if isinstance(source, unicode) else b'\n\n' | ||
| 154 | + source = newlines + source | ||
| 155 | + # we know we're in Python 2 here, so ok to reference unicode | ||
| 138 | 156 | if filename is None: | |
| 139 | 157 | filename = filename_for_console_input(source) | |
| 140 | 158 | with self.timer: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,6 +3,8 @@ | |||
| 3 | 3 | from __future__ import unicode_literals | |
| 4 | 4 | ||
| 5 | 5 | import sys | |
| 6 | + import re | ||
| 7 | + from textwrap import dedent | ||
| 6 | 8 | ||
| 7 | 9 | from curtsies.fmtfuncs import bold, green, magenta, cyan, red, plain | |
| 8 | 10 | ||
@@ -13,15 +15,32 @@ | |||
| 13 | 15 | pypy = 'PyPy' in sys.version | |
| 14 | 16 | ||
| 15 | 17 | ||
| 18 | + def remove_ansi(s): | ||
| 19 | + return re.sub(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]'.encode('ascii'), b'', s) | ||
| 20 | + | ||
| 21 | + | ||
| 16 | 22 | class TestInterpreter(unittest.TestCase): | |
| 17 | - def test_syntaxerror(self): | ||
| 23 | + def interp_errlog(self): | ||
| 18 | 24 | i = interpreter.Interp() | |
| 19 | 25 | a = [] | |
| 26 | + i.write = a.append | ||
| 27 | + return i, a | ||
| 28 | + | ||
| 29 | + def err_lineno(self, a): | ||
| 30 | + strings = [x.__unicode__() for x in a] | ||
| 31 | + print('looking for lineno') | ||
| 32 | + for line in reversed(strings): | ||
| 33 | + clean_line = remove_ansi(line) | ||
| 34 | + print(clean_line) | ||
| 35 | + m = re.search(r'line (\d+)[,]', clean_line) | ||
| 36 | + if m: | ||
| 37 | + print('found!', m.group(1)) | ||
| 38 | + return int(m.group(1)) | ||
| 39 | + return None | ||
| 20 | 40 | ||
| 21 | - def append_to_a(message): | ||
| 22 | - a.append(message) | ||
| 41 | + def test_syntaxerror(self): | ||
| 42 | + i, a = self.interp_errlog() | ||
| 23 | 43 | ||
| 24 | - i.write = append_to_a | ||
| 25 | 44 | i.runsource('1.1.1.1') | |
| 26 | 45 | ||
| 27 | 46 | if pypy: | |
@@ -41,13 +60,7 @@ def append_to_a(message): | |||
| 41 | 60 | self.assertEquals(plain('').join(a), expected) | |
| 42 | 61 | ||
| 43 | 62 | def test_traceback(self): | |
| 44 | - i = interpreter.Interp() | ||
| 45 | - a = [] | ||
| 46 | - | ||
| 47 | - def append_to_a(message): | ||
| 48 | - a.append(message) | ||
| 49 | - | ||
| 50 | - i.write = append_to_a | ||
| 63 | + i, a = self.interp_errlog() | ||
| 51 | 64 | ||
| 52 | 65 | def f(): | |
| 53 | 66 | return 1 / 0 | |
@@ -88,22 +101,22 @@ def test_runsource_bytes_over_128_syntax_error_py3(self): | |||
| 88 | 101 | i = interpreter.Interp(encoding=b'latin-1') | |
| 89 | 102 | i.showsyntaxerror = mock.Mock(return_value=None) | |
| 90 | 103 | ||
| 91 | - i.runsource("a = b'\xfe'", encode=True) | ||
| 104 | + i.runsource("a = b'\xfe'") | ||
| 92 | 105 | i.showsyntaxerror.assert_called_with(mock.ANY) | |
| 93 | 106 | ||
| 94 | 107 | @unittest.skipIf(py3, "encode is Python 2 only") | |
| 95 | 108 | def test_runsource_bytes_over_128_syntax_error_py2(self): | |
| 96 | 109 | i = interpreter.Interp(encoding=b'latin-1') | |
| 97 | 110 | ||
| 98 | - i.runsource(b"a = b'\xfe'", encode=True) | ||
| 111 | + i.runsource(b"a = b'\xfe'") | ||
| 99 | 112 | self.assertIsInstance(i.locals['a'], type(b'')) | |
| 100 | 113 | self.assertEqual(i.locals['a'], b"\xfe") | |
| 101 | 114 | ||
| 102 | 115 | @unittest.skipIf(py3, "encode is Python 2 only") | |
| 103 | 116 | def test_runsource_unicode(self): | |
| 104 | 117 | i = interpreter.Interp(encoding=b'latin-1') | |
| 105 | 118 | ||
| 106 | - i.runsource("a = u'\xfe'", encode=True) | ||
| 119 | + i.runsource("a = u'\xfe'") | ||
| 107 | 120 | self.assertIsInstance(i.locals['a'], type(u'')) | |
| 108 | 121 | self.assertEqual(i.locals['a'], u"\xfe") | |
| 109 | 122 | ||
@@ -114,3 +127,119 @@ def test_getsource_works_on_interactively_defined_functions(self): | |||
| 114 | 127 | import inspect | |
| 115 | 128 | inspected_source = inspect.getsource(i.locals['foo']) | |
| 116 | 129 | self.assertEquals(inspected_source, source) | |
| 130 | + | ||
| 131 | + @unittest.skipIf(py3, "encode only does anything in Python 2") | ||
| 132 | + def test_runsource_unicode_autoencode_and_noencode(self): | ||
| 133 | + """error line numbers should be fixed""" | ||
| 134 | + | ||
| 135 | + # Since correct behavior for unicode is the same | ||
| 136 | + # for auto and False, run the same tests | ||
| 137 | + for encode in ['auto', False]: | ||
| 138 | + i, a = self.interp_errlog() | ||
| 139 | + i.runsource(u'[1 + 1,\nabc]', encode=encode) | ||
| 140 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 141 | + | ||
| 142 | + i, a = self.interp_errlog() | ||
| 143 | + i.runsource(u'[1 + 1,\nabc]', encode=encode) | ||
| 144 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 145 | + | ||
| 146 | + i, a = self.interp_errlog() | ||
| 147 | + i.runsource(u'#encoding: utf-8\nabc', encode=encode) | ||
| 148 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 149 | + | ||
| 150 | + i, a = self.interp_errlog() | ||
| 151 | + i.runsource(u'#encoding: utf-8\nabc', | ||
| 152 | + filename='x.py', encode=encode) | ||
| 153 | + self.assertIn('SyntaxError: encoding', | ||
| 154 | + ''.join(''.join(remove_ansi(x.__unicode__()) for x in a))) | ||
| 155 | + | ||
| 156 | + @unittest.skipIf(py3, "encode only does anything in Python 2") | ||
| 157 | + def test_runsource_unicode_encode(self): | ||
| 158 | + i, _ = self.interp_errlog() | ||
| 159 | + with self.assertRaises(ValueError): | ||
| 160 | + i.runsource(u'1 + 1', encode=True) | ||
| 161 | + | ||
| 162 | + i, _ = self.interp_errlog() | ||
| 163 | + with self.assertRaises(ValueError): | ||
| 164 | + i.runsource(u'1 + 1', filename='x.py', encode=True) | ||
| 165 | + | ||
| 166 | + @unittest.skipIf(py3, "encode only does anything in Python 2") | ||
| 167 | + def test_runsource_bytestring_noencode(self): | ||
| 168 | + i, a = self.interp_errlog() | ||
| 169 | + i.runsource(b'[1 + 1,\nabc]', encode=False) | ||
| 170 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 171 | + | ||
| 172 | + i, a = self.interp_errlog() | ||
| 173 | + i.runsource(b'[1 + 1,\nabc]', filename='x.py', encode=False) | ||
| 174 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 175 | + | ||
| 176 | + i, a = self.interp_errlog() | ||
| 177 | + i.runsource(dedent(b'''\ | ||
| 178 | + #encoding: utf-8 | ||
| 179 | + | ||
| 180 | + ["%s", | ||
| 181 | + abc]''' % (u'åß∂ƒ'.encode('utf8'),)), encode=False) | ||
| 182 | + self.assertEqual(self.err_lineno(a), 4) | ||
| 183 | + | ||
| 184 | + i, a = self.interp_errlog() | ||
| 185 | + i.runsource(dedent(b'''\ | ||
| 186 | + #encoding: utf-8 | ||
| 187 | + | ||
| 188 | + ["%s", | ||
| 189 | + abc]''' % (u'åß∂ƒ'.encode('utf8'),)), | ||
| 190 | + filename='x.py', encode=False) | ||
| 191 | + self.assertEqual(self.err_lineno(a), 4) | ||
| 192 | + | ||
| 193 | + @unittest.skipIf(py3, "encode only does anything in Python 2") | ||
| 194 | + def test_runsource_bytestring_encode(self): | ||
| 195 | + i, a = self.interp_errlog() | ||
| 196 | + i.runsource(b'[1 + 1,\nabc]', encode=True) | ||
| 197 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 198 | + | ||
| 199 | + i, a = self.interp_errlog() | ||
| 200 | + with self.assertRaises(ValueError): | ||
| 201 | + i.runsource(b'[1 + 1,\nabc]', filename='x.py', encode=True) | ||
| 202 | + | ||
| 203 | + i, a = self.interp_errlog() | ||
| 204 | + i.runsource(dedent(b'''\ | ||
| 205 | + #encoding: utf-8 | ||
| 206 | + | ||
| 207 | + [u"%s", | ||
| 208 | + abc]''' % (u'åß∂ƒ'.encode('utf8'),)), encode=True) | ||
| 209 | + self.assertEqual(self.err_lineno(a), 4) | ||
| 210 | + | ||
| 211 | + i, a = self.interp_errlog() | ||
| 212 | + with self.assertRaises(ValueError): | ||
| 213 | + i.runsource(dedent(b'''\ | ||
| 214 | + #encoding: utf-8 | ||
| 215 | + | ||
| 216 | + [u"%s", | ||
| 217 | + abc]''' % (u'åß∂ƒ'.encode('utf8'),)), | ||
| 218 | + filename='x.py', | ||
| 219 | + encode=True) | ||
| 220 | + | ||
| 221 | + @unittest.skipIf(py3, "encode only does anything in Python 2") | ||
| 222 | + def test_runsource_bytestring_autoencode(self): | ||
| 223 | + i, a = self.interp_errlog() | ||
| 224 | + i.runsource(b'[1 + 1,\n abc]') | ||
| 225 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 226 | + | ||
| 227 | + i, a = self.interp_errlog() | ||
| 228 | + i.runsource(b'[1 + 1,\nabc]', filename='x.py') | ||
| 229 | + self.assertEqual(self.err_lineno(a), 2) | ||
| 230 | + | ||
| 231 | + i, a = self.interp_errlog() | ||
| 232 | + i.runsource(dedent(b'''\ | ||
| 233 | + #encoding: utf-8 | ||
| 234 | + | ||
| 235 | + [u"%s", | ||
| 236 | + abc]''' % (u'åß∂ƒ'.encode('utf8'),))) | ||
| 237 | + self.assertEqual(self.err_lineno(a), 4) | ||
| 238 | + | ||
| 239 | + i, a = self.interp_errlog() | ||
| 240 | + i.runsource(dedent(b'''\ | ||
| 241 | + #encoding: utf-8 | ||
| 242 | + | ||
| 243 | + [u"%s", | ||
| 244 | + abc]''' % (u'åß∂ƒ'.encode('utf8'),))) | ||
| 245 | + self.assertEqual(self.err_lineno(a), 4) | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments