Skip to content

test_pyexpat.MemoryProtectionTest fails when Python was built with expat 2.7.1 but runs with 2.7.2 #144739

@hroncok

Description

@hroncok

Bug report

Bug description:

  1. Build Python with system expat 2.7.1
  2. Update expat to e.g. 2.7.2
  3. test_pyexpat.MemoryProtectionTest fail with AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerMaximumAmplification'

======================================================================
ERROR: test_set_activation_threshold__fail_for_subparser (test.test_pyexpat.MemoryProtectionTest.test_set_activation_threshold__fail_for_subparser)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 966, in test_set_activation_threshold__fail_for_subparser
    self.assert_root_parser_failure(setter, 12345)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 920, in assert_root_parser_failure
    self.assertRaisesRegex(expat.ExpatError, msg, func, *args, **kwargs)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 1338, in assertRaisesRegex
    return context.handle('assertRaisesRegex', args, kwargs)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle
    callable_obj(*args, **kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1018, in set_activation_threshold
    return parser.SetAllocTrackerActivationThreshold(threshold)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerActivationThreshold'

======================================================================
ERROR: test_set_activation_threshold__invalid_threshold_range (test.test_pyexpat.MemoryProtectionTest.test_set_activation_threshold__invalid_threshold_range)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 960, in test_set_activation_threshold__invalid_threshold_range
    self.assertRaises(OverflowError, setter, _testcapi.ULLONG_MAX + 1)
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 795, in assertRaises
    return context.handle('assertRaises', args, kwargs)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle
    callable_obj(*args, **kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1018, in set_activation_threshold
    return parser.SetAllocTrackerActivationThreshold(threshold)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerActivationThreshold'

======================================================================
ERROR: test_set_activation_threshold__invalid_threshold_type (test.test_pyexpat.MemoryProtectionTest.test_set_activation_threshold__invalid_threshold_type)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 951, in test_set_activation_threshold__invalid_threshold_type
    self.assertRaises(TypeError, setter, 1.0)
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 795, in assertRaises
    return context.handle('assertRaises', args, kwargs)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle
    callable_obj(*args, **kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1018, in set_activation_threshold
    return parser.SetAllocTrackerActivationThreshold(threshold)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerActivationThreshold'

======================================================================
ERROR: test_set_activation_threshold__threshold_not_reached (test.test_pyexpat.MemoryProtectionTest.test_set_activation_threshold__threshold_not_reached)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1036, in test_set_activation_threshold__threshold_not_reached
    self.set_activation_threshold(parser, pow(10, 5))
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1018, in set_activation_threshold
    return parser.SetAllocTrackerActivationThreshold(threshold)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerActivationThreshold'

======================================================================
ERROR: test_set_activation_threshold__threshold_reached (test.test_pyexpat.MemoryProtectionTest.test_set_activation_threshold__threshold_reached)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1026, in test_set_activation_threshold__threshold_reached
    self.set_activation_threshold(parser, 3)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1018, in set_activation_threshold
    return parser.SetAllocTrackerActivationThreshold(threshold)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerActivationThreshold'

======================================================================
ERROR: test_set_maximum_amplification__amplification_exceeded (test.test_pyexpat.MemoryProtectionTest.test_set_maximum_amplification__amplification_exceeded)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1046, in test_set_maximum_amplification__amplification_exceeded
    self.set_activation_threshold(parser, 0)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1018, in set_activation_threshold
    return parser.SetAllocTrackerActivationThreshold(threshold)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerActivationThreshold'

======================================================================
ERROR: test_set_maximum_amplification__amplification_not_exceeded (test.test_pyexpat.MemoryProtectionTest.test_set_maximum_amplification__amplification_not_exceeded)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1056, in test_set_maximum_amplification__amplification_not_exceeded
    self.set_activation_threshold(parser, 0)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1018, in set_activation_threshold
    return parser.SetAllocTrackerActivationThreshold(threshold)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerActivationThreshold'

======================================================================
ERROR: test_set_maximum_amplification__fail_for_subparser (test.test_pyexpat.MemoryProtectionTest.test_set_maximum_amplification__fail_for_subparser)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1000, in test_set_maximum_amplification__fail_for_subparser
    self.assert_root_parser_failure(setter, 123.45)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 920, in assert_root_parser_failure
    self.assertRaisesRegex(expat.ExpatError, msg, func, *args, **kwargs)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 1338, in assertRaisesRegex
    return context.handle('assertRaisesRegex', args, kwargs)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle
    callable_obj(*args, **kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1021, in set_maximum_amplification
    return parser.SetAllocTrackerMaximumAmplification(max_factor)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerMaximumAmplification'

======================================================================
ERROR: test_set_maximum_amplification__infinity (test.test_pyexpat.MemoryProtectionTest.test_set_maximum_amplification__infinity)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 979, in test_set_maximum_amplification__infinity
    self.assertIsNone(self.set_maximum_amplification(parser, inf))
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1021, in set_maximum_amplification
    return parser.SetAllocTrackerMaximumAmplification(max_factor)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerMaximumAmplification'

======================================================================
ERROR: test_set_maximum_amplification__invalid_max_factor_range (test.test_pyexpat.MemoryProtectionTest.test_set_maximum_amplification__invalid_max_factor_range)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 993, in test_set_maximum_amplification__invalid_max_factor_range
    self.assertRaisesRegex(expat.ExpatError, msg, setter, float('nan'))
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 1338, in assertRaisesRegex
    return context.handle('assertRaisesRegex', args, kwargs)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle
    callable_obj(*args, **kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1021, in set_maximum_amplification
    return parser.SetAllocTrackerMaximumAmplification(max_factor)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerMaximumAmplification'

======================================================================
ERROR: test_set_maximum_amplification__invalid_max_factor_type (test.test_pyexpat.MemoryProtectionTest.test_set_maximum_amplification__invalid_max_factor_type)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 985, in test_set_maximum_amplification__invalid_max_factor_type
    self.assertRaises(TypeError, setter, None)
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 795, in assertRaises
    return context.handle('assertRaises', args, kwargs)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle
    callable_obj(*args, **kwargs)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.13/test/test_pyexpat.py", line 1021, in set_maximum_amplification
    return parser.SetAllocTrackerMaximumAmplification(max_factor)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'pyexpat.xmlparser' object has no attribute 'SetAllocTrackerMaximumAmplification'

----------------------------------------------------------------------
Ran 11 tests in 0.013s

Updating expat to a newer version, unlike downgrading, should generally be a safe operation. The test has a @unittest.skipIf(expat.version_info < (2, 7, 2), "requires Expat >= 2.7.2") decorator. But in fact it should rather check for "was compiled with pyexpat < 2.7.2".

I belive this could be fixed by changing the skip to a hasattr based check and will submit a PR.

CPython versions tested on:

3.13, 3.14, 3.15

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions