[Python-checkins] bpo-23722: Raise a RuntimeError for absent __classcell__. (GH-6931)
Serhiy Storchaka
webhook-mailer at python.org
Sun May 20 01:48:14 EDT 2018
https://github.com/python/cpython/commit/f5e7b1999f46e592d42dfab51563ea5411946fb7
commit: f5e7b1999f46e592d42dfab51563ea5411946fb7
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-05-20T08:48:12+03:00
summary:
bpo-23722: Raise a RuntimeError for absent __classcell__. (GH-6931)
A DeprecationWarning was emitted in Python 3.6-3.7.
files:
A Misc/NEWS.d/next/Core and Builtins/2018-05-17-13-06-36.bpo-23722.xisqZk.rst
M Doc/reference/datamodel.rst
M Doc/whatsnew/3.8.rst
M Lib/test/test_super.py
M Python/bltinmodule.c
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index cc8dc958a80a..855f2412b139 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1967,8 +1967,7 @@ current call is identified based on the first argument passed to the method.
as a ``__classcell__`` entry in the class namespace. If present, this must
be propagated up to the ``type.__new__`` call in order for the class to be
initialised correctly.
- Failing to do so will result in a :exc:`DeprecationWarning` in Python 3.6,
- and a :exc:`RuntimeError` in Python 3.8.
+ Failing to do so will result in a :exc:`RuntimeError` in Python 3.8.
When using the default metaclass :class:`type`, or any metaclass that ultimately
calls ``type.__new__``, the following additional customisation steps are
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 11538e26691c..9aad908f927f 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -146,6 +146,11 @@ Changes in the Python API
a database if it does not exist.
(Contributed by Serhiy Storchaka in :issue:`32749`.)
+* A :exc:`RuntimeError` is now raised when the custom metaclass doesn't
+ provide the ``__classcell__`` entry in the namespace passed to
+ ``type.__new__``. A :exc:`DeprecationWarning` was emitted in Python
+ 3.6--3.7. (Contributed by Serhiy Storchaka in :issue:`23722`.)
+
CPython bytecode changes
------------------------
diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py
index cb2d7c32236b..5d94372bf6ec 100644
--- a/Lib/test/test_super.py
+++ b/Lib/test/test_super.py
@@ -1,8 +1,6 @@
"""Unit tests for zero-argument super() & related machinery."""
import unittest
-import warnings
-from test.support import check_warnings
class A:
@@ -173,14 +171,10 @@ def __new__(cls, name, bases, namespace):
test_namespace = namespace
return None
- # This case shouldn't trigger the __classcell__ deprecation warning
- with check_warnings() as w:
- warnings.simplefilter("always", DeprecationWarning)
- class A(metaclass=Meta):
- @staticmethod
- def f():
- return __class__
- self.assertEqual(w.warnings, [])
+ class A(metaclass=Meta):
+ @staticmethod
+ def f():
+ return __class__
self.assertIs(A, None)
@@ -244,37 +238,19 @@ def __new__(cls, name, bases, namespace):
namespace.pop('__classcell__', None)
return super().__new__(cls, name, bases, namespace)
- # The default case should continue to work without any warnings
- with check_warnings() as w:
- warnings.simplefilter("always", DeprecationWarning)
- class WithoutClassRef(metaclass=Meta):
- pass
- self.assertEqual(w.warnings, [])
+ # The default case should continue to work without any errors
+ class WithoutClassRef(metaclass=Meta):
+ pass
# With zero-arg super() or an explicit __class__ reference, we expect
- # __build_class__ to emit a DeprecationWarning complaining that
+ # __build_class__ to raise a RuntimeError complaining that
# __class__ was not set, and asking if __classcell__ was propagated
# to type.__new__.
- # In Python 3.7, that warning will become a RuntimeError.
- expected_warning = (
- '__class__ not set.*__classcell__ propagated',
- DeprecationWarning
- )
- with check_warnings(expected_warning):
- warnings.simplefilter("always", DeprecationWarning)
+ expected_error = '__class__ not set.*__classcell__ propagated'
+ with self.assertRaisesRegex(RuntimeError, expected_error):
class WithClassRef(metaclass=Meta):
def f(self):
return __class__
- # Check __class__ still gets set despite the warning
- self.assertIs(WithClassRef().f(), WithClassRef)
-
- # Check the warning is turned into an error as expected
- with warnings.catch_warnings():
- warnings.simplefilter("error", DeprecationWarning)
- with self.assertRaises(DeprecationWarning):
- class WithClassRef(metaclass=Meta):
- def f(self):
- return __class__
def test___classcell___overwrite(self):
# See issue #23722
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-05-17-13-06-36.bpo-23722.xisqZk.rst b/Misc/NEWS.d/next/Core and Builtins/2018-05-17-13-06-36.bpo-23722.xisqZk.rst
new file mode 100644
index 000000000000..dfd1e79786ab
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-05-17-13-06-36.bpo-23722.xisqZk.rst
@@ -0,0 +1,4 @@
+A :exc:`RuntimeError` is now raised when the custom metaclass doesn't
+provide the ``__classcell__`` entry in the namespace passed to
+``type.__new__``. A :exc:`DeprecationWarning` was emitted in Python
+3.6--3.7.
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 839258b87495..88a4bf991d88 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -254,30 +254,19 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
if (cls != NULL && PyType_Check(cls) && PyCell_Check(cell)) {
PyObject *cell_cls = PyCell_GET(cell);
if (cell_cls != cls) {
- /* TODO: In 3.7, DeprecationWarning will become RuntimeError.
- * At that point, cell_error won't be needed.
- */
- int cell_error;
if (cell_cls == NULL) {
const char *msg =
"__class__ not set defining %.200R as %.200R. "
"Was __classcell__ propagated to type.__new__?";
- cell_error = PyErr_WarnFormat(
- PyExc_DeprecationWarning, 1, msg, name, cls);
+ PyErr_Format(PyExc_RuntimeError, msg, name, cls);
} else {
const char *msg =
"__class__ set to %.200R defining %.200R as %.200R";
PyErr_Format(PyExc_TypeError, msg, cell_cls, name, cls);
- cell_error = 1;
- }
- if (cell_error) {
- Py_DECREF(cls);
- cls = NULL;
- goto error;
- } else {
- /* Fill in the cell, since type.__new__ didn't do it */
- PyCell_Set(cell, cls);
}
+ Py_DECREF(cls);
+ cls = NULL;
+ goto error;
}
}
}
More information about the Python-checkins
mailing list