[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