Bug report
For example the following program fails with either assert WeirdClass.value == 2 or assert WeirdClass.value == 3 in recent Python versions:
import sys
class Base:
value = 1
class Meta(type):
def mro(cls):
return (cls, Base, object)
class WeirdClass(metaclass=Meta):
pass
assert Base.value == 1
assert WeirdClass.value == 1
Base.value = 2
assert Base.value == 2
assert WeirdClass.value == 2
Base.value = 3
assert Base.value == 3
assert WeirdClass.value == 3
Adding intervening calls to sys _clear_internal_caches() makes the test pass.
| Version |
Result |
| 3.7 |
OK |
| 3.8 |
OK |
| 3.9 |
OK |
| 3.10 |
AssertionError: assert WeirdClass.value == 2 |
| 3.11 |
AssertionError: assert WeirdClass.value == 2 |
| 3.12 |
AssertionError: assert WeirdClass.value == 2 |
| 3.13 |
AssertionError: assert WeirdClass.value == 3 |
| main |
AssertionError: assert WeirdClass.value == 3 |
We have code that checks for this case, but it hasn't worked properly in Python 3.10+:
|
static void |
|
type_mro_modified(PyTypeObject *type, PyObject *bases) { |
|
/* |
|
Check that all base classes or elements of the MRO of type are |
|
able to be cached. This function is called after the base |
|
classes or mro of the type are altered. |
We also have a test that partly covers this case, but doesn't detect the bug:
|
def test_freeze_meta(self): |
|
"""test PyType_Freeze() with overridden MRO""" |
|
type_freeze = _testcapi.type_freeze |
|
|
|
class Base: |
|
value = 1 |
|
|
|
class Meta(type): |
|
def mro(cls): |
|
return (cls, Base, object) |
|
|
|
class FreezeThis(metaclass=Meta): |
|
"""This has `Base` in the MRO, but not tp_bases""" |
|
|
|
self.assertEqual(FreezeThis.value, 1) |
|
|
|
with self.assertRaises(TypeError): |
|
type_freeze(FreezeThis) |
|
|
|
Base.value = 2 |
|
self.assertEqual(FreezeThis.value, 2) |
|
|
|
type_freeze(Base) |
|
with self.assertRaises(TypeError): |
|
Base.value = 3 |
|
type_freeze(FreezeThis) |
|
self.assertEqual(FreezeThis.value, 2) |
Linked PRs
Bug report
For example the following program fails with either
assert WeirdClass.value == 2orassert WeirdClass.value == 3in recent Python versions:Adding intervening calls to
sys _clear_internal_caches()makes the test pass.AssertionError: assert WeirdClass.value == 2AssertionError: assert WeirdClass.value == 2AssertionError: assert WeirdClass.value == 2AssertionError: assert WeirdClass.value == 3AssertionError: assert WeirdClass.value == 3We have code that checks for this case, but it hasn't worked properly in Python 3.10+:
cpython/Objects/typeobject.c
Lines 1107 to 1112 in 5c89adf
We also have a test that partly covers this case, but doesn't detect the bug:
cpython/Lib/test/test_capi/test_type.py
Lines 40 to 66 in 5c89adf
Linked PRs