Jiwon Seo's PEP 3102 implementation.
See SF#1549670.
The compiler package has not yet been updated.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index ca156e8..6d5daa8 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -41,7 +41,8 @@
 
 
 PyCodeObject *
-PyCode_New(int argcount, int nlocals, int stacksize, int flags,
+PyCode_New(int argcount, int kwonlyargcount,
+	   int nlocals, int stacksize, int flags,
 	   PyObject *code, PyObject *consts, PyObject *names,
 	   PyObject *varnames, PyObject *freevars, PyObject *cellvars,
 	   PyObject *filename, PyObject *name, int firstlineno,
@@ -80,6 +81,7 @@
 	co = PyObject_NEW(PyCodeObject, &PyCode_Type);
 	if (co != NULL) {
 		co->co_argcount = argcount;
+		co->co_kwonlyargcount = kwonlyargcount;
 		co->co_nlocals = nlocals;
 		co->co_stacksize = stacksize;
 		co->co_flags = flags;
@@ -112,6 +114,7 @@
 
 static PyMemberDef code_memberlist[] = {
 	{"co_argcount",	T_INT,		OFF(co_argcount),	READONLY},
+	{"co_kwonlyargcount",	T_INT,	OFF(co_kwonlyargcount),	READONLY},
 	{"co_nlocals",	T_INT,		OFF(co_nlocals),	READONLY},
 	{"co_stacksize",T_INT,		OFF(co_stacksize),	READONLY},
 	{"co_flags",	T_INT,		OFF(co_flags),		READONLY},
@@ -182,6 +185,7 @@
 code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
 	int argcount;
+	int kwonlyargcount;
 	int nlocals;
 	int stacksize;
 	int flags;
@@ -197,8 +201,9 @@
 	int firstlineno;
 	PyObject *lnotab;
 
-	if (!PyArg_ParseTuple(args, "iiiiSO!O!O!SSiS|O!O!:code",
-			      &argcount, &nlocals, &stacksize, &flags,
+	if (!PyArg_ParseTuple(args, "iiiiiSO!O!O!SSiS|O!O!:code",
+			      &argcount, &kwonlyargcount,
+				  &nlocals, &stacksize, &flags,
 			      &code,
 			      &PyTuple_Type, &consts,
 			      &PyTuple_Type, &names,
@@ -216,6 +221,12 @@
 		goto cleanup;
 	}
 
+	if (kwonlyargcount < 0) {
+		PyErr_SetString(
+			PyExc_ValueError,
+			"code: kwonlyargcount must not be negative");
+		goto cleanup;
+	}
 	if (nlocals < 0) {
 		PyErr_SetString(
 			PyExc_ValueError,
@@ -242,7 +253,8 @@
 	if (ourcellvars == NULL)
 		goto cleanup;
 
-	co = (PyObject *)PyCode_New(argcount, nlocals, stacksize, flags,
+	co = (PyObject *)PyCode_New(argcount, kwonlyargcount,
+				    nlocals, stacksize, flags,
 				    code, consts, ournames, ourvarnames,
 				    ourfreevars, ourcellvars, filename,
 				    name, firstlineno, lnotab);
@@ -312,6 +324,8 @@
 	if (eq <= 0) goto unequal;
 	eq = co->co_argcount == cp->co_argcount;
 	if (!eq) goto unequal;
+	eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
+	if (!eq) goto unequal;
 	eq = co->co_nlocals == cp->co_nlocals;
 	if (!eq) goto unequal;
 	eq = co->co_flags == cp->co_flags;
@@ -369,7 +383,8 @@
 	h6 = PyObject_Hash(co->co_cellvars);
 	if (h6 == -1) return -1;
 	h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
-		co->co_argcount ^ co->co_nlocals ^ co->co_flags;
+		co->co_argcount ^ co->co_kwonlyargcount ^
+		co->co_nlocals ^ co->co_flags;
 	if (h == -1) h = -2;
 	return h;
 }
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 1ba74c5..06a4fe9 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -24,6 +24,7 @@
 		op->func_name = ((PyCodeObject *)code)->co_name;
 		Py_INCREF(op->func_name);
 		op->func_defaults = NULL; /* No default arguments */
+		op->func_kwdefaults = NULL; /* No keyword only defaults */
 		op->func_closure = NULL;
 		consts = ((PyCodeObject *)code)->co_consts;
 		if (PyTuple_Size(consts) >= 1) {
@@ -122,6 +123,38 @@
 }
 
 PyObject *
+PyFunction_GetKwDefaults(PyObject *op)
+{
+	if (!PyFunction_Check(op)) {
+		PyErr_BadInternalCall();
+		return NULL;
+	}
+	return ((PyFunctionObject *) op) -> func_kwdefaults;
+}
+
+int
+PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults)
+{
+	if (!PyFunction_Check(op)) {
+		PyErr_BadInternalCall();
+		return -1;
+	}
+	if (defaults == Py_None)
+		defaults = NULL;
+	else if (defaults && PyDict_Check(defaults)) {
+		Py_INCREF(defaults);
+	}
+	else {
+		PyErr_SetString(PyExc_SystemError,
+				"non-dict keyword only default args");
+		return -1;
+	}
+	Py_XDECREF(((PyFunctionObject *)op) -> func_kwdefaults);
+	((PyFunctionObject *) op) -> func_kwdefaults = defaults;
+	return 0;
+}
+
+PyObject *
 PyFunction_GetClosure(PyObject *op)
 {
 	if (!PyFunction_Check(op)) {
@@ -325,10 +358,49 @@
 	return 0;
 }
 
+static PyObject *
+func_get_kwdefaults(PyFunctionObject *op)
+{
+	if (restricted())
+		return NULL;
+	if (op->func_kwdefaults == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+	Py_INCREF(op->func_kwdefaults);
+	return op->func_kwdefaults;
+}
+
+static int
+func_set_kwdefaults(PyFunctionObject *op, PyObject *value)
+{
+	PyObject *tmp;
+    
+	if (restricted())
+		return -1;
+
+	if (value == Py_None)
+		value = NULL;
+	/* Legal to del f.func_defaults.
+	 * Can only set func_kwdefaults to NULL or a dict. */
+	if (value != NULL && !PyDict_Check(value)) {
+		PyErr_SetString(PyExc_TypeError,
+			"func_kwdefaults must be set to a dict object");
+		return -1;
+	}
+	tmp = op->func_kwdefaults;
+	Py_XINCREF(value);
+	op->func_kwdefaults = value;
+	Py_XDECREF(tmp);
+	return 0;
+}
+
 static PyGetSetDef func_getsetlist[] = {
         {"func_code", (getter)func_get_code, (setter)func_set_code},
         {"func_defaults", (getter)func_get_defaults,
 	 (setter)func_set_defaults},
+	{"func_kwdefaults", (getter)func_get_kwdefaults,
+	 (setter)func_set_kwdefaults},
 	{"func_dict", (getter)func_get_dict, (setter)func_set_dict},
 	{"__dict__", (getter)func_get_dict, (setter)func_set_dict},
 	{"func_name", (getter)func_get_name, (setter)func_set_name},
@@ -519,6 +591,7 @@
 		PyFunction_GET_GLOBALS(func), (PyObject *)NULL,
 		&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg),
 		k, nk, d, nd,
+		PyFunction_GET_KW_DEFAULTS(func),
 		PyFunction_GET_CLOSURE(func));
 
 	if (k != NULL)