From 64505a1f6c0af4574e17e823b27ffe24eca44df5 Mon Sep 17 00:00:00 2001 From: Lisa Roach Date: Thu, 8 Jun 2017 04:43:26 -0700 Subject: [PATCH] bpo-30486: Allow setting cell value (#1840) The cell_contents attribute of the cell object is now writable. --- Doc/reference/datamodel.rst | 6 ++++++ Lib/test/test_funcattrs.py | 20 ++++++++++++++++++++ Misc/NEWS | 8 +++++--- Objects/cellobject.c | 11 ++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 9708688c5ce..24a2618b01e 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -510,6 +510,9 @@ Callable types | :attr:`__closure__` | ``None`` or a tuple of cells | Read-only | | | that contain bindings for the | | | | function's free variables. | | + | | See below for information on | | + | | the ``cell_contents`` | | + | | attribute. | | +-------------------------+-------------------------------+-----------+ | :attr:`__annotations__` | A dict containing annotations | Writable | | | of parameters. The keys of | | @@ -530,6 +533,9 @@ Callable types implementation only supports function attributes on user-defined functions. Function attributes on built-in functions may be supported in the future.* + A cell object has the attribute ``cell_contents``. This can be used to get + 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. diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 8f481bb64e1..35fd657ec0b 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -93,6 +93,26 @@ def f(): print(a) self.fail("shouldn't be able to read an empty cell") a = 12 + def test_set_cell(self): + a = 12 + def f(): return a + c = f.__closure__ + c[0].cell_contents = 9 + self.assertEqual(c[0].cell_contents, 9) + self.assertEqual(f(), 9) + self.assertEqual(a, 9) + del c[0].cell_contents + try: + c[0].cell_contents + except ValueError: + pass + else: + self.fail("shouldn't be able to read an empty cell") + with self.assertRaises(NameError): + f() + with self.assertRaises(UnboundLocalError): + print(a) + def test___name__(self): self.assertEqual(self.b.__name__, 'b') self.b.__name__ = 'c' diff --git a/Misc/NEWS b/Misc/NEWS index 0bc33bb2345..29c0005638d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ What's New in Python 3.7.0 alpha 1? Core and Builtins ----------------- +- bpo-30486: Allows setting cell values for __closure__. Patch by Lisa Roach. + +- bpo-30537: itertools.islice now accepts integer-like objects (having + an __index__ method) as start, stop, and slice arguments + - bpo-25324: Tokens needed for parsing in Python moved to C. ``COMMENT``, ``NL`` and ``ENCODING``. This way the tokens and tok_names in the token module don't get changed when you import the tokenize module. @@ -128,9 +133,6 @@ Core and Builtins - bpo-29546: Improve from-import error message with location -- bpo-30537: itertools.islice now accepts integer-like objects (having - an __index__ method) as start, stop, and slice arguments - - Issue #29319: Prevent RunMainFromImporter overwriting sys.path[0]. - Issue #29337: Fixed possible BytesWarning when compare the code objects. diff --git a/Objects/cellobject.c b/Objects/cellobject.c index 9f4eddb8468..6af93b00308 100644 --- a/Objects/cellobject.c +++ b/Objects/cellobject.c @@ -140,8 +140,17 @@ cell_get_contents(PyCellObject *op, void *closure) return op->ob_ref; } +int +cell_set_contents(PyCellObject *op, PyObject *obj) +{ + Py_XINCREF(obj); + Py_XSETREF(op->ob_ref, obj); + return 0; +} + static PyGetSetDef cell_getsetlist[] = { - {"cell_contents", (getter)cell_get_contents, NULL}, + {"cell_contents", (getter)cell_get_contents, + (setter)cell_set_contents, NULL}, {NULL} /* sentinel */ };