Add a custom __str__ method to KeyError that applies repr() to the
missing key.  (Also added a guard to SyntaxError__str__ to prevent
calling PyString_Check(NULL).)
diff --git a/Lib/test/output/test_exceptions b/Lib/test/output/test_exceptions
index e1e146a..28a7aa8 100644
--- a/Lib/test/output/test_exceptions
+++ b/Lib/test/output/test_exceptions
@@ -10,7 +10,7 @@
 ImportError
 spam
 IndexError
-spam
+'spam'
 KeyError
 spam
 KeyboardInterrupt
diff --git a/Python/exceptions.c b/Python/exceptions.c
index 24ea25d..3f07089 100644
--- a/Python/exceptions.c
+++ b/Python/exceptions.c
@@ -785,7 +785,7 @@
     /* XXX -- do all the additional formatting with filename and
        lineno here */
 
-    if (PyString_Check(str)) {
+    if (str != NULL && PyString_Check(str)) {
 	int have_filename = 0;
 	int have_lineno = 0;
 	char *buffer = NULL;
@@ -844,6 +844,44 @@
 };
 
 
+static PyObject *
+KeyError__str__(PyObject *self, PyObject *args)
+{
+    PyObject *argsattr;
+    PyObject *result;
+
+    if (!PyArg_ParseTuple(args, "O:__str__", &self))
+	return NULL;
+
+    if (!(argsattr = PyObject_GetAttrString(self, "args")))
+	return NULL;
+
+    /* If args is a tuple of exactly one item, apply repr to args[0].
+       This is done so that e.g. the exception raised by {}[''] prints
+         KeyError: ''
+       rather than the confusing
+         KeyError
+       alone.  The downside is that if KeyError is raised with an explanatory
+       string, that string will be displayed in quotes.  Too bad.
+       If args is anything else, use the default Exception__str__().
+    */
+    if (PyTuple_Check(argsattr) && PyTuple_GET_SIZE(argsattr) == 1) {
+	PyObject *key = PyTuple_GET_ITEM(argsattr, 0);
+	result = PyObject_Repr(key);
+    }
+    else
+	result = Exception__str__(self, args);
+
+    Py_DECREF(argsattr);
+    return result;
+}
+
+static PyMethodDef KeyError_methods[] = {
+    {"__str__",  KeyError__str__, METH_VARARGS},
+    {NULL, NULL}
+};
+
+
 static
 int get_int(PyObject *exc, const char *name, int *value)
 {
@@ -1617,7 +1655,7 @@
  {"IndexError",         &PyExc_IndexError,     &PyExc_LookupError,
   IndexError__doc__},
  {"KeyError",           &PyExc_KeyError,       &PyExc_LookupError,
-  KeyError__doc__},
+  KeyError__doc__, KeyError_methods},
  {"ArithmeticError",    &PyExc_ArithmeticError, 0, ArithmeticError__doc__},
  {"OverflowError",      &PyExc_OverflowError,     &PyExc_ArithmeticError,
   OverflowError__doc__},