summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Glaser <pierreglaser@msn.com>2019-02-07 19:36:48 (GMT)
committerAntoine Pitrou <pitrou@free.fr>2019-02-07 19:36:48 (GMT)
commitdf8d2cde63c865446468351f8f648e1c7bd45109 (patch)
tree1cc555d57319990602a4987cbf21ee225c4ff2a1
parentf289084c83190cc72db4a70c58f007ec62e75247 (diff)
downloadcpython-df8d2cde63c865446468351f8f648e1c7bd45109.zip
cpython-df8d2cde63c865446468351f8f648e1c7bd45109.tar.gz
cpython-df8d2cde63c865446468351f8f648e1c7bd45109.tar.bz2
bpo-35911: add cell constructor (GH-11771)
Add a cell constructor, expose the cell type in the types module.
-rw-r--r--Doc/library/types.rst8
-rw-r--r--Doc/reference/datamodel.rst4
-rw-r--r--Lib/test/test_funcattrs.py9
-rw-r--r--Lib/types.py7
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-02-06-17-50-59.bpo-35911.oiWE8.rst3
-rw-r--r--Objects/cellobject.c42
6 files changed, 71 insertions, 2 deletions
diff --git a/Doc/library/types.rst b/Doc/library/types.rst
index b19aa02..07c3a2e 100644
--- a/Doc/library/types.rst
+++ b/Doc/library/types.rst
@@ -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.
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 83e1d23..9961aee 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -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::
diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py
index 35fd657..11d68cc 100644
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -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:
diff --git a/Lib/types.py b/Lib/types.py
index ce4652f..53b588d 100644
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -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
index 0000000..458ccb4
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-02-06-17-50-59.bpo-35911.oiWE8.rst
@@ -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.
diff --git a/Objects/cellobject.c b/Objects/cellobject.c
index 86bebb9..4e359f8 100644
--- a/Objects/cellobject.c
+++ b/Objects/cellobject.c
@@ -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 */
};