From e55aab95786e0e9fb36a9a1122d2d0fb3d2403cd Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 11 Sep 2023 00:16:59 +0200 Subject: [PATCH] gh-109230: test_pyexpat no longer depends on the current directory (#109233) Fix test_pyexpat.test_exception(): it can now be run from a directory different than Python source code directory. Before, the test failed in this case. Skip the test if Modules/pyexpat.c source is not available. Skip also the test on Python implementations other than CPython. --- Lib/test/test_pyexpat.py | 72 ++++++++++++------- ...-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst | 5 ++ 2 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index abe1ad517d2246..41f4d172f8d057 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -1,13 +1,15 @@ # XXX TypeErrors on calling handlers, or on bad return values from a # handler, are obscure and unhelpful. -from io import BytesIO import os import platform import sys import sysconfig import unittest import traceback +from io import BytesIO +from test import support +from test.support import os_helper from xml.parsers import expat from xml.parsers.expat import errors @@ -439,37 +441,59 @@ def test7(self): # Test handling of exception from callback: class HandlerExceptionTest(unittest.TestCase): def StartElementHandler(self, name, attrs): - raise RuntimeError(name) + raise RuntimeError(f'StartElementHandler: <{name}>') def check_traceback_entry(self, entry, filename, funcname): - self.assertEqual(os.path.basename(entry[0]), filename) - self.assertEqual(entry[2], funcname) + self.assertEqual(os.path.basename(entry.filename), filename) + self.assertEqual(entry.name, funcname) + @support.cpython_only def test_exception(self): + # gh-66652: test _PyTraceback_Add() used by pyexpat.c to inject frames + + # Change the current directory to the Python source code directory + # if it is available. + src_dir = sysconfig.get_config_var('abs_builddir') + if src_dir: + have_source = os.path.isdir(src_dir) + else: + have_source = False + if have_source: + with os_helper.change_cwd(src_dir): + self._test_exception(have_source) + else: + self._test_exception(have_source) + + def _test_exception(self, have_source): + # Use path relative to the current directory which should be the Python + # source code directory (if it is available). + PYEXPAT_C = os.path.join('Modules', 'pyexpat.c') + parser = expat.ParserCreate() parser.StartElementHandler = self.StartElementHandler try: parser.Parse(b"", True) - self.fail() - except RuntimeError as e: - self.assertEqual(e.args[0], 'a', - "Expected RuntimeError for element 'a', but" + \ - " found %r" % e.args[0]) - # Check that the traceback contains the relevant line in pyexpat.c - entries = traceback.extract_tb(e.__traceback__) - self.assertEqual(len(entries), 3) - self.check_traceback_entry(entries[0], - "test_pyexpat.py", "test_exception") - self.check_traceback_entry(entries[1], - "pyexpat.c", "StartElement") - self.check_traceback_entry(entries[2], - "test_pyexpat.py", "StartElementHandler") - if (sysconfig.is_python_build() - and not (sys.platform == 'win32' and platform.machine() == 'ARM') - and not is_emscripten - and not is_wasi - ): - self.assertIn('call_with_frame("StartElement"', entries[1][3]) + + self.fail("the parser did not raise RuntimeError") + except RuntimeError as exc: + self.assertEqual(exc.args[0], 'StartElementHandler: ', exc) + entries = traceback.extract_tb(exc.__traceback__) + + self.assertEqual(len(entries), 3, entries) + self.check_traceback_entry(entries[0], + "test_pyexpat.py", "_test_exception") + self.check_traceback_entry(entries[1], + os.path.basename(PYEXPAT_C), + "StartElement") + self.check_traceback_entry(entries[2], + "test_pyexpat.py", "StartElementHandler") + + # Check that the traceback contains the relevant line in + # Modules/pyexpat.c. Skip the test if Modules/pyexpat.c is not + # available. + if have_source and os.path.exists(PYEXPAT_C): + self.assertIn('call_with_frame("StartElement"', + entries[1].line) # Test Current* members: diff --git a/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst b/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst new file mode 100644 index 00000000000000..18e1e85242005a --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst @@ -0,0 +1,5 @@ +Fix ``test_pyexpat.test_exception()``: it can now be run from a directory +different than Python source code directory. Before, the test failed in this +case. Skip the test if Modules/pyexpat.c source is not available. Skip also +the test on Python implementations other than CPython. Patch by Victor +Stinner.