bpo-30486: Allow setting cell value (#1840)

The cell_contents attribute of the cell object is now writable.
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 9708688..24a2618 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -510,6 +510,9 @@
       | :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 @@
       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 8f481bb..35fd657 100644
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -93,6 +93,26 @@
             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 0bc33bb..29c0005 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,11 @@
 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 @@
 
 - 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 9f4eddb..6af93b0 100644
--- a/Objects/cellobject.c
+++ b/Objects/cellobject.c
@@ -140,8 +140,17 @@
     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 */
 };