Skip to content

Commit 102737f

Browse files
committed
gh-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. Skip the test if Modules/pyexpat.c source is not available. Skip also the test on Python implementations other than CPython.
1 parent d6892c2 commit 102737f

File tree

2 files changed

+53
-24
lines changed

2 files changed

+53
-24
lines changed

Lib/test/test_pyexpat.py

+48-24
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
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
54
import os
65
import platform
76
import sys
87
import sysconfig
98
import unittest
109
import traceback
10+
from io import BytesIO
11+
from test import support
12+
from test.support import os_helper
1113

1214
from xml.parsers import expat
1315
from xml.parsers.expat import errors
@@ -439,37 +441,59 @@ def test7(self):
439441
# Test handling of exception from callback:
440442
class HandlerExceptionTest(unittest.TestCase):
441443
def StartElementHandler(self, name, attrs):
442-
raise RuntimeError(name)
444+
raise RuntimeError(f'StartElementHandler: <{name}>')
443445

444446
def check_traceback_entry(self, entry, filename, funcname):
445-
self.assertEqual(os.path.basename(entry[0]), filename)
446-
self.assertEqual(entry[2], funcname)
447+
self.assertEqual(os.path.basename(entry.filename), filename)
448+
self.assertEqual(entry.name, funcname)
447449

450+
@support.cpython_only
448451
def test_exception(self):
452+
# gh-66652: test _PyTraceback_Add() used by pyexpat.c to inject frames
453+
454+
# Change the current directory to the Python source code directory
455+
# if it is available.
456+
src_dir = sysconfig.get_config_var('abs_builddir')
457+
if src_dir:
458+
have_source = os.path.isdir(src_dir)
459+
else:
460+
have_source = False
461+
if have_source:
462+
with os_helper.change_cwd(src_dir):
463+
self._test_exception(have_source)
464+
else:
465+
self._test_exception(have_source)
466+
467+
def _test_exception(self, have_source):
468+
# Use path relative to the current directory which should be the Python
469+
# source code directory (if it is available).
470+
PYEXPAT_C = os.path.join('Modules', 'pyexpat.c')
471+
449472
parser = expat.ParserCreate()
450473
parser.StartElementHandler = self.StartElementHandler
451474
try:
452475
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])
476+
477+
self.fail("the parser did not raise RuntimeError")
478+
except RuntimeError as exc:
479+
self.assertEqual(exc.args[0], 'StartElementHandler: <a>', exc)
480+
entries = traceback.extract_tb(exc.__traceback__)
481+
482+
self.assertEqual(len(entries), 3, entries)
483+
self.check_traceback_entry(entries[0],
484+
"test_pyexpat.py", "_test_exception")
485+
self.check_traceback_entry(entries[1],
486+
os.path.basename(PYEXPAT_C),
487+
"StartElement")
488+
self.check_traceback_entry(entries[2],
489+
"test_pyexpat.py", "StartElementHandler")
490+
491+
# Check that the traceback contains the relevant line in
492+
# Modules/pyexpat.c. Skip the test if Modules/pyexpat.c is not
493+
# available.
494+
if have_source and os.path.exists(PYEXPAT_C):
495+
self.assertIn('call_with_frame("StartElement"',
496+
entries[1].line)
473497

474498

475499
# Test Current* members:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix ``test_pyexpat.test_exception()``: it can now be run from a directory
2+
different than Python source code directory. Before, the test failed in this
3+
case. Skip the test if Modules/pyexpat.c source is not available. Skip also
4+
the test on Python implementations other than CPython. Patch by Victor
5+
Stinner.

0 commit comments

Comments
 (0)