summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2018-05-20 05:48:12 (GMT)
committerGitHub <noreply@github.com>2018-05-20 05:48:12 (GMT)
commitf5e7b1999f46e592d42dfab51563ea5411946fb7 (patch)
tree3001498a55273fc45ac4d2c7b393190d4d2dbd42
parent8ae8e6af37f29163ee263e293570cb892dc5b5d5 (diff)
downloadcpython-f5e7b1999f46e592d42dfab51563ea5411946fb7.zip
cpython-f5e7b1999f46e592d42dfab51563ea5411946fb7.tar.gz
cpython-f5e7b1999f46e592d42dfab51563ea5411946fb7.tar.bz2
bpo-23722: Raise a RuntimeError for absent __classcell__. (GH-6931)
A DeprecationWarning was emitted in Python 3.6-3.7.
-rw-r--r--Doc/reference/datamodel.rst3
-rw-r--r--Doc/whatsnew/3.8.rst5
-rw-r--r--Lib/test/test_super.py44
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2018-05-17-13-06-36.bpo-23722.xisqZk.rst4
-rw-r--r--Python/bltinmodule.c19
5 files changed, 24 insertions, 51 deletions
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index cc8dc95..855f241 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 11538e2..9aad908 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 cb2d7c3..5d94372 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 @@ class TestSuper(unittest.TestCase):
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 @@ class TestSuper(unittest.TestCase):
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 0000000..dfd1e79
--- /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 839258b..88a4bf9 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;
}
}
}