]> granicus.if.org Git - python/commitdiff
bpo-35911: add cell constructor (GH-11771)
authorPierre Glaser <pierreglaser@msn.com>
Thu, 7 Feb 2019 19:36:48 +0000 (20:36 +0100)
committerAntoine Pitrou <pitrou@free.fr>
Thu, 7 Feb 2019 19:36:48 +0000 (19:36 +0000)
Add a cell constructor, expose the cell type in the types module.

Doc/library/types.rst
Doc/reference/datamodel.rst
Lib/test/test_funcattrs.py
Lib/types.py
Misc/NEWS.d/next/Core and Builtins/2019-02-06-17-50-59.bpo-35911.oiWE8.rst [new file with mode: 0644]
Objects/cellobject.c

index b19aa0273ef52cd4d06382ca89b7e5547c71973b..07c3a2e7f68276db5b81c1ad3603f5d18479698d 100644 (file)
@@ -136,6 +136,14 @@ Standard names are defined for the following types:
    The type for code objects such as returned by :func:`compile`.
 
 
+.. data:: CellType
+
+   The type for cell objects: such objects are used as containers for
+   a function's free variables.
+
+   .. versionadded:: 3.8
+
+
 .. data:: MethodType
 
    The type of methods of user-defined class instances.
index 83e1d239b34a754c72c330f10001a4d2f1498aab..9961aee14e06524606ad62ef576a14c658aa8ad1 100644 (file)
@@ -539,7 +539,9 @@ Callable types
       the value of the cell, as well as set the value.
 
       Additional information about a function's definition can be retrieved from its
-      code object; see the description of internal types below.
+      code object; see the description of internal types below. The
+      :data:`cell <types.CellType>` type can be accessed in the :mod:`types`
+      module.
 
    Instance methods
       .. index::
index 35fd657ec0ba56721ddafd72f5f7c2ff2a8128f3..11d68cc75e208995fca88fd60389bda98401f4bc 100644 (file)
@@ -83,6 +83,15 @@ class FunctionPropertiesTest(FuncAttrsTest):
         self.assertEqual(c[0].__class__.__name__, "cell")
         self.cannot_set_attr(f, "__closure__", c, AttributeError)
 
+    def test_cell_new(self):
+        cell_obj = types.CellType(1)
+        self.assertEqual(cell_obj.cell_contents, 1)
+
+        cell_obj = types.CellType()
+        msg = "shouldn't be able to read an empty cell"
+        with self.assertRaises(ValueError, msg=msg):
+            cell_obj.cell_contents
+
     def test_empty_cell(self):
         def f(): print(a)
         try:
index ce4652f37189763dbce5b3946d53b45d4e076493..53b588da75696bf65ff8b11e3d4ba18b0e14c04c 100644 (file)
@@ -15,6 +15,13 @@ CodeType = type(_f.__code__)
 MappingProxyType = type(type.__dict__)
 SimpleNamespace = type(sys.implementation)
 
+def _cell_factory():
+    a = 1
+    def f():
+        nonlocal a
+    return f.__closure__[0]
+CellType = type(_cell_factory())
+
 def _g():
     yield 1
 GeneratorType = type(_g())
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-02-06-17-50-59.bpo-35911.oiWE8.rst b/Misc/NEWS.d/next/Core and Builtins/2019-02-06-17-50-59.bpo-35911.oiWE8.rst
new file mode 100644 (file)
index 0000000..458ccb4
--- /dev/null
@@ -0,0 +1,3 @@
+Enable the creation of cell objects by adding a ``cell.__new__`` method, and
+expose the type ``cell`` in ``Lib/types.py`` under the name CellType. Patch by
+Pierre Glaser.
index 86bebb9604a579b724af59687435809463a8f48d..4e359f889fdc81ce24b3f5a2816ef7f5146ee9f3 100644 (file)
@@ -20,6 +20,37 @@ PyCell_New(PyObject *obj)
     return (PyObject *)op;
 }
 
+PyDoc_STRVAR(cell_new_doc,
+"cell([contents])\n"
+"--\n"
+"\n"
+"Create a new cell object.\n"
+"\n"
+"  contents\n"
+"    the contents of the cell. If not specified, the cell will be empty,\n"
+"    and \n further attempts to access its cell_contents attribute will\n"
+"    raise a ValueError.");
+
+
+static PyObject *
+cell_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+    PyObject *return_value = NULL;
+    PyObject *obj = NULL;
+
+    if (!_PyArg_NoKeywords("cell", kwargs)) {
+        goto exit;
+    }
+    /* min = 0: we allow the cell to be empty */
+    if (!PyArg_UnpackTuple(args, "cell", 0, 1, &obj)) {
+        goto exit;
+    }
+    return_value = PyCell_New(obj);
+
+exit:
+    return return_value;
+}
+
 PyObject *
 PyCell_Get(PyObject *op)
 {
@@ -146,7 +177,7 @@ PyTypeObject PyCell_Type = {
     0,                                          /* tp_setattro */
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
-    0,                                          /* tp_doc */
+    cell_new_doc,                               /* tp_doc */
     (traverseproc)cell_traverse,                /* tp_traverse */
     (inquiry)cell_clear,                        /* tp_clear */
     cell_richcompare,                           /* tp_richcompare */
@@ -156,4 +187,13 @@ PyTypeObject PyCell_Type = {
     0,                                          /* tp_methods */
     0,                                          /* tp_members */
     cell_getsetlist,                            /* tp_getset */
+    0,                                          /* tp_base */
+    0,                                          /* tp_dict */
+    0,                                          /* tp_descr_get */
+    0,                                          /* tp_descr_set */
+    0,                                          /* tp_dictoffset */
+    0,                                          /* tp_init */
+    0,                                          /* tp_alloc */
+    (newfunc)cell_new,                          /* tp_new */
+    0,                                          /* tp_free */
 };