| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -205,6 +205,10 @@ Pending Removal in Python 3.14 | |||
| 205 | 205 | ||
| 206 | 206 | (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) | |
| 207 | 207 | ||
| 208 | + * Creating :c:data:`immutable types <Py_TPFLAGS_IMMUTABLETYPE>` with mutable | ||
| 209 | + bases using the C API. | ||
| 210 | + | ||
| 211 | + | ||
| 208 | 212 | Pending Removal in Future Versions | |
| 209 | 213 | ---------------------------------- | |
| 210 | 214 | ||
@@ -458,6 +462,9 @@ Deprecated | |||
| 458 | 462 | :c:type:`PyConfig` instead. | |
| 459 | 463 | (Contributed by Victor Stinner in :gh:`77782`.) | |
| 460 | 464 | ||
| 465 | + * Creating :c:data:`immutable types <Py_TPFLAGS_IMMUTABLETYPE>` with mutable | ||
| 466 | + bases is deprecated and will be disabled in Python 3.14. | ||
| 467 | + | ||
| 461 | 468 | ||
| 462 | 469 | Removed | |
| 463 | 470 | ------- | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,6 +15,7 @@ | |||
| 15 | 15 | import threading | |
| 16 | 16 | import time | |
| 17 | 17 | import unittest | |
| 18 | + import warnings | ||
| 18 | 19 | import weakref | |
| 19 | 20 | from test import support | |
| 20 | 21 | from test.support import MISSING_C_DOCSTRINGS | |
@@ -644,6 +645,34 @@ def test_pytype_fromspec_with_repeated_slots(self): | |||
| 644 | 645 | with self.assertRaises(SystemError): | |
| 645 | 646 | _testcapi.create_type_from_repeated_slots(variant) | |
| 646 | 647 | ||
| 648 | + def test_immutable_type_with_mutable_base(self): | ||
| 649 | + # Add deprecation warning here so it's removed in 3.14 | ||
| 650 | + warnings._deprecated( | ||
| 651 | + 'creating immutable classes with mutable bases', remove=(3, 14)) | ||
| 652 | + | ||
| 653 | + class MutableBase: | ||
| 654 | + def meth(self): | ||
| 655 | + return 'original' | ||
| 656 | + | ||
| 657 | + with self.assertWarns(DeprecationWarning): | ||
| 658 | + ImmutableSubclass = _testcapi.make_immutable_type_with_base( | ||
| 659 | + MutableBase) | ||
| 660 | + instance = ImmutableSubclass() | ||
| 661 | + | ||
| 662 | + self.assertEqual(instance.meth(), 'original') | ||
| 663 | + | ||
| 664 | + # Cannot override the static type's method | ||
| 665 | + with self.assertRaisesRegex( | ||
| 666 | + TypeError, | ||
| 667 | + "cannot set 'meth' attribute of immutable type"): | ||
| 668 | + ImmutableSubclass.meth = lambda self: 'overridden' | ||
| 669 | + self.assertEqual(instance.meth(), 'original') | ||
| 670 | + | ||
| 671 | + # Can change the method on the mutable base | ||
| 672 | + MutableBase.meth = lambda self: 'changed' | ||
| 673 | + self.assertEqual(instance.meth(), 'changed') | ||
| 674 | + | ||
| 675 | + | ||
| 647 | 676 | def test_pynumber_tobase(self): | |
| 648 | 677 | from _testcapi import pynumber_tobase | |
| 649 | 678 | self.assertEqual(pynumber_tobase(123, 2), '0b1111011') | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Creating :c:data:`immutable types <Py_TPFLAGS_IMMUTABLETYPE>` with mutable | ||
| 2 | + bases is deprecated and is planned to be disabled in Python 3.14. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -365,6 +365,21 @@ create_type_from_repeated_slots(PyObject *self, PyObject *variant_obj) | |||
| 365 | 365 | } | |
| 366 | 366 | ||
| 367 | 367 | ||
| 368 | + | ||
| 369 | + static PyObject * | ||
| 370 | + make_immutable_type_with_base(PyObject *self, PyObject *base) | ||
| 371 | + { | ||
| 372 | + assert(PyType_Check(base)); | ||
| 373 | + PyType_Spec ImmutableSubclass_spec = { | ||
| 374 | + .name = "ImmutableSubclass", | ||
| 375 | + .basicsize = (int)((PyTypeObject*)base)->tp_basicsize, | ||
| 376 | + .slots = empty_type_slots, | ||
| 377 | + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, | ||
| 378 | + }; | ||
| 379 | + return PyType_FromSpecWithBases(&ImmutableSubclass_spec, base); | ||
| 380 | + } | ||
| 381 | + | ||
| 382 | + | ||
| 368 | 383 | static PyMethodDef TestMethods[] = { | |
| 369 | 384 | {"pytype_fromspec_meta", pytype_fromspec_meta, METH_O}, | |
| 370 | 385 | {"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS}, | |
@@ -375,6 +390,7 @@ static PyMethodDef TestMethods[] = { | |||
| 375 | 390 | {"test_from_spec_invalid_metatype_inheritance", | |
| 376 | 391 | test_from_spec_invalid_metatype_inheritance, | |
| 377 | 392 | METH_NOARGS}, | |
| 393 | + {"make_immutable_type_with_base", make_immutable_type_with_base, METH_O}, | ||
| 378 | 394 | {NULL}, | |
| 379 | 395 | }; | |
| 380 | 396 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3676,6 +3676,32 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, | |||
| 3676 | 3676 | goto finally; | |
| 3677 | 3677 | } | |
| 3678 | 3678 | ||
| 3679 | + /* If this is an immutable type, check if all bases are also immutable, | ||
| 3680 | + * and (for now) fire a deprecation warning if not. | ||
| 3681 | + * (This isn't necessary for static types: those can't have heap bases, | ||
| 3682 | + * and only heap types can be mutable.) | ||
| 3683 | + */ | ||
| 3684 | + if (spec->flags & Py_TPFLAGS_IMMUTABLETYPE) { | ||
| 3685 | + for (int i=0; i<PyTuple_GET_SIZE(bases); i++) { | ||
| 3686 | + PyTypeObject *b = (PyTypeObject*)PyTuple_GET_ITEM(bases, i); | ||
| 3687 | + if (!b) { | ||
| 3688 | + goto finally; | ||
| 3689 | + } | ||
| 3690 | + if (!_PyType_HasFeature(b, Py_TPFLAGS_IMMUTABLETYPE)) { | ||
| 3691 | + if (PyErr_WarnFormat( | ||
| 3692 | + PyExc_DeprecationWarning, | ||
| 3693 | + 0, | ||
| 3694 | + "Creating immutable type %s from mutable base %s is " | ||
| 3695 | + "deprecated, and slated to be disallowed in Python 3.14.", | ||
| 3696 | + spec->name, | ||
| 3697 | + b->tp_name)) | ||
| 3698 | + { | ||
| 3699 | + goto finally; | ||
| 3700 | + } | ||
| 3701 | + } | ||
| 3702 | + } | ||
| 3703 | + } | ||
| 3704 | + | ||
| 3679 | 3705 | /* Calculate the metaclass */ | |
| 3680 | 3706 | ||
| 3681 | 3707 | if (!metaclass) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments