8000 bpo-23722: Raise a RuntimeError for absent __classcell__. (GH-6931) · python/cpython@f5e7b19 · GitHub
[go: up one dir, main page]

Skip to content

Commit f5e7b19

Browse files
bpo-23722: Raise a RuntimeError for absent __classcell__. (GH-6931)
A DeprecationWarning was emitted in Python 3.6-3.7.
1 parent 8ae8e6a commit f5e7b19

File tree

5 files changed

+24
-51
lines changed

5 files changed

+24
-51
lines changed

Doc/reference/datamodel.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,8 +1967,7 @@ current call is identified based on the first argument passed to the method.
19671967
as a ``__classcell__`` entry in the class namespace. If present, this must
19681968
be propagated up to the ``type.__new__`` call in order for the class to be
19691969
initialised correctly.
1970-
Failing to do so will result in a :exc:`DeprecationWarning` in Python 3.6,
1971-
and a :exc:`RuntimeError` in Python 3.8.
1970+
Failing to do so will result in a :exc:`RuntimeError` in Python 3.8.
19721971

19731972
When using the default metaclass :class:`type`, or any metaclass that ultimately
19741973
calls ``type.__new__``, the following additional customisation steps are

Doc/whatsnew/3.8.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ Changes in the Python API
146146
a database if it does not exist.
147147
(Contributed by Serhiy Storchaka in :issue:`32749`.)
148148

149+
* A :exc:`RuntimeError` is now raised when the custom metaclass doesn't
150+
provide the ``__classcell__`` entry in the namespace passed to
151+
``type.__new__``. A :exc:`DeprecationWarning` was emitted in Python
152+
3.6--3.7. (Contributed by Serhiy Storchaka in :issue:`23722`.)
153+
149154

150155
CPython bytecode changes
151156
------------------------

Lib/test/test_super.py

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"""Unit tests for zero-argument super() & related machinery."""
22

33
import unittest
4-
import warnings
5-
from test.support import check_warnings
64

75

86
class A:
@@ -173,14 +171,10 @@ def __new__(cls, name, bases, namespace):
173171
test_namespace = namespace
174172
return None
175173

176-
# This case shouldn't trigger the __classcell__ deprecation warning
177-
with check_warnings() as w:
178-
warnings.simplefilter("always", DeprecationWarning)
179-
class A(metaclass=Meta):
180-
@staticmethod
181-
def f():
182-
return __class__
183-
self.assertEqual(w.warnings, [])
174+
class A(metaclass=Meta):
175+
@staticmethod
176+
def f():
177+
return __class__
184178

185179
self.assertIs(A, None)
186180

@@ -244,37 +238,19 @@ def __new__(cls, name, bases, namespace):
244238
namespace.pop('__classcell__', None)
245239
return super().__new__(cls, name, bases, namespace)
246240

247-
# The default case should continue to work without any warnings
248-
with check_warnings() as w:
249-
warnings.simplefilter("always", DeprecationWarning)
250-
class WithoutClassRef(metaclass=Meta):
251-
pass
252-
self.assertEqual(w.warnings, [])
241+
# The default case should continue to work without any errors
242+
class WithoutClassRef(metaclass=Meta):
243+
pass
253244

254245
# With zero-arg super() or an explicit __class__ reference, we expect
255-
# __build_class__ to emit a DeprecationWarning complaining that
246+
# __build_class__ to raise a RuntimeError complaining that
256247
# __class__ was not set, and asking if __classcell__ was propagated
257248
# to type.__new__.
258-
# In Python 3.7, that warning will become a RuntimeError.
259-
expected_warning = (
260-
'__class__ not set.*__classcell__ propagated',
261-
DeprecationWarning
262-
)
263-
with check_warnings(expected_warning):
264-
warnings.simplefilter("always", DeprecationWarning)
249+
expected_error = '__class__ not set.*__classcell__ propagated'
250+
with self.assertRaisesRegex(RuntimeError, expected_error):
265251
class WithClassRef(metaclass=Meta):
266252
def f(self):
267253
return __class__
268-
# Check __class__ still gets set despite the warning
269-
self.assertIs(WithClassRef().f(), WithClassRef)
270-
271-
# Check the warning is turned into an error as expected
272-
with warnings.catch_warnings():
273-
warnings.simplefilter("error", DeprecationWarning)
274-
with self.assertRaises(DeprecationWarning):
275-
class WithClassRef(metaclass=Meta):
276-
def f(self):
277-
return __class__
278254

279255
def test___classcell___overwrite(self):
280256
# See issue #23722
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
A :exc:`RuntimeError` is now raised when the custom metaclass doesn't
2+
provide the ``__classcell__`` entry in the namespace passed to
3+
``type.__new__``. A :exc:`DeprecationWarning` was emitted in Python
4+
3.6--3.7.

Python/bltinmodule.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -254,30 +254,19 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
254254
if (cls != NULL && PyType_Check(cls) && PyCell_Check(cell)) {
255255
PyObject *cell_cls = PyCell_GET(cell);
256256
if (cell_cls != cls) {
257-
/* TODO: In 3.7, DeprecationWarning will become RuntimeError.
258-
* At that point, cell_error won't be needed.
259-
*/
260-
int cell_error;
261257
if (cell_cls == NULL) {
262258
const char *msg =
263259
"__class__ not set defining %.200R as %.200R. "
264260
"Was __classcell__ propagated to type.__new__?";
265-
cell_error = PyErr_WarnFormat(
266-
PyExc_DeprecationWarning, 1, msg, name, cls);
261+
PyErr_Format(PyExc_RuntimeError, msg, name, cls);
267262
} else {
268263
const char *msg =
269264
"__class__ set to %.200R defining %.200R as %.200R";
270265
PyErr_Format(PyExc_TypeError, msg, cell_cls, name, cls);
271-
cell_error = 1;
272-
}
273-
if (cell_error) {
274-
Py_DECREF(cls);
275-
cls = NULL;
276-
goto error;
277-
} else {
278-
/* Fill in the cell, since type.__new__ didn't do it */
279-
PyCell_Set(cell, cls);
280266
}
267+
Py_DECREF(cls);
268+
cls = NULL;
269+
goto error;
281270
}
282271
}
283272
}

0 commit comments

Comments
 (0)
0