optimise Py3-style metaclass also when other keywords are provided
authorStefan Behnel <scoder@users.berlios.de>
Sat, 20 Nov 2010 16:38:38 +0000 (17:38 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Sat, 20 Nov 2010 16:38:38 +0000 (17:38 +0100)
Cython/Compiler/Nodes.py
tests/run/metaclass.pyx

index a25033cea2f4c3062d971c7931f6488a1fd027c6..c56fab707184e510f423116164c42776b0cc03fc 100644 (file)
@@ -2959,22 +2959,27 @@ class PyClassDefNode(ClassDefNode):
             self.py3_style_class = True
             self.bases = bases
             self.metaclass = None
-            if keyword_args and not starstar_arg and len(keyword_args.key_value_pairs) == 1:
-                item = keyword_args.key_value_pairs[0]
-                if item.key.value == 'metaclass':
-                    # special case: we already know the metaclass and
-                    # it's the only kwarg, so we don't need to do the
-                    # "build kwargs, find metaclass" dance at runtime
-                    self.metaclass = item.value
-                    self.mkw = ExprNodes.NullNode(pos)
-            if self.metaclass is None:
+            if keyword_args and not starstar_arg:
+                for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]:
+                    if item.key.value == 'metaclass':
+                        if self.metaclass is not None:
+                            error(item.pos, "keyword argument 'metaclass' passed multiple times")
+                        # special case: we already know the metaclass,
+                        # so we don't need to do the "build kwargs,
+                        # find metaclass" dance at runtime
+                        self.metaclass = item.value
+                        del keyword_args.key_value_pairs[i]
+            if starstar_arg or (keyword_args and keyword_args.key_value_pairs):
                 self.mkw = ExprNodes.KeywordArgsNode(
                     pos, keyword_args = keyword_args, starstar_arg = starstar_arg)
+            else:
+                self.mkw = ExprNodes.NullNode(pos)
+            if self.metaclass is None:
                 self.metaclass = ExprNodes.PyClassMetaclassNode(
                     pos, mkw = self.mkw, bases = self.bases)
             self.dict = ExprNodes.PyClassNamespaceNode(pos, name = name,
                         doc = doc_node, metaclass = self.metaclass, bases = self.bases,
-                        mkw = self.mkw)
+                        mkw = self.mkw)
             self.classobj = ExprNodes.Py3ClassNode(pos, name = name,
                     bases = self.bases, dict = self.dict, doc = doc_node,
                     metaclass = self.metaclass, mkw = self.mkw)
index 764c37fb7980634c9e9779185780fc92ae00cbf8..6e2fe0a88e100e99f7712de2a3610b59a9539069 100644 (file)
@@ -66,7 +66,8 @@ class Py3Base(type):
     def __prepare__(*args, **kwargs):
         return ODict()
 
-@cython.test_assert_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
+@cython.test_fail_if_path_exists("//PyClassMetaclassNode")
+@cython.test_assert_path_exists("//Py3ClassNode")
 class Py3Foo(object, metaclass=Py3Base, foo=123):
     """
     >>> obj = Py3Foo()