diff -r 6f1f38775991 Lib/idlelib/HyperParser.py --- a/Lib/idlelib/HyperParser.py Sat Jun 14 10:22:05 2014 +0100 +++ b/Lib/idlelib/HyperParser.py Sat Jun 14 20:00:18 2014 +0530 @@ -64,8 +64,8 @@ self.bracketing = parser.get_last_stmt_bracketing() # find which pairs of bracketing are openers. These always correspond # to a character of rawtext. - self.isopener = [i>0 and self.bracketing[i][1] > self.bracketing[i-1][1] - for i in range(len(self.bracketing))] + self.isopener = [self.bracketing[i][1] > self.bracketing[i-1][1] + and i > 0 for i in range(len(self.bracketing))] self.set_index(index) @@ -76,7 +76,8 @@ indexinrawtext = \ len(self.rawtext) - len(self.text.get(index, self.stopatindex)) if indexinrawtext < 0: - raise ValueError("The index given is before the analyzed statement") + raise ValueError("The index given is before the analyzed " + "statement") self.indexinrawtext = indexinrawtext # find the rightmost bracket to which index belongs self.indexbracket = 0 @@ -143,7 +144,8 @@ _whitespace_chars = " \t\n\\" # This string includes all chars that may be in an identifier _id_chars = string.ascii_letters + string.digits + "_" - # This string includes all chars that may be the first char of an identifier + # This string includes all chars that may be + # the first char of an identifier _id_first_chars = string.ascii_letters + "_" # Given a string and pos, return the number of chars in the identifier @@ -163,7 +165,7 @@ index, which is empty if there is no real one. """ if not self.is_in_code(): - raise ValueError("get_expression should only be called if index "\ + raise ValueError("get_expression should only be called if index " "is inside a code.") rawtext = self.rawtext @@ -177,7 +179,7 @@ postdot_phase = True while 1: - # Eat whitespaces, comments, and if postdot_phase is False - one dot + # Eat whitespaces, comments, and if postdot_phase is False - a dot while 1: if pos>brck_limit and rawtext[pos-1] in self._whitespace_chars: # Eat a whitespace @@ -244,3 +246,7 @@ break return rawtext[last_identifier_pos:self.indexinrawtext] + +if __name__ == '__main__': + import unittest + unittest.main('idlelib.idle_test.test_hyperparser', verbosity=2) diff -r 6f1f38775991 Lib/idlelib/idle_test/test_hyperparser.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/idlelib/idle_test/test_hyperparser.py Sat Jun 14 20:00:18 2014 +0530 @@ -0,0 +1,200 @@ +"""Unittest for idlelib.HyperParser""" +import unittest +from test.support import requires +from idlelib.HyperParser import HyperParser +from tkinter import Tk, Text + +class DummyEditwin: + def __init__(self, text): + self.text = text + self.indentwidth = 8 + self.tabwidth = 8 + self.context_use_ps1 = True + + # existing code from EditorWindow + def _build_char_in_string_func(self, startindex): + def inner(offset, _startindex=startindex, + _icis=self.is_char_in_string): + return _icis(_startindex + "+%dc" % offset) + return inner + + # existing code from EditorWindow + def is_char_in_string(self, text_index): + if self.color: + # Return true iff colorizer hasn't (re)gotten this far + # yet, or the character is tagged as being in a string + return self.text.tag_prevrange("TODO", text_index) or \ + "STRING" in self.text.tag_names(text_index) + else: + # The colorizer is missing: assume the worst + return 1 + + +class HyperParserTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = Tk() + cls.text = Text(cls.root) + cls.editwin = DummyEditwin(cls.text) + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + del cls.text, cls.root + + def setUp(self): + code = [] + code.append('"""This is a module docstring"""') + code.append('# this line is a comment') + code.append('x = "this is a string"') + code.append("y = 'this is also a string'") + code.append('l = [i for i in range(10)]') + code.append('m = [py*py for # comment') + code.append(' py in l]') + code.append('x.__len__') + code.append("z = ((r'asdf')+('a')))") + code.append('[x for x in') + code.append('False =') + self.text.insert('insert', '\n'.join(code)) + + def tearDown(self): + self.text.delete('1.0', 'end') + self.editwin.context_use_ps1 = True + + def get_parser(self, index): + """ + Return a parser object with index at 'index' + """ + return HyperParser(self.editwin, index) + + def test_init(self): + """ + test corner cases in the init method + """ + with self.assertRaises(ValueError) as ve: + self.text.tag_add('console', '1.0', '1.end') + p = self.get_parser('1.5') + self.assertIn('before the analyzed', str(ve.exception)) + + # test without ps1 + self.editwin.context_use_ps1 = False + # reason for the constants explained in EditorWindow + self.editwin.num_context_lines = 50, 500, 1000 + + # number of lines lesser than 50 + p = self.get_parser('end') + self.assertEqual(p.rawtext, self.text.get('1.0', 'end')) + + # number of lines greater than 50 + self.text.insert('end', self.text.get('1.0', 'end')*4) + p = self.get_parser('54.5') + + def test_is_in_string(self): + get = self.get_parser + + p = get('1.0') + self.assertFalse(p.is_in_string()) + p = get('1.4') + self.assertTrue(p.is_in_string()) + p = get('2.3') + self.assertFalse(p.is_in_string()) + p = get('3.3') + self.assertFalse(p.is_in_string()) + p = get('3.7') + self.assertTrue(p.is_in_string()) + p = get('4.6') + self.assertTrue(p.is_in_string()) + + def test_is_in_code(self): + get = self.get_parser + + p = get('1.0') + self.assertTrue(p.is_in_code()) + p = get('1.1') + self.assertFalse(p.is_in_code()) + p = get('2.5') + self.assertFalse(p.is_in_code()) + p = get('3.4') + self.assertTrue(p.is_in_code()) + p = get('3.6') + self.assertFalse(p.is_in_code()) + p = get('4.14') + self.assertFalse(p.is_in_code()) + + def test_get_surrounding_bracket(self): + get = self.get_parser + + def without_mustclose(parser): + # a utility function to get surrounding bracket + # with mustclose=False + return parser.get_surrounding_brackets(mustclose=False) + + def with_mustclose(parser): + # a utility function to get surrounding bracket + # with mustclose=True + return parser.get_surrounding_brackets(mustclose=True) + + p = get('3.2') + self.assertIsNone(with_mustclose(p)) + self.assertIsNone(without_mustclose(p)) + + p = get('5.6') + self.assertTupleEqual(without_mustclose(p), ('5.4', '5.25')) + self.assertTupleEqual(without_mustclose(p), with_mustclose(p)) + + p = get('5.23') + self.assertTupleEqual(without_mustclose(p), ('5.21', '5.24')) + self.assertTupleEqual(without_mustclose(p), with_mustclose(p)) + + p = get('6.15') + self.assertTupleEqual(without_mustclose(p), ('6.4', '6.end')) + self.assertIsNone(with_mustclose(p)) + + p = get('9.end') + self.assertIsNone(with_mustclose(p)) + self.assertIsNone(without_mustclose(p)) + + def test_get_expression(self): + get = self.get_parser + + p = get('4.2') + self.assertEqual(p.get_expression(), 'y ') + + p = get('4.7') + with self.assertRaises(ValueError) as ve: + p.get_expression() + self.assertIn('is inside a code', str(ve.exception)) + + p = get('5.25') + self.assertEqual(p.get_expression(), 'range(10)') + + p = get('6.7') + self.assertEqual(p.get_expression(), 'py') + + p = get('6.8') + self.assertEqual(p.get_expression(), '') + + p = get('7.9') + self.assertEqual(p.get_expression(), 'py') + + p = get('8.end') + self.assertEqual(p.get_expression(), 'x.__len__') + + p = get('9.13') + self.assertEqual(p.get_expression(), "r'asdf'") + + p = get('9.17') + with self.assertRaises(ValueError) as ve: + p.get_expression() + self.assertIn('is inside a code', str(ve.exception)) + + p = get('10.0') + self.assertEqual(p.get_expression(), '') + + p = get('11.5') + self.assertEqual(p.get_expression(), '') + +if __name__ == '__main__': + unittest.main(verbosity=2)