From cc7eba1894beae94288a963b76ce89d7c1eff1a7 Mon Sep 17 00:00:00 2001 From: scoder Date: Fri, 6 Mar 2026 23:15:05 +0100 Subject: [PATCH] Tests: Clean up builtins after running IPython tests (GH-7553) If useful in more places, most of this can be moved into CythonTest. Closes https://github.com/cython/cython/issues/7075 Supersedes https://github.com/cython/cython/pull/7078 --- Cython/Build/Tests/TestIpythonMagic.py | 54 +++++++++++++++++--------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/Cython/Build/Tests/TestIpythonMagic.py b/Cython/Build/Tests/TestIpythonMagic.py index 86f5c1a059b..7036ef10f83 100644 --- a/Cython/Build/Tests/TestIpythonMagic.py +++ b/Cython/Build/Tests/TestIpythonMagic.py @@ -3,36 +3,21 @@ """Tests for the Cython magics extension.""" +import builtins import os import io import sys from contextlib import contextmanager -from unittest import skipIf +from unittest import skipIf, SkipTest from Cython.Build import IpythonMagic from Cython.TestUtils import CythonTest from Cython.Compiler.Annotate import AnnotationCCodeWriter -try: - import IPython.testing.globalipapp -except ImportError: - # Disable tests and fake helpers for initialisation below. - def skip_if_not_installed(_): - return None -else: - def skip_if_not_installed(c): - return c # not using IPython's decorators here because they depend on "nose" skip_win32 = skipIf(sys.platform == 'win32', "Skip on Windows") -try: - # disable IPython history thread before it gets started to avoid having to clean it up - from IPython.core.history import HistoryManager - HistoryManager.enabled = False -except ImportError: - pass - @contextmanager def capture_output(): @@ -94,14 +79,45 @@ def doit(): ''' -@skip_if_not_installed class TestIPythonMagic(CythonTest): + _orig_builtins = None @classmethod def setUpClass(cls): - CythonTest.setUpClass() + super().setUpClass() + + # IPython modifies the builtins, so keep a clean copy before the import. + orig_builtins = dict(builtins.__dict__) + + try: + import IPython.testing.globalipapp + except ImportError as exc: + # Disable tests and fake helpers for initialisation below. + raise SkipTest(f"IPython is not installed: {exc}") + + try: + # disable IPython history thread before it gets started to avoid having to clean it up + from IPython.core.history import HistoryManager + HistoryManager.enabled = False + except ImportError: + pass + + cls._orig_builtins = orig_builtins cls._ip = IPython.testing.globalipapp.get_ipython() + @classmethod + def tearDownClass(cls): + # Clean up builtins from IPython left-overs. + if cls._orig_builtins: + for name in list(vars(builtins)): + if name not in cls._orig_builtins: + delattr(builtins, name) + for name, value in cls._orig_builtins.items(): + if getattr(builtins, name, None) is not value: + setattr(builtins, name, value) + + super().tearDownClass() + def setUp(self): CythonTest.setUp(self) self._ip.extension_manager.load_extension('cython')