Skip to content

Commit

Permalink
bpo-35911: add cell constructor (GH-11771)
Browse files Browse the repository at this point in the history
Add a cell constructor, expose the cell type in the types module.
  • Loading branch information
pierreglaser authored and pitrou committed Feb 7, 2019
1 parent f289084 commit df8d2cd
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 2 deletions.
8 changes: 8 additions & 0 deletions Doc/library/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_funcattrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ def f(): print(a)
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:
Expand Down
7 changes: 7 additions & 0 deletions Lib/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ def _f(): pass
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())
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
42 changes: 41 additions & 1 deletion Objects/cellobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 */
Expand All @@ -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 */
};

0 comments on commit df8d2cd

Please sign in to comment.