Skip to content

Commit df8d2cd

Browse files
pierreglaserpitrou
authored andcommitted
bpo-35911: add cell constructor (GH-11771)
Add a cell constructor, expose the cell type in the types module.
1 parent f289084 commit df8d2cd

File tree

6 files changed

+71
-2
lines changed

6 files changed

+71
-2
lines changed

Doc/library/types.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ Standard names are defined for the following types:
136136
The type for code objects such as returned by :func:`compile`.
137137

138138

139+
.. data:: CellType
140+
141+
The type for cell objects: such objects are used as containers for
142+
a function's free variables.
143+
144+
.. versionadded:: 3.8
145+
146+
139147
.. data:: MethodType
140148

141149
The type of methods of user-defined class instances.

Doc/reference/datamodel.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,9 @@ Callable types
539539
the value of the cell, as well as set the value.
540540

541541
Additional information about a function's definition can be retrieved from its
542-
code object; see the description of internal types below.
542+
code object; see the description of internal types below. The
543+
:data:`cell <types.CellType>` type can be accessed in the :mod:`types`
544+
module.
543545

544546
Instance methods
545547
.. index::

Lib/test/test_funcattrs.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ def f(): print(a)
8383
self.assertEqual(c[0].__class__.__name__, "cell")
8484
self.cannot_set_attr(f, "__closure__", c, AttributeError)
8585

86+
def test_cell_new(self):
87+
cell_obj = types.CellType(1)
88+
self.assertEqual(cell_obj.cell_contents, 1)
89+
90+
cell_obj = types.CellType()
91+
msg = "shouldn't be able to read an empty cell"
92+
with self.assertRaises(ValueError, msg=msg):
93+
cell_obj.cell_contents
94+
8695
def test_empty_cell(self):
8796
def f(): print(a)
8897
try:

Lib/types.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ def _f(): pass
1515
MappingProxyType = type(type.__dict__)
1616
SimpleNamespace = type(sys.implementation)
1717

18+
def _cell_factory():
19+
a = 1
20+
def f():
21+
nonlocal a
22+
return f.__closure__[0]
23+
CellType = type(_cell_factory())
24+
1825
def _g():
1926
yield 1
2027
GeneratorType = type(_g())
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Enable the creation of cell objects by adding a ``cell.__new__`` method, and
2+
expose the type ``cell`` in ``Lib/types.py`` under the name CellType. Patch by
3+
Pierre Glaser.

Objects/cellobject.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,37 @@ PyCell_New(PyObject *obj)
2020
return (PyObject *)op;
2121
}
2222

23+
PyDoc_STRVAR(cell_new_doc,
24+
"cell([contents])\n"
25+
"--\n"
26+
"\n"
27+
"Create a new cell object.\n"
28+
"\n"
29+
" contents\n"
30+
" the contents of the cell. If not specified, the cell will be empty,\n"
31+
" and \n further attempts to access its cell_contents attribute will\n"
32+
" raise a ValueError.");
33+
34+
35+
static PyObject *
36+
cell_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
37+
{
38+
PyObject *return_value = NULL;
39+
PyObject *obj = NULL;
40+
41+
if (!_PyArg_NoKeywords("cell", kwargs)) {
42+
goto exit;
43+
}
44+
/* min = 0: we allow the cell to be empty */
45+
if (!PyArg_UnpackTuple(args, "cell", 0, 1, &obj)) {
46+
goto exit;
47+
}
48+
return_value = PyCell_New(obj);
49+
50+
exit:
51+
return return_value;
52+
}
53+
2354
PyObject *
2455
PyCell_Get(PyObject *op)
2556
{
@@ -146,7 +177,7 @@ PyTypeObject PyCell_Type = {
146177
0, /* tp_setattro */
147178
0, /* tp_as_buffer */
148179
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
149-
0, /* tp_doc */
180+
cell_new_doc, /* tp_doc */
150181
(traverseproc)cell_traverse, /* tp_traverse */
151182
(inquiry)cell_clear, /* tp_clear */
152183
cell_richcompare, /* tp_richcompare */
@@ -156,4 +187,13 @@ PyTypeObject PyCell_Type = {
156187
0, /* tp_methods */
157188
0, /* tp_members */
158189
cell_getsetlist, /* tp_getset */
190+
0, /* tp_base */
191+
0, /* tp_dict */
192+
0, /* tp_descr_get */
193+
0, /* tp_descr_set */
194+
0, /* tp_dictoffset */
195+
0, /* tp_init */
196+
0, /* tp_alloc */
197+
(newfunc)cell_new, /* tp_new */
198+
0, /* tp_free */
159199
};

0 commit comments

Comments
 (0)