Skip to content

Commit bcb68cc

Browse files
committed
pythongh-109230: test_pyexpat no longer depends on the current directory
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. Moreover, skip the test if Modules/pyexpat.c doesn't exist and other Python implementations other than CPython.
1 parent 71b6e26 commit bcb68cc

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

Lib/test/test_pyexpat.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
# XXX TypeErrors on calling handlers, or on bad return values from a
22
# handler, are obscure and unhelpful.
33

4-
from io import BytesIO
4+
import contextlib
55
import os
66
import platform
77
import sys
88
import sysconfig
99
import unittest
1010
import traceback
11+
from io import BytesIO
12+
from test import support
13+
from test.support import os_helper
1114

1215
from xml.parsers import expat
1316
from xml.parsers.expat import errors
@@ -439,37 +442,57 @@ def test7(self):
439442
# Test handling of exception from callback:
440443
class HandlerExceptionTest(unittest.TestCase):
441444
def StartElementHandler(self, name, attrs):
442-
raise RuntimeError(name)
445+
raise RuntimeError(f'StartElementHandler: <{name}>')
443446

444447
def check_traceback_entry(self, entry, filename, funcname):
445-
self.assertEqual(os.path.basename(entry[0]), filename)
446-
self.assertEqual(entry[2], funcname)
448+
self.assertEqual(os.path.basename(entry.filename), filename)
449+
self.assertEqual(entry.name, funcname)
450+
451+
def _test_exception(self, have_source):
452+
# Use path relative to the current directory which should be the Python
453+
# source code directory (if it is available).
454+
PYEXPAT_C = os.path.join('Modules', 'pyexpat.c')
447455

448-
def test_exception(self):
449456
parser = expat.ParserCreate()
450457
parser.StartElementHandler = self.StartElementHandler
451458
try:
452459
parser.Parse(b"<a><b><c/></b></a>", True)
453-
self.fail()
454-
except RuntimeError as e:
455-
self.assertEqual(e.args[0], 'a',
456-
"Expected RuntimeError for element 'a', but" + \
457-
" found %r" % e.args[0])
458-
# Check that the traceback contains the relevant line in pyexpat.c
459-
entries = traceback.extract_tb(e.__traceback__)
460-
self.assertEqual(len(entries), 3)
461-
self.check_traceback_entry(entries[0],
462-
"test_pyexpat.py", "test_exception")
463-
self.check_traceback_entry(entries[1],
464-
"pyexpat.c", "StartElement")
465-
self.check_traceback_entry(entries[2],
466-
"test_pyexpat.py", "StartElementHandler")
467-
if (sysconfig.is_python_build()
468-
and not (sys.platform == 'win32' and platform.machine() == 'ARM')
469-
and not is_emscripten
470-
and not is_wasi
471-
):
472-
self.assertIn('call_with_frame("StartElement"', entries[1][3])
460+
461+
self.fail("the parser did not raise RuntimeError")
462+
except RuntimeError as exc:
463+
self.assertEqual(exc.args[0], 'StartElementHandler: <a>', exc)
464+
entries = traceback.extract_tb(exc.__traceback__)
465+
466+
self.assertEqual(len(entries), 3, entries)
467+
self.check_traceback_entry(entries[0],
468+
"test_pyexpat.py", "_test_exception")
469+
self.check_traceback_entry(entries[1],
470+
os.path.basename(PYEXPAT_C),
471+
"StartElement")
472+
self.check_traceback_entry(entries[2],
473+
"test_pyexpat.py", "StartElementHandler")
474+
475+
# Check that the traceback contains the relevant line in
476+
# Modules/pyexpat.c. Skip the test if Modules/pyexpat.c is not
477+
# available.
478+
if have_source and os.path.exists(PYEXPAT_C):
479+
self.assertIn('call_with_frame("StartElement"',
480+
entries[1].line)
481+
482+
@support.cpython_only
483+
def test_exception(self):
484+
# gh-66652: test _PyTraceback_Add() used by pyexpat.c to inject frames
485+
486+
# Change the current directory to the Python source code directory
487+
# if it is available.
488+
src_dir = sysconfig.get_config_var('abs_builddir')
489+
have_source = os.path.isdir(src_dir)
490+
if have_source:
491+
cm = os_helper.change_cwd(src_dir)
492+
else:
493+
cm = contextlib.nullcontext()
494+
with cm:
495+
self._test_exception(have_source)
473496

474497

475498
# Test Current* members:

0 commit comments

Comments
 (0)