diff options
author | Tal Einat <taleinat@gmail.com> | 2019-07-17 08:15:53 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-17 08:15:53 (GMT) |
commit | 7036e1de3a87d36c7ef41b8a2b44ed6fc4d34be2 (patch) | |
tree | af7513ef796268a9749c1b4dc3fdcfb83a4f8b0b /Lib/idlelib/idle_test | |
parent | bd26a4466b507e196fc9a5e4a6cb7cd6d39f85aa (diff) | |
download | cpython-7036e1de3a87d36c7ef41b8a2b44ed6fc4d34be2.zip cpython-7036e1de3a87d36c7ef41b8a2b44ed6fc4d34be2.tar.gz cpython-7036e1de3a87d36c7ef41b8a2b44ed6fc4d34be2.tar.bz2 |
bpo-37530: simplify, optimize and clean up IDLE code context (GH-14675)
* Only create CodeContext instances for "real" editors windows, but
not e.g. shell or output windows.
* Remove configuration update Tk event fired every second, by having
the editor window ask its code context widget to update when
necessary, i.e. upon font or highlighting updates.
* When code context isn't being shown, avoid having a Tk event fired
every 100ms to check whether the code context needs to be updated.
* Use the editor window's getlineno() method where applicable.
* Update font of the code context widget before the main text widget
Diffstat (limited to 'Lib/idlelib/idle_test')
-rw-r--r-- | Lib/idlelib/idle_test/test_codecontext.py | 144 |
1 files changed, 86 insertions, 58 deletions
diff --git a/Lib/idlelib/idle_test/test_codecontext.py b/Lib/idlelib/idle_test/test_codecontext.py index 6c68935..05d3209 100644 --- a/Lib/idlelib/idle_test/test_codecontext.py +++ b/Lib/idlelib/idle_test/test_codecontext.py @@ -2,6 +2,7 @@ from idlelib import codecontext import unittest +import unittest.mock from test.support import requires from tkinter import Tk, Frame, Text, TclError @@ -42,6 +43,9 @@ class DummyEditwin: self.text = text self.label = '' + def getlineno(self, index): + return int(float(self.text.index(index))) + def update_menu_label(self, **kwargs): self.label = kwargs['label'] @@ -75,6 +79,18 @@ class CodeContextTest(unittest.TestCase): self.text.yview(0) self.cc = codecontext.CodeContext(self.editor) + self.highlight_cfg = {"background": '#abcdef', + "foreground": '#123456'} + orig_idleConf_GetHighlight = codecontext.idleConf.GetHighlight + def mock_idleconf_GetHighlight(theme, element): + if element == 'context': + return self.highlight_cfg + return orig_idleConf_GetHighlight(theme, element) + patcher = unittest.mock.patch.object( + codecontext.idleConf, 'GetHighlight', mock_idleconf_GetHighlight) + patcher.start() + self.addCleanup(patcher.stop) + def tearDown(self): if self.cc.context: self.cc.context.destroy() @@ -89,30 +105,24 @@ class CodeContextTest(unittest.TestCase): eq(cc.editwin, ed) eq(cc.text, ed.text) - eq(cc.textfont, ed.text['font']) + eq(cc.text['font'], ed.text['font']) self.assertIsNone(cc.context) eq(cc.info, [(0, -1, '', False)]) eq(cc.topvisible, 1) - eq(self.root.tk.call('after', 'info', self.cc.t1)[1], 'timer') - eq(self.root.tk.call('after', 'info', self.cc.t2)[1], 'timer') + self.assertIsNone(self.cc.t1) def test_del(self): self.cc.__del__() - with self.assertRaises(TclError) as msg: - self.root.tk.call('after', 'info', self.cc.t1) - self.assertIn("doesn't exist", msg) - with self.assertRaises(TclError) as msg: - self.root.tk.call('after', 'info', self.cc.t2) - self.assertIn("doesn't exist", msg) - # For coverage on the except. Have to delete because the - # above Tcl error is caught by after_cancel. - del self.cc.t1, self.cc.t2 + + def test_del_with_timer(self): + timer = self.cc.t1 = self.text.after(10000, lambda: None) self.cc.__del__() + with self.assertRaises(TclError) as cm: + self.root.tk.call('after', 'info', timer) + self.assertIn("doesn't exist", str(cm.exception)) def test_reload(self): codecontext.CodeContext.reload() - self.assertEqual(self.cc.colors, {'background': 'lightgray', - 'foreground': '#000000'}) self.assertEqual(self.cc.context_depth, 15) def test_toggle_code_context_event(self): @@ -127,16 +137,18 @@ class CodeContextTest(unittest.TestCase): # Toggle on. eq(toggle(), 'break') self.assertIsNotNone(cc.context) - eq(cc.context['font'], cc.textfont) - eq(cc.context['fg'], cc.colors['foreground']) - eq(cc.context['bg'], cc.colors['background']) + eq(cc.context['font'], self.text['font']) + eq(cc.context['fg'], self.highlight_cfg['foreground']) + eq(cc.context['bg'], self.highlight_cfg['background']) eq(cc.context.get('1.0', 'end-1c'), '') eq(cc.editwin.label, 'Hide Code Context') + eq(self.root.tk.call('after', 'info', self.cc.t1)[1], 'timer') # Toggle off. eq(toggle(), 'break') self.assertIsNone(cc.context) eq(cc.editwin.label, 'Show Code Context') + self.assertIsNone(self.cc.t1) def test_get_context(self): eq = self.assertEqual @@ -227,7 +239,7 @@ class CodeContextTest(unittest.TestCase): (4, 4, ' def __init__(self, a, b):', 'def')]) eq(cc.topvisible, 5) eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n' - ' def __init__(self, a, b):') + ' def __init__(self, a, b):') # Scroll down to line 11. Last 'def' is removed. cc.text.yview(11) @@ -239,9 +251,9 @@ class CodeContextTest(unittest.TestCase): (10, 8, ' elif a < b:', 'elif')]) eq(cc.topvisible, 12) eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n' - ' def compare(self):\n' - ' if a > b:\n' - ' elif a < b:') + ' def compare(self):\n' + ' if a > b:\n' + ' elif a < b:') # No scroll. No update, even though context_depth changed. cc.update_code_context() @@ -253,9 +265,9 @@ class CodeContextTest(unittest.TestCase): (10, 8, ' elif a < b:', 'elif')]) eq(cc.topvisible, 12) eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n' - ' def compare(self):\n' - ' if a > b:\n' - ' elif a < b:') + ' def compare(self):\n' + ' if a > b:\n' + ' elif a < b:') # Scroll up. cc.text.yview(5) @@ -276,7 +288,7 @@ class CodeContextTest(unittest.TestCase): cc.toggle_code_context_event() # Empty context. - cc.text.yview(f'{2}.0') + cc.text.yview('2.0') cc.update_code_context() eq(cc.topvisible, 2) cc.context.mark_set('insert', '1.5') @@ -284,7 +296,7 @@ class CodeContextTest(unittest.TestCase): eq(cc.topvisible, 1) # 4 lines of context showing. - cc.text.yview(f'{12}.0') + cc.text.yview('12.0') cc.update_code_context() eq(cc.topvisible, 12) cc.context.mark_set('insert', '3.0') @@ -293,7 +305,7 @@ class CodeContextTest(unittest.TestCase): # More context lines than limit. cc.context_depth = 2 - cc.text.yview(f'{12}.0') + cc.text.yview('12.0') cc.update_code_context() eq(cc.topvisible, 12) cc.context.mark_set('insert', '1.0') @@ -313,56 +325,72 @@ class CodeContextTest(unittest.TestCase): self.cc.timer_event() mock_update.assert_called() - def test_config_timer_event(self): + def test_font(self): eq = self.assertEqual cc = self.cc save_font = cc.text['font'] - save_colors = codecontext.CodeContext.colors - test_font = 'FakeFont' + test_font = 'TkFixedFont' + + # Ensure code context is not active. + if cc.context is not None: + cc.toggle_code_context_event() + + # Nothing breaks or changes with inactive code context. + cc.update_font(test_font) + + # Activate code context, but no change to font. + cc.toggle_code_context_event() + eq(cc.context['font'], save_font) + # Call font update with the existing font. + cc.update_font(save_font) + eq(cc.context['font'], save_font) + cc.toggle_code_context_event() + + # Change text widget font and activate code context. + cc.text['font'] = test_font + cc.toggle_code_context_event(test_font) + eq(cc.context['font'], test_font) + + # Just call the font update. + cc.update_font(save_font) + eq(cc.context['font'], save_font) + cc.text['font'] = save_font + + def test_highlight_colors(self): + eq = self.assertEqual + cc = self.cc + save_colors = dict(self.highlight_cfg) test_colors = {'background': '#222222', 'foreground': '#ffff00'} # Ensure code context is not active. if cc.context: cc.toggle_code_context_event() - # Nothing updates on inactive code context. - cc.text['font'] = test_font - codecontext.CodeContext.colors = test_colors - cc.config_timer_event() - eq(cc.textfont, save_font) - eq(cc.contextcolors, save_colors) + # Nothing breaks with inactive code context. + cc.update_highlight_colors() - # Activate code context, but no change to font or color. + # Activate code context, but no change to colors. cc.toggle_code_context_event() - cc.text['font'] = save_font - codecontext.CodeContext.colors = save_colors - cc.config_timer_event() - eq(cc.textfont, save_font) - eq(cc.contextcolors, save_colors) - eq(cc.context['font'], save_font) eq(cc.context['background'], save_colors['background']) eq(cc.context['foreground'], save_colors['foreground']) - # Active code context, change font. - cc.text['font'] = test_font - cc.config_timer_event() - eq(cc.textfont, test_font) - eq(cc.contextcolors, save_colors) - eq(cc.context['font'], test_font) + # Call colors update, but no change to font. + cc.update_highlight_colors() eq(cc.context['background'], save_colors['background']) eq(cc.context['foreground'], save_colors['foreground']) + cc.toggle_code_context_event() - # Active code context, change color. - cc.text['font'] = save_font - codecontext.CodeContext.colors = test_colors - cc.config_timer_event() - eq(cc.textfont, save_font) - eq(cc.contextcolors, test_colors) - eq(cc.context['font'], save_font) + # Change colors and activate code context. + self.highlight_cfg = test_colors + cc.toggle_code_context_event() eq(cc.context['background'], test_colors['background']) eq(cc.context['foreground'], test_colors['foreground']) - codecontext.CodeContext.colors = save_colors - cc.config_timer_event() + + # Change colors and call highlight colors update. + self.highlight_cfg = save_colors + cc.update_highlight_colors() + eq(cc.context['background'], save_colors['background']) + eq(cc.context['foreground'], save_colors['foreground']) class HelperFunctionText(unittest.TestCase): |