Jiwon Seo's PEP 3102 implementation.
See SF#1549670.
The compiler package has not yet been updated.
diff --git a/Lib/compiler/ast.py b/Lib/compiler/ast.py
index 0be36a4..d21905f 100644
--- a/Lib/compiler/ast.py
+++ b/Lib/compiler/ast.py
@@ -487,11 +487,12 @@
         return "From(%s, %s, %s)" % (repr(self.modname), repr(self.names), repr(self.level))
 
 class Function(Node):
-    def __init__(self, decorators, name, argnames, defaults, flags, doc, code, lineno=None):
+    def __init__(self, decorators, name, argnames, defaults, kwonlyargs, flags, doc, code, lineno=None):
         self.decorators = decorators
         self.name = name
         self.argnames = argnames
         self.defaults = defaults
+        self.kwonlyargs = kwonlyargs
         self.flags = flags
         self.doc = doc
         self.code = code
@@ -509,6 +510,7 @@
         children.append(self.name)
         children.append(self.argnames)
         children.extend(flatten(self.defaults))
+        children.append(self.kwonlyargs)
         children.append(self.flags)
         children.append(self.doc)
         children.append(self.code)
@@ -523,7 +525,7 @@
         return tuple(nodelist)
 
     def __repr__(self):
-        return "Function(%s, %s, %s, %s, %s, %s, %s)" % (repr(self.decorators), repr(self.name), repr(self.argnames), repr(self.defaults), repr(self.flags), repr(self.doc), repr(self.code))
+        return "Function(%s, %s, %s, %s, %s, %s, %s, %s)" % (repr(self.decorators), repr(self.name), repr(self.argnames), repr(self.defaults), repr(self.kwonlyargs), repr(self.flags), repr(self.doc), repr(self.code))
 
 class GenExpr(Node):
     def __init__(self, code, lineno=None):
@@ -531,6 +533,7 @@
         self.lineno = lineno
         self.argnames = ['.0']
         self.varargs = self.kwargs = None
+        self.kwonlyargs = ()
 
 
     def getChildren(self):
@@ -713,9 +716,10 @@
         return "Keyword(%s, %s)" % (repr(self.name), repr(self.expr))
 
 class Lambda(Node):
-    def __init__(self, argnames, defaults, flags, code, lineno=None):
+    def __init__(self, argnames, defaults, kwonlyargs, flags, code, lineno=None):
         self.argnames = argnames
         self.defaults = defaults
+        self.kwonlyargs = kwonlyargs
         self.flags = flags
         self.code = code
         self.lineno = lineno
@@ -730,6 +734,7 @@
         children = []
         children.append(self.argnames)
         children.extend(flatten(self.defaults))
+        children.append(self.kwonlyargs)
         children.append(self.flags)
         children.append(self.code)
         return tuple(children)
@@ -741,7 +746,7 @@
         return tuple(nodelist)
 
     def __repr__(self):
-        return "Lambda(%s, %s, %s, %s)" % (repr(self.argnames), repr(self.defaults), repr(self.flags), repr(self.code))
+        return "Lambda(%s, %s, %s, %s, %s)" % (repr(self.argnames), repr(self.defaults), repr(self.kwonlyargs), repr(self.flags), repr(self.code))
 
 class LeftShift(Node):
     def __init__(self, (left, right), lineno=None):
diff --git a/Lib/compiler/pyassem.py b/Lib/compiler/pyassem.py
index 5e3eb30..7f44d46 100644
--- a/Lib/compiler/pyassem.py
+++ b/Lib/compiler/pyassem.py
@@ -313,13 +313,15 @@
 class PyFlowGraph(FlowGraph):
     super_init = FlowGraph.__init__
 
-    def __init__(self, name, filename, args=(), optimized=0, klass=None):
+    def __init__(self, name, filename,
+                 args=(), kwonlyargs={}, optimized=0, klass=None):
         self.super_init()
         self.name = name
         self.filename = filename
         self.docstring = None
         self.args = args # XXX
         self.argcount = getArgCount(args)
+        self.kwonlyargs = kwonlyargs
         self.klass = klass
         if optimized:
             self.flags = CO_OPTIMIZED | CO_NEWLOCALS
@@ -595,7 +597,9 @@
         argcount = self.argcount
         if self.flags & CO_VARKEYWORDS:
             argcount = argcount - 1
