As per discussion on python-dev, descriptors defined in C with a NULL setter
now raise AttributeError instead of TypeError, for consistency with their
pure-Python equivalent.
diff --git a/Misc/NEWS b/Misc/NEWS
index ec30734..01a1c73 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@
 Core and builtins
 -----------------
 
+- Descriptors defined in C with a PyGetSetDef structure, where the setter is
+  NULL, now raise an AttributeError when attempting to set or delete the
+  attribute.  Previously a TypeError was raised, but this was inconsistent
+  with the equivalent pure-Python implementation.
+
 - It is now safe to call PyGILState_Release() before
   PyEval_InitThreads() (note that if there is reason to believe there
   are multiple threads around you still must call PyEval_InitThreads()
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 7d523cf..4aa1313 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -144,7 +144,7 @@
 		return res;
 	if (descr->d_getset->get != NULL)
 		return descr->d_getset->get(obj, descr->d_getset->closure);
-	PyErr_Format(PyExc_TypeError,
+	PyErr_Format(PyExc_AttributeError,
 		     "attribute '%.300s' of '%.100s' objects is not readable",
 		     descr_name((PyDescrObject *)descr),
 		     descr->d_type->tp_name);
@@ -199,7 +199,7 @@
 	if (descr->d_getset->set != NULL)
 		return descr->d_getset->set(obj, value,
 					    descr->d_getset->closure);
-	PyErr_Format(PyExc_TypeError,
+	PyErr_Format(PyExc_AttributeError,
 		     "attribute '%.300s' of '%.100s' objects is not writable",
 		     descr_name((PyDescrObject *)descr),
 		     descr->d_type->tp_name);