Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32.4k
Description
I've noticed a discrepancy in the value of thePy_TPFLAGS_MANAGED_DICT
flag constant used inLib/test/test_class.py
.
Summary
The test fileLib/test/test_class.py
defines a local constantPy_TPFLAGS_MANAGED_DICT = (1 << 2)
. However, the canonical definition in the C headerInclude/object.h
isPy_TPFLAGS_MANAGED_DICT = (1 << 4)
.
The existing tests that use this constant pass only coincidentally. They test plain classes which happen to have a flag set at the(1 << 2)
position, but this is not the actual managed dictionary flag.
This can be proven by a test case that uses a__slots__
class. Such a class should not have a managed dictionary, and therefore, a test checking for theMANAGED_DICT
flag should result in0
. However, the test written to check for the incorrect(1 << 2)
flag also results in0
, which causes an assertion to fail, proving the constant is wrong.
Proof of Incorrect Constant
The following test case demonstrates that the(1 << 2)
constant is incorrect. It uses a__slots__
class, which is known not to have a managed dictionary.
The test attempts to assert that this classhas the flag specified by the incorrect(1 << 2)
constant. This assertion fails, providing evidence that the constant is wrong.
# In Lib/test/test_class.pyimportunittestclassTestMisleadingConstant(unittest.TestCase):deftest_slots_class_reveals_flaw_in_constant(self):# The incorrect constant as defined in test_class.pyPy_TPFLAGS_MANAGED_DICT_WRONG= (1<<2)# The correct constant from object.hPy_TPFLAGS_MANAGED_DICT_CORRECT= (1<<4)classNoManagedDict:__slots__= ('a',)# First, confirm that a __slots__ class correctly does NOT have# the true managed dict flag. This assertion passes.self.assertEqual(NoManagedDict.__flags__&Py_TPFLAGS_MANAGED_DICT_CORRECT,0,"A __slots__ class should not have the correct MANAGED_DICT flag (1<<4)" )# Next, try to assert that this class HAS the flag at the (1<<2) position.# This assertion FAILS with "AssertionError: 0 != 4", because a __slots__ class# does not have this flag either.# This failure is the proof that the (1<<2) constant is wrong for this purpose.self.assertEqual(NoManagedDict.__flags__&Py_TPFLAGS_MANAGED_DICT_WRONG,Py_TPFLAGS_MANAGED_DICT_WRONG,"This fails, proving the constant is wrong." )
Reference Links
Incorrect constant in
test_class.py
:cpython/Lib/test/test_class.py
Line 862 in49365bd
Py_TPFLAGS_MANAGED_DICT= (1<<2)
Correct constant definition in
object.h
:Lines 532 to 535 in49365bd
/* Placement of dict (and values) pointers are managed by the VM, not by the type. * The VM will automatically set tp_dictoffset. Implies Py_TPFLAGS_HAVE_GC. */ #definePy_TPFLAGS_MANAGED_DICT (1 << 4)
Proposed Fix
The constantPy_TPFLAGS_MANAGED_DICT
inLib/test/test_class.py
should be updated to(1 << 4)
to match the C header definition.
Additionally, we could add a test case for a class that does not havePy_TPFLAGS_INLINE_VALUES
.
If this analysis seems correct, I would be happy to open a Pull Request to update the constant and add a corresponding test case.