-        return new.code(argcount, nlocals, self.stacksize, self.flags,
+        kwonlyargcount = len(self.kwonlyargs)
+        return new.code(argcount, kwonlyargcount,
+                        nlocals, self.stacksize, self.flags,
                         self.lnotab.getCode(), self.getConsts(),
                         tuple(self.names), tuple(self.varnames),
                         self.filename, self.name, self.lnotab.firstline,
@@ -804,7 +808,8 @@
     def CALL_FUNCTION_VAR_KW(self, argc):
         return self.CALL_FUNCTION(argc)-2
     def MAKE_FUNCTION(self, argc):
-        return -argc
+        hi, lo = divmod(argc, 256)
+        return -(lo + hi * 2)
     def MAKE_CLOSURE(self, argc):
         # XXX need to account for free variables too!
         return -argc
diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py
index 83d0481..b08a307 100644
--- a/Lib/compiler/pycodegen.py
+++ b/Lib/compiler/pycodegen.py
@@ -378,6 +378,12 @@
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
+        for keyword in node.kwonlyargs:
+            default = keyword.expr
+            if isinstance(default, ast.EmptyNode):
+                continue
+            self.emit('LOAD_CONST', keyword.name)
+            self.visit(default)
         for default in node.defaults:
             self.visit(default)
         self._makeClosure(gen, len(node.defaults))
@@ -1320,7 +1326,9 @@
             name = func.name
 
         args, hasTupleArg = generateArgList(func.argnames)
+        kwonlyargs = generateKwonlyArgList(func.kwonlyargs)
         self.graph = pyassem.PyFlowGraph(name, func.filename, args,
+                                         kwonlyargs=kwonlyargs,
                                          optimized=1)
         self.isLambda = isLambda
         self.super_init()
@@ -1456,6 +1464,13 @@
             raise ValueError, "unexpect argument type:", elt
     return args + extra, count
 
+def generateKwonlyArgList(keywordOnlyArgs):
+    kwonlyargs = {}
+    for elt in keywordOnlyArgs:
+        assert isinstance(elt, ast.Keyword)
+        kwonlyargs[elt.name] = elt.expr
+    return kwonlyargs
+    
 def findOp(node):
     """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
     v = OpFinder()
diff --git a/Lib/compiler/transformer.py b/Lib/compiler/transformer.py
index 0ffb597..7b1e31c 100644
--- a/Lib/compiler/transformer.py
+++ b/Lib/compiler/transformer.py
@@ -250,9 +250,9 @@
         args = nodelist[-3][2]
 
         if args[0] == symbol.varargslist:
-            names, defaults, flags = self.com_arglist(args[1:])
+            names, defaults, kwonlyargs, flags = self.com_arglist(args[1:])
         else:
-            names = defaults = ()
+            names = defaults = kwonlyargs = ()
             flags = 0
         doc = self.get_docstring(nodelist[-1])
 
@@ -263,21 +263,23 @@
             assert isinstance(code, Stmt)
             assert isinstance(code.nodes[0], Discard)
             del code.nodes[0]
-        return Function(decorators, name, names, defaults, flags, doc, code,
-                     lineno=lineno)
+        return Function(decorators, name, names, defaults,
+                        kwonlyargs, flags, doc, code, lineno=lineno)
 
     def lambdef(self, nodelist):
         # lambdef: 'lambda' [varargslist] ':' test
         if nodelist[2][0] == symbol.varargslist:
-            names, defaults, flags = self.com_arglist(nodelist[2][1:])
+            names, defaults, kwonlyargs, flags = \
+                                self.com_arglist(nodelist[2][1:])
         else:
-            names = defaults = ()
+            names = defaults = kwonlyargs = ()
             flags = 0
 
         # code for lambda
         code = self.com_node(nodelist[-1])
 
-        return Lambda(names, defaults, flags, code, lineno=nodelist[1][2])
+        return Lambda(names, defaults, kwonlyargs,
+                      flags, code, lineno=nodelist[1][2])
     old_lambdef = lambdef
 
     def classdef(self, nodelist):
@@ -783,13 +785,37 @@
         # ('const', xxxx)) Nodes)
         return Discard(Const(None))
 
+    def keywordonlyargs(self, nodelist):
+        # (',' NAME ['=' test])*
+        #      ^^^
+        # ------+
+        kwonlyargs = []
+        i = 0
+        while i < len(nodelist):
+            default = EmptyNode()
+            node = nodelist[i]
+            #assert node[0] == token.COMMA
+            #node = nodelist[i+1]
+            if i+1 < len(nodelist) and nodelist[i+1][0] == token.EQUAL:
+                assert i+2 < len(nodelist)
+                default = self.com_node(nodelist[i+2])
+                i += 2
+            if node[0] == token.DOUBLESTAR:
+                return kwonlyargs, i
+            elif node[0] == token.NAME:
+                kwonlyargs.append(Keyword(node[1], default, lineno=node[2]))
+                i += 2
+        return kwonlyargs, i
+        
     def com_arglist(self, nodelist):
         # varargslist:
-        #     (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
-        #   | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+        #     (fpdef ['=' test] ',')*
+        #      ('*' [NAME] (',' NAME '=' test)* [',' '**' NAME] | '**' NAME)
+        #      | fpdef ['=' test] (',' fpdef ['=' test])* [',']
         # fpdef: NAME | '(' fplist ')'
         # fplist: fpdef (',' fpdef)* [',']
         names = []
+        kwonlyargs = []
         defaults = []
         flags = 0
 
@@ -799,10 +825,22 @@
             if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
                 if node[0] == token.STAR:
                     node = nodelist[i+1]
-                    if node[0] == token.NAME:
+                    if node[0] == token.NAME: # vararg
                         names.append(node[1])
                         flags = flags | CO_VARARGS
                         i = i + 3
+                    else: # no vararg
+                        assert node[0] == token.COMMA
+                        i += 1
+                    #elif node[0] == token.COMMA:
+                    #    i += 1
+                    #    kwonlyargs, skip = self.keywordonlyargs(nodelist[i:])
+                    #    i += skip
+                    if nodelist[i][0] == token.NAME:
+                        kwonlyargs, skip = self.keywordonlyargs(nodelist[i:])
+                        i += skip
+
+                print "kwonlyargs:", kwonlyargs
 
                 if i < len(nodelist):
                     # should be DOUBLESTAR
@@ -831,7 +869,8 @@
             # skip the comma
             i = i + 1
 
-        return names, defaults, flags
+        print "names:", names, "defaults:", defaults, "kwonlyargs:", kwonlyargs, "flags:", flags
+        return names, defaults, kwonlyargs, flags
 
     def com_fpdef(self, node):
         # fpdef: NAME | '(' fplist ')'