From 08d54c0e367b535fd88aca5273fd09e5e70d08f8 2021-04-09 05:23:25 From: Matthias Bussonnier Date: 2021-04-09 05:23:25 Subject: [PATCH] Finish fixing the at-exit spurious failures. Mostly due to concurrent file access, and late calling --- diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 5905ace..6742a1c 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -3771,6 +3771,22 @@ class InteractiveShell(SingletonConfigurable): raise TypeError("%s is neither a string nor a macro." % target, codeobj) + def _atexit_once(self): + """ + At exist operation that need to be called at most once. + Second call to this function per instance will do nothing. + """ + + if not getattr(self, "_atexit_once_called", False): + self._atexit_once_called = True + # Clear all user namespaces to release all references cleanly. + self.reset(new_session=False) + # Close the history session (this stores the end time and line count) + # this must be *before* the tempfile cleanup, in case of temporary + # history db + self.history_manager.end_session() + self.history_manager = None + #------------------------------------------------------------------------- # Things related to IPython exiting #------------------------------------------------------------------------- @@ -3785,13 +3801,7 @@ class InteractiveShell(SingletonConfigurable): code that has the appropriate information, rather than trying to clutter """ - # Clear all user namespaces to release all references cleanly. - self.reset(new_session=False) - # Close the history session (this stores the end time and line count) - # this must be *before* the tempfile cleanup, in case of temporary - # history db - self.history_manager.end_session() - del self.history_manager + self._atexit_once() # Cleanup all tempfiles and folders left around for tfile in self.tempfiles: diff --git a/IPython/core/tests/test_pylabtools.py b/IPython/core/tests/test_pylabtools.py index 75b103f..5a83423 100644 --- a/IPython/core/tests/test_pylabtools.py +++ b/IPython/core/tests/test_pylabtools.py @@ -146,8 +146,16 @@ def test_import_pylab(): nt.assert_true('plt' in ns) nt.assert_equal(ns['np'], np) +from traitlets.config import Config + + class TestPylabSwitch(object): class Shell(InteractiveShell): + def init_history(self): + """Sets up the command history, and starts regular autosaves.""" + self.config.HistoryManager.hist_file = ":memory:" + super().init_history() + def enable_gui(self, gui): pass @@ -179,6 +187,7 @@ class TestPylabSwitch(object): matplotlib.rcParamsOrig = self._saved_rcParamsOrig def test_qt(self): + s = self.Shell() gui, backend = s.enable_matplotlib(None) nt.assert_equal(gui, 'qt') diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 324246a..0fa9028 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -615,6 +615,13 @@ class TerminalInteractiveShell(InteractiveShell): self.restore_term_title() + # try to call some at-exit operation optimistically as some things can't + # be done during interpreter shutdown. this is technically inaccurate as + # this make mainlool not re-callable, but that should be a rare if not + # in existent use case. + + self._atexit_once() + _inputhook = None def inputhook(self, context):