diff --git a/IPython/core/events.py b/IPython/core/events.py index dcdc669..798ef01 100644 --- a/IPython/core/events.py +++ b/IPython/core/events.py @@ -63,14 +63,6 @@ class EventManager(object): """Remove a callback from the given event.""" self.callbacks[event].remove(function) - def reset(self, event): - """Clear all callbacks for the given event.""" - self.callbacks[event] = [] - - def reset_all(self): - """Clear all callbacks for all events.""" - self.callbacks = {n:[] for n in self.callbacks} - def trigger(self, event, *args, **kwargs): """Call callbacks for ``event``. diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index c04f925..31fa45e 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -873,6 +873,8 @@ class InteractiveShell(SingletonConfigurable): def init_events(self): self.events = EventManager(self, available_events) + self.events.register("pre_execute", self._clear_warning_registry) + def register_post_execute(self, func): """DEPRECATED: Use ip.events.register('post_run_cell', func) @@ -882,6 +884,13 @@ class InteractiveShell(SingletonConfigurable): "ip.events.register('post_run_cell', func) instead.") self.events.register('post_run_cell', func) + def _clear_warning_registry(self): + # clear the warning registry, so that different code blocks with + # overlapping line number ranges don't cause spurious suppression of + # warnings (see gh-6611 for details) + if "__warningregistry__" in self.user_global_ns: + del self.user_global_ns["__warningregistry__"] + #------------------------------------------------------------------------- # Things related to the "main" module #------------------------------------------------------------------------- diff --git a/IPython/core/tests/test_events.py b/IPython/core/tests/test_events.py index e265999..8e8402c 100644 --- a/IPython/core/tests/test_events.py +++ b/IPython/core/tests/test_events.py @@ -25,22 +25,8 @@ class CallbackTests(unittest.TestCase): self.em.trigger('ping_received') self.assertEqual(cb.call_count, 1) - def test_reset(self): - cb = Mock() - self.em.register('ping_received', cb) - self.em.reset('ping_received') - self.em.trigger('ping_received') - assert not cb.called - - def test_reset_all(self): - cb = Mock() - self.em.register('ping_received', cb) - self.em.reset_all() - self.em.trigger('ping_received') - assert not cb.called - def test_cb_error(self): cb = Mock(side_effect=ValueError) self.em.register('ping_received', cb) with tt.AssertPrints("Error in callback"): - self.em.trigger('ping_received') \ No newline at end of file + self.em.trigger('ping_received') diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index 4d95a68..1e8bfae 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -301,7 +301,10 @@ class InteractiveShellTestCase(unittest.TestCase): assert post_explicit.called finally: # remove post-exec - ip.events.reset_all() + ip.events.unregister('pre_run_cell', pre_explicit) + ip.events.unregister('pre_execute', pre_always) + ip.events.unregister('post_run_cell', post_explicit) + ip.events.unregister('post_execute', post_always) def test_silent_noadvance(self): """run_cell(silent=True) doesn't advance execution_count""" @@ -840,3 +843,17 @@ class TestSyntaxErrorTransformer(unittest.TestCase): +def test_warning_suppression(): + ip.run_cell("import warnings") + try: + with tt.AssertPrints("UserWarning: asdf", channel="stderr"): + ip.run_cell("warnings.warn('asdf')") + # Here's the real test -- if we run that again, we should get the + # warning again. Traditionally, each warning was only issued once per + # IPython session (approximately), even if the user typed in new and + # different code that should have also triggered the warning, leading + # to much confusion. + with tt.AssertPrints("UserWarning: asdf", channel="stderr"): + ip.run_cell("warnings.warn('asdf')") + finally: + ip.run_cell("del warnings")