[Python-3000-checkins] r54428 - in python/branches/p3yk: Grammar/Grammar Include/Python-ast.h Include/opcode.h Lib/build_class.py Lib/ctypes/_endian.py Lib/opcode.py Lib/string.py Lib/test/crashers/modify_dict_attr.py Lib/test/leakers/test_selftype.py Lib/test/pickletester.py Lib/test/test_ast.py Lib/test/test_copy.py Lib/test/test_descr.py Lib/test/test_metaclass.py Lib/unittest.py Modules/_bsddb.c Parser/Python.asdl Python/Python-ast.c Python/ast.c Python/bltinmodule.c Python/ceval.c Python/compile.c Python/graminit.c Python/import.c Python/symtable.c

guido.van.rossum python-3000-checkins at python.org
Sun Mar 18 16:42:12 CET 2007


Author: guido.van.rossum
Date: Sun Mar 18 16:41:51 2007
New Revision: 54428

Added:
   python/branches/p3yk/Lib/build_class.py   (contents, props changed)
   python/branches/p3yk/Lib/test/test_metaclass.py   (contents, props changed)
Modified:
   python/branches/p3yk/Grammar/Grammar
   python/branches/p3yk/Include/Python-ast.h
   python/branches/p3yk/Include/opcode.h
   python/branches/p3yk/Lib/ctypes/_endian.py
   python/branches/p3yk/Lib/opcode.py
   python/branches/p3yk/Lib/string.py
   python/branches/p3yk/Lib/test/crashers/modify_dict_attr.py
   python/branches/p3yk/Lib/test/leakers/test_selftype.py
   python/branches/p3yk/Lib/test/pickletester.py
   python/branches/p3yk/Lib/test/test_ast.py
   python/branches/p3yk/Lib/test/test_copy.py
   python/branches/p3yk/Lib/test/test_descr.py
   python/branches/p3yk/Lib/unittest.py
   python/branches/p3yk/Modules/_bsddb.c
   python/branches/p3yk/Parser/Python.asdl
   python/branches/p3yk/Python/Python-ast.c
   python/branches/p3yk/Python/ast.c
   python/branches/p3yk/Python/bltinmodule.c
   python/branches/p3yk/Python/ceval.c
   python/branches/p3yk/Python/compile.c
   python/branches/p3yk/Python/graminit.c
   python/branches/p3yk/Python/import.c
   python/branches/p3yk/Python/symtable.c
Log:
Implement PEP 3115 -- new metaclass syntax and semantics.
The compiler package hasn't been updated yet; test_compiler.py fails.
Otherwise all tests seem to be passing now.  There are no occurrences
of __metaclass__ left in the standard library.
Docs have not been updated.


Modified: python/branches/p3yk/Grammar/Grammar
==============================================================================
--- python/branches/p3yk/Grammar/Grammar	(original)
+++ python/branches/p3yk/Grammar/Grammar	Sun Mar 18 16:41:51 2007
@@ -119,7 +119,7 @@
 testlist: test (',' test)* [',']
 dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [','])
 
-classdef: 'class' NAME ['(' [testlist] ')'] ':' suite
+classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
 
 arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
 argument: test [gen_for] | test '=' test  # Really [keyword '='] test

Modified: python/branches/p3yk/Include/Python-ast.h
==============================================================================
--- python/branches/p3yk/Include/Python-ast.h	(original)
+++ python/branches/p3yk/Include/Python-ast.h	Sun Mar 18 16:41:51 2007
@@ -82,6 +82,9 @@
                 struct {
                         identifier name;
                         asdl_seq *bases;
+                        asdl_seq *keywords;
+                        expr_ty starargs;
+                        expr_ty kwargs;
                         asdl_seq *body;
                 } ClassDef;
                 
@@ -380,8 +383,9 @@
 stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body,
                         asdl_seq * decorators, expr_ty returns, int lineno, int
                         col_offset, PyArena *arena);
-#define ClassDef(a0, a1, a2, a3, a4, a5) _Py_ClassDef(a0, a1, a2, a3, a4, a5)
-stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int
+#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8)
+stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords,
+                     expr_ty starargs, expr_ty kwargs, asdl_seq * body, int
                      lineno, int col_offset, PyArena *arena);
 #define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3)
 stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena);

Modified: python/branches/p3yk/Include/opcode.h
==============================================================================
--- python/branches/p3yk/Include/opcode.h	(original)
+++ python/branches/p3yk/Include/opcode.h	Sun Mar 18 16:41:51 2007
@@ -59,8 +59,9 @@
 #define BINARY_OR	66
 #define INPLACE_POWER	67
 #define GET_ITER	68
-
+#define STORE_LOCALS	69
 #define PRINT_EXPR	70
+#define LOAD_BUILD_CLASS 71
 
 #define INPLACE_LSHIFT	75
 #define INPLACE_RSHIFT	76
@@ -69,14 +70,13 @@
 #define INPLACE_OR	79
 #define BREAK_LOOP	80
 #define WITH_CLEANUP    81
-#define LOAD_LOCALS	82
+
 #define RETURN_VALUE	83
 #define IMPORT_STAR	84
 #define MAKE_BYTES	85
 #define YIELD_VALUE	86
 #define POP_BLOCK	87
 #define END_FINALLY	88
-#define BUILD_CLASS	89
 
 #define HAVE_ARGUMENT	90	/* Opcodes from here have an argument: */
 
@@ -120,10 +120,10 @@
 #define RAISE_VARARGS	130	/* Number of raise arguments (1, 2 or 3) */
 /* CALL_FUNCTION_XXX opcodes defined below depend on this definition */
 #define CALL_FUNCTION	131	/* #args + (#kwargs<<8) */
-#define MAKE_FUNCTION	132	/* #defaults */
+#define MAKE_FUNCTION	132	/* #defaults + #kwdefaults<<8 + #annotations<<16 */
 #define BUILD_SLICE 	133	/* Number of items */
 
-#define MAKE_CLOSURE    134     /* #free vars */
+#define MAKE_CLOSURE    134     /* same as MAKE_FUNCTION */
 #define LOAD_CLOSURE    135     /* Load free variable from closure */
 #define LOAD_DEREF      136     /* Load and dereference from closure cell */ 
 #define STORE_DEREF     137     /* Store into cell */ 

Added: python/branches/p3yk/Lib/build_class.py
==============================================================================

Modified: python/branches/p3yk/Lib/ctypes/_endian.py
==============================================================================
--- python/branches/p3yk/Lib/ctypes/_endian.py	(original)
+++ python/branches/p3yk/Lib/ctypes/_endian.py	Sun Mar 18 16:41:51 2007
@@ -42,18 +42,16 @@
 
     LittleEndianStructure = Structure
 
-    class BigEndianStructure(Structure):
+    class BigEndianStructure(Structure, metaclass=_swapped_meta):
         """Structure with big endian byte order"""
-        __metaclass__ = _swapped_meta
         _swappedbytes_ = None
 
 elif sys.byteorder == "big":
     _OTHER_ENDIAN = "__ctype_le__"
 
     BigEndianStructure = Structure
-    class LittleEndianStructure(Structure):
+    class LittleEndianStructure(Structure, metaclass=_swapped_meta):
         """Structure with little endian byte order"""
-        __metaclass__ = _swapped_meta
         _swappedbytes_ = None
 
 else:

Modified: python/branches/p3yk/Lib/opcode.py
==============================================================================
--- python/branches/p3yk/Lib/opcode.py	(original)
+++ python/branches/p3yk/Lib/opcode.py	Sun Mar 18 16:41:51 2007
@@ -98,8 +98,10 @@
 def_op('BINARY_OR', 66)
 def_op('INPLACE_POWER', 67)
 def_op('GET_ITER', 68)
+def_op('STORE_LOCALS', 69)
 
 def_op('PRINT_EXPR', 70)
+def_op('LOAD_BUILD_CLASS', 71)
 
 def_op('INPLACE_LSHIFT', 75)
 def_op('INPLACE_RSHIFT', 76)
@@ -108,14 +110,13 @@
 def_op('INPLACE_OR', 79)
 def_op('BREAK_LOOP', 80)
 def_op('WITH_CLEANUP', 81)
-def_op('LOAD_LOCALS', 82)
+
 def_op('RETURN_VALUE', 83)
 def_op('IMPORT_STAR', 84)
 def_op('MAKE_BYTES', 85)
 def_op('YIELD_VALUE', 86)
 def_op('POP_BLOCK', 87)
 def_op('END_FINALLY', 88)
-def_op('BUILD_CLASS', 89)
 
 HAVE_ARGUMENT = 90              # Opcodes from here have an argument:
 

Modified: python/branches/p3yk/Lib/string.py
==============================================================================
--- python/branches/p3yk/Lib/string.py	(original)
+++ python/branches/p3yk/Lib/string.py	Sun Mar 18 16:41:51 2007
@@ -119,9 +119,8 @@
         cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
 
 
-class Template:
+class Template(metaclass=_TemplateMetaclass):
     """A string class for supporting $-substitutions."""
-    __metaclass__ = _TemplateMetaclass
 
     delimiter = '$'
     idpattern = r'[_a-z][_a-z0-9]*'

Modified: python/branches/p3yk/Lib/test/crashers/modify_dict_attr.py
==============================================================================
--- python/branches/p3yk/Lib/test/crashers/modify_dict_attr.py	(original)
+++ python/branches/p3yk/Lib/test/crashers/modify_dict_attr.py	Sun Mar 18 16:41:51 2007
@@ -7,11 +7,10 @@
 class type_with_modifiable_dict(Y, type):
     pass
 
-class MyClass(object):
+class MyClass(object, metaclass=type_with_modifiable_dict):
     """This class has its __dict__ attribute completely exposed:
     user code can read, reassign and even delete it.
     """
-    __metaclass__ = type_with_modifiable_dict
 
 
 if __name__ == '__main__':

Modified: python/branches/p3yk/Lib/test/leakers/test_selftype.py
==============================================================================
--- python/branches/p3yk/Lib/test/leakers/test_selftype.py	(original)
+++ python/branches/p3yk/Lib/test/leakers/test_selftype.py	Sun Mar 18 16:41:51 2007
@@ -6,8 +6,8 @@
 def leak():
     class T(type):
         pass
-    class U(type):
-        __metaclass__ = T
+    class U(type, metaclass=T):
+        pass
     U.__class__ = U
     del U
     gc.collect(); gc.collect(); gc.collect()

Modified: python/branches/p3yk/Lib/test/pickletester.py
==============================================================================
--- python/branches/p3yk/Lib/test/pickletester.py	(original)
+++ python/branches/p3yk/Lib/test/pickletester.py	Sun Mar 18 16:41:51 2007
@@ -88,8 +88,8 @@
 class metaclass(type):
     pass
 
-class use_metaclass(object):
-    __metaclass__ = metaclass
+class use_metaclass(object, metaclass=metaclass):
+    pass
 
 # DATA0 .. DATA2 are the pickles we expect under the various protocols, for
 # the object returned by create_data().

Modified: python/branches/p3yk/Lib/test/test_ast.py
==============================================================================
--- python/branches/p3yk/Lib/test/test_ast.py	(original)
+++ python/branches/p3yk/Lib/test/test_ast.py	Sun Mar 18 16:41:51 2007
@@ -144,13 +144,19 @@
                                 (eval_tests, eval_results, "eval")):
         for i, o in itertools.izip(input, output):
             ast_tree = compile(i, "?", kind, 0x400)
+            if to_tuple(ast_tree) != o:
+                print("i=", i)
+                print("o=", o)
+                print("kind=", kind)
+                print("tree=", ast_tree)
+                print("tuple=", to_tuple(ast_tree))
             assert to_tuple(ast_tree) == o
             test_order(ast_tree, (0, 0))
 
 #### EVERYTHING BELOW IS GENERATED #####
 exec_results = [
 ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Pass', (1, 9))], [], None)]),
-('Module', [('ClassDef', (1, 0), 'C', [], [('Pass', (1, 8))])]),
+('Module', [('ClassDef', (1, 0), 'C', [], [], None, None, [('Pass', (1, 8))])]),
 ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Return', (1, 8), ('Num', (1, 15), 1))], [], None)]),
 ('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])]),
 ('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Num', (1, 4), 1))]),

Modified: python/branches/p3yk/Lib/test/test_copy.py
==============================================================================
--- python/branches/p3yk/Lib/test/test_copy.py	(original)
+++ python/branches/p3yk/Lib/test/test_copy.py	Sun Mar 18 16:41:51 2007
@@ -191,8 +191,8 @@
         # type.
         class Meta(type):
             pass
-        class C:
-            __metaclass__ = Meta
+        class C(metaclass=Meta):
+            pass
         self.assertEqual(copy.deepcopy(C), C)
 
     def test_deepcopy_deepcopy(self):

Modified: python/branches/p3yk/Lib/test/test_descr.py
==============================================================================
--- python/branches/p3yk/Lib/test/test_descr.py	(original)
+++ python/branches/p3yk/Lib/test/test_descr.py	Sun Mar 18 16:41:51 2007
@@ -616,9 +616,8 @@
     vereq(a[100:200], (100,200))
 
 def metaclass():
-    if verbose: print("Testing __metaclass__...")
-    class C:
-        __metaclass__ = type
+    if verbose: print("Testing metaclass...")
+    class C(metaclass=type):
         def __init__(self):
             self.__state = 0
         def getstate(self):
@@ -629,9 +628,10 @@
     vereq(a.getstate(), 0)
     a.setstate(10)
     vereq(a.getstate(), 10)
-    class D:
-        class __metaclass__(type):
-            def myself(cls): return cls
+    class _metaclass(type):
+        def myself(cls): return cls
+    class D(metaclass=_metaclass):
+        pass
     vereq(D.myself(), D)
     d = D()
     verify(d.__class__ is D)
@@ -639,8 +639,8 @@
         def __new__(cls, name, bases, dict):
             dict['__spam__'] = 1
             return type.__new__(cls, name, bases, dict)
-    class C:
-        __metaclass__ = M1
+    class C(metaclass=M1):
+        pass
     vereq(C.__spam__, 1)
     c = C()
     vereq(c.__spam__, 1)
@@ -663,8 +663,7 @@
                     continue
                 setattr(it, key, self.dict[key].__get__(it, self))
             return it
-    class C:
-        __metaclass__ = M2
+    class C(metaclass=M2):
         def spam(self):
             return 42
     vereq(C.name, 'C')
@@ -690,8 +689,7 @@
                 name = "__super"
             setattr(cls, name, super(cls))
             return cls
-    class A:
-        __metaclass__ = autosuper
+    class A(metaclass=autosuper):
         def meth(self):
             return "A"
     class B(A):
@@ -729,8 +727,7 @@
                 dict[key] = property(get, set)
             return super(autoproperty, metaclass).__new__(metaclass,
                                                         name, bases, dict)
-    class A:
-        __metaclass__ = autoproperty
+    class A(metaclass=autoproperty):
         def _get_x(self):
             return -self.__x
         def _set_x(self, x):
@@ -744,8 +741,7 @@
     class multimetaclass(autoproperty, autosuper):
         # Merge of multiple cooperating metaclasses
         pass
-    class A:
-        __metaclass__ = multimetaclass
+    class A(metaclass=multimetaclass):
         def _get_x(self):
             return "A"
     class B(A):
@@ -764,8 +760,8 @@
         counter = 0
         def __init__(self, *args):
             T.counter += 1
-    class C:
-        __metaclass__ = T
+    class C(metaclass=T):
+        pass
     vereq(T.counter, 1)
     a = C()
     vereq(type(a), C)
@@ -1273,8 +1269,8 @@
     # Test comparison of classes with dynamic metaclasses
     class dynamicmetaclass(type):
         pass
-    class someclass:
-        __metaclass__ = dynamicmetaclass
+    class someclass(metaclass=dynamicmetaclass):
+        pass
     verify(someclass != object)
 
 def errors():
@@ -1505,36 +1501,39 @@
             L = type.mro(cls)
             L.reverse()
             return L
-    class X(D,B,C,A):
-        __metaclass__ = PerverseMetaType
+    class X(D,B,C,A, metaclass=PerverseMetaType):
+        pass
     vereq(X.__mro__, (object, A, C, B, D, X))
     vereq(X().f(), "A")
 
     try:
-        class X(object):
-            class __metaclass__(type):
-                def mro(self):
-                    return [self, dict, object]
+        class _metaclass(type):
+            def mro(self):
+                return [self, dict, object]
+        class X(object, metaclass=_metaclass):
+            pass
     except TypeError:
         pass
     else:
         raise TestFailed, "devious mro() return not caught"
 
     try:
-        class X(object):
-            class __metaclass__(type):
-                def mro(self):
-                    return [1]
+        class _metaclass(type):
+            def mro(self):
+                return [1]
+        class X(object, metaclass=_metaclass):
+            pass
     except TypeError:
         pass
     else:
         raise TestFailed, "non-class mro() return not caught"
 
     try:
-        class X(object):
-            class __metaclass__(type):
-                def mro(self):
-                    return 1
+        class _metaclass(type):
+            def mro(self):
+                return 1
+        class X(object, metaclass=_metaclass):
+            pass
     except TypeError:
         pass
     else:
@@ -3575,11 +3574,11 @@
     class E(D):
         pass
 
-    class F(D):
-        __metaclass__ = WorkOnce
+    class F(D, metaclass=WorkOnce):
+        pass
 
-    class G(D):
-        __metaclass__ = WorkAlways
+    class G(D, metaclass=WorkAlways):
+        pass
 
     # Immediate subclasses have their mro's adjusted in alphabetical
     # order, so E's will get adjusted before adjusting F's fails.  We
@@ -3690,15 +3689,15 @@
 
 def dict_type_with_metaclass():
     if verbose:
-        print("Testing type of __dict__ when __metaclass__ set...")
+        print("Testing type of __dict__ when metaclass set...")
 
     class B(object):
         pass
     class M(type):
         pass
-    class C:
+    class C(metaclass=M):
         # In 2.3a1, C.__dict__ was a real dict rather than a dict proxy
-        __metaclass__ = M
+        pass
     veris(type(C.__dict__), type(B.__dict__))
 
 def meth_class_get():

Added: python/branches/p3yk/Lib/test/test_metaclass.py
==============================================================================
--- (empty file)
+++ python/branches/p3yk/Lib/test/test_metaclass.py	Sun Mar 18 16:41:51 2007
@@ -0,0 +1,218 @@
+doctests = """
+
+Basic class construction.
+
+    >>> class C:
+    ...     def meth(self): print("Hello")
+    ...
+    >>> C.__class__ is type
+    True
+    >>> a = C()
+    >>> a.__class__ is C
+    True
+    >>> a.meth()
+    Hello
+    >>>
+
+Use *args notation for the bases.
+
+    >>> class A: pass
+    >>> class B: pass
+    >>> bases = (A, B)
+    >>> class C(*bases): pass
+    >>> C.__bases__ == bases
+    True
+    >>>
+
+Use a trivial metaclass.
+
+    >>> class M(type):
+    ...     pass
+    ...
+    >>> class C(metaclass=M):
+    ...    def meth(self): print("Hello")
+    ...
+    >>> C.__class__ is M
+    True
+    >>> a = C()
+    >>> a.__class__ is C
+    True
+    >>> a.meth()
+    Hello
+    >>>
+
+Use **kwds notation for the metaclass keyword.
+
+    >>> kwds = {'metaclass': M}
+    >>> class C(**kwds): pass
+    ...
+    >>> C.__class__ is M
+    True
+    >>> a = C()
+    >>> a.__class__ is C
+    True
+    >>>
+
+Use a metaclass with a __prepare__ static method.
+
+    >>> class M(type):
+    ...    @staticmethod
+    ...    def __prepare__(*args, **kwds):
+    ...        print("Prepare called:", args, kwds)
+    ...        return dict()
+    ...    def __new__(cls, name, bases, namespace, **kwds):
+    ...        print("New called:", kwds)
+    ...        return type.__new__(cls, name, bases, namespace)
+    ...
+    >>> class C(metaclass=M):
+    ...     def meth(self): print("Hello")
+    ...
+    Prepare called: ('C', ()) {}
+    New called: {}
+    >>>
+
+Also pass another keyword.
+
+    >>> class C(object, metaclass=M, other="haha"):
+    ...     pass
+    ...
+    Prepare called: ('C', (<type 'object'>,)) {'other': 'haha'}
+    New called: {'other': 'haha'}
+    >>> C.__class__ is M
+    True
+    >>> C.__bases__ == (object,)
+    True
+    >>> a = C()
+    >>> a.__class__ is C
+    True
+    >>>
+
+Check that build_class doesn't mutate the kwds dict.
+
+    >>> kwds = {'metaclass': type}
+    >>> class C(**kwds): pass
+    ...
+    >>> kwds == {'metaclass': type}
+    True
+    >>>
+
+Use various combinations of explicit keywords and **kwds.
+
+    >>> bases = (object,)
+    >>> kwds = {'metaclass': M, 'other': 'haha'}
+    >>> class C(*bases, **kwds): pass
+    ...
+    Prepare called: ('C', (<type 'object'>,)) {'other': 'haha'}
+    New called: {'other': 'haha'}
+    >>> C.__class__ is M
+    True
+    >>> C.__bases__ == (object,)
+    True
+    >>> class B: pass
+    >>> kwds = {'other': 'haha'}
+    >>> class C(B, metaclass=M, *bases, **kwds): pass
+    ...
+    Prepare called: ('C', (<class 'test.test_metaclass.B'>, <type 'object'>)) {'other': 'haha'}
+    New called: {'other': 'haha'}
+    >>> C.__class__ is M
+    True
+    >>> C.__bases__ == (B, object)
+    True
+    >>>
+
+Check for duplicate keywords.
+
+    >>> class C(metaclass=type, metaclass=type): pass
+    ...
+    Traceback (most recent call last):
+    [...]
+    TypeError: __build_class__() got multiple values for keyword argument 'metaclass'
+    >>>
+
+Another way.
+
+    >>> kwds = {'metaclass': type}
+    >>> class C(metaclass=type, **kwds): pass
+    ...
+    Traceback (most recent call last):
+    [...]
+    TypeError: __build_class__() got multiple values for keyword argument 'metaclass'
+    >>>
+
+Use a __prepare__ method that returns an instrumented dict.
+
+    >>> class LoggingDict(dict):
+    ...     def __setitem__(self, key, value):
+    ...         print("d[%r] = %r" % (key, value))
+    ...         dict.__setitem__(self, key, value)
+    ...
+    >>> class Meta(type):
+    ...    @staticmethod
+    ...    def __prepare__(name, bases):
+    ...        return LoggingDict()
+    ...
+    >>> class C(metaclass=Meta):
+    ...     foo = 2+2
+    ...     foo = 42
+    ...     bar = 123
+    ...
+    d['__module__'] = 'test.test_metaclass'
+    d['foo'] = 4
+    d['foo'] = 42
+    d['bar'] = 123
+    >>>
+
+Use a metaclass that doesn't derive from type.
+
+    >>> def meta(name, bases, namespace, **kwds):
+    ...     print("meta:", name, bases)
+    ...     print("ns:", sorted(namespace.items()))
+    ...     print("kw:", sorted(kwds.items()))
+    ...     return namespace
+    ...
+    >>> class C(metaclass=meta):
+    ...     a = 42
+    ...     b = 24
+    ...
+    meta: C ()
+    ns: [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
+    kw: []
+    >>> type(C) is dict
+    True
+    >>> print(sorted(C.items()))
+    [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
+    >>>
+
+And again, with a __prepare__ attribute.
+
+    >>> def prepare(name, bases, **kwds):
+    ...     print("prepare:", name, bases, sorted(kwds.items()))
+    ...     return LoggingDict()
+    ...
+    >>> meta.__prepare__ = prepare
+    >>> class C(metaclass=meta, other="booh"):
+    ...    a = 1
+    ...    a = 2
+    ...    b = 3
+    ...
+    prepare: C () [('other', 'booh')]
+    d['__module__'] = 'test.test_metaclass'
+    d['a'] = 1
+    d['a'] = 2
+    d['b'] = 3
+    meta: C ()
+    ns: [('__module__', 'test.test_metaclass'), ('a', 2), ('b', 3)]
+    kw: [('other', 'booh')]
+    >>>
+
+"""
+
+__test__ = {'doctests' : doctests}
+
+def test_main(verbose=False):
+    from test import test_support
+    from test import test_metaclass
+    test_support.run_doctest(test_metaclass, verbose)
+
+if __name__ == "__main__":
+    test_main(verbose=True)

Modified: python/branches/p3yk/Lib/unittest.py
==============================================================================
--- python/branches/p3yk/Lib/unittest.py	(original)
+++ python/branches/p3yk/Lib/unittest.py	Sun Mar 18 16:41:51 2007
@@ -84,9 +84,6 @@
 # Test framework core
 ##############################################################################
 
-# All classes defined herein are 'new-style' classes, allowing use of 'super()'
-__metaclass__ = type
-
 def _strclass(cls):
     return "%s.%s" % (cls.__module__, cls.__name__)
 

Modified: python/branches/p3yk/Modules/_bsddb.c
==============================================================================
--- python/branches/p3yk/Modules/_bsddb.c	(original)
+++ python/branches/p3yk/Modules/_bsddb.c	Sun Mar 18 16:41:51 2007
@@ -5991,6 +5991,10 @@
      * from both DBError and KeyError, since the API only supports
      * using one base class. */
     PyDict_SetItemString(d, "KeyError", PyExc_KeyError);
+    { 
+	    PyObject *builtin_mod = PyImport_ImportModule("__builtin__");
+	    PyDict_SetItemString(d, "__builtins__", builtin_mod);
+    }
     PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n"
 	         "class DBKeyEmptyError(DBError, KeyError): pass",
                  Py_file_input, d, d);

Modified: python/branches/p3yk/Parser/Python.asdl
==============================================================================
--- python/branches/p3yk/Parser/Python.asdl	(original)
+++ python/branches/p3yk/Parser/Python.asdl	Sun Mar 18 16:41:51 2007
@@ -11,7 +11,12 @@
 
 	stmt = FunctionDef(identifier name, arguments args, 
                            stmt* body, expr* decorators, expr? returns)
-	      | ClassDef(identifier name, expr* bases, stmt* body)
+	      | ClassDef(identifier name, 
+			 expr* bases,
+			 keyword* keywords,
+			 expr? starargs,
+			 expr? kwargs,
+			 stmt* body)
 	      | Return(expr? value)
 
 	      | Delete(expr* targets)

Modified: python/branches/p3yk/Python/Python-ast.c
==============================================================================
--- python/branches/p3yk/Python/Python-ast.c	(original)
+++ python/branches/p3yk/Python/Python-ast.c	Sun Mar 18 16:41:51 2007
@@ -49,6 +49,9 @@
 static char *ClassDef_fields[]={
         "name",
         "bases",
+        "keywords",
+        "starargs",
+        "kwargs",
         "body",
 };
 static PyTypeObject *Return_type;
@@ -477,7 +480,7 @@
         FunctionDef_type = make_type("FunctionDef", stmt_type,
                                      FunctionDef_fields, 5);
         if (!FunctionDef_type) return 0;
-        ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 3);
+        ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 6);
         if (!ClassDef_type) return 0;
         Return_type = make_type("Return", stmt_type, Return_fields, 1);
         if (!Return_type) return 0;
@@ -835,8 +838,9 @@
 }
 
 stmt_ty
-ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int lineno, int
-         col_offset, PyArena *arena)
+ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, expr_ty
+         starargs, expr_ty kwargs, asdl_seq * body, int lineno, int col_offset,
+         PyArena *arena)
 {
         stmt_ty p;
         if (!name) {
@@ -850,6 +854,9 @@
         p->kind = ClassDef_kind;
         p->v.ClassDef.name = name;
         p->v.ClassDef.bases = bases;
+        p->v.ClassDef.keywords = keywords;
+        p->v.ClassDef.starargs = starargs;
+        p->v.ClassDef.kwargs = kwargs;
         p->v.ClassDef.body = body;
         p->lineno = lineno;
         p->col_offset = col_offset;
@@ -1974,6 +1981,21 @@
                 if (PyObject_SetAttrString(result, "bases", value) == -1)
                         goto failed;
                 Py_DECREF(value);
+                value = ast2obj_list(o->v.ClassDef.keywords, ast2obj_keyword);
+                if (!value) goto failed;
+                if (PyObject_SetAttrString(result, "keywords", value) == -1)
+                        goto failed;
+                Py_DECREF(value);
+                value = ast2obj_expr(o->v.ClassDef.starargs);
+                if (!value) goto failed;
+                if (PyObject_SetAttrString(result, "starargs", value) == -1)
+                        goto failed;
+                Py_DECREF(value);
+                value = ast2obj_expr(o->v.ClassDef.kwargs);
+                if (!value) goto failed;
+                if (PyObject_SetAttrString(result, "kwargs", value) == -1)
+                        goto failed;
+                Py_DECREF(value);
                 value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt);
                 if (!value) goto failed;
                 if (PyObject_SetAttrString(result, "body", value) == -1)

Modified: python/branches/p3yk/Python/ast.c
==============================================================================
--- python/branches/p3yk/Python/ast.c	(original)
+++ python/branches/p3yk/Python/ast.c	Sun Mar 18 16:41:51 2007
@@ -2092,28 +2092,6 @@
     return ast_for_testlist(c, n);
 }
 
-/* like ast_for_testlist() but returns a sequence */
-static asdl_seq*
-ast_for_class_bases(struct compiling *c, const node* n)
-{
-    /* testlist: test (',' test)* [','] */
-    assert(NCH(n) > 0);
-    REQ(n, testlist);
-    if (NCH(n) == 1) {
-        expr_ty base;
-        asdl_seq *bases = asdl_seq_new(1, c->c_arena);
-        if (!bases)
-            return NULL;
-        base = ast_for_expr(c, CHILD(n, 0));
-        if (!base)
-            return NULL;
-        asdl_seq_SET(bases, 0, base);
-        return bases;
-    }
-
-    return seq_for_testlist(c, n);
-}
-
 static stmt_ty
 ast_for_expr_stmt(struct compiling *c, const node *n)
 {
@@ -3032,9 +3010,10 @@
 static stmt_ty
 ast_for_classdef(struct compiling *c, const node *n)
 {
-    /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
-    asdl_seq *bases, *s;
-    
+    /* classdef: 'class' NAME ['(' arglist ')'] ':' suite */
+    asdl_seq *s;
+    expr_ty call, dummy;
+
     REQ(n, classdef);
 
     if (!strcmp(STR(CHILD(n, 1)), "None")) {
@@ -3042,32 +3021,36 @@
             return NULL;
     }
 
-    if (NCH(n) == 4) {
+    if (NCH(n) == 4) { /* class NAME ':' suite */
         s = ast_for_suite(c, CHILD(n, 3));
         if (!s)
             return NULL;
-        return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n),
-                        n->n_col_offset, c->c_arena);
+        return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s,
+                        LINENO(n), n->n_col_offset, c->c_arena);
     }
-    /* check for empty base list */
-    if (TYPE(CHILD(n,3)) == RPAR) {
+
+    if (TYPE(CHILD(n, 3)) == RPAR) { /* class NAME '(' ')' ':' suite */
         s = ast_for_suite(c, CHILD(n,5));
         if (!s)
                 return NULL;
-        return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n),
-                        n->n_col_offset, c->c_arena);
+        return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s,
+                        LINENO(n), n->n_col_offset, c->c_arena);
     }
 
-    /* else handle the base class list */
-    bases = ast_for_class_bases(c, CHILD(n, 3));
-    if (!bases)
+    /* class NAME '(' arglist ')' ':' suite */
+    /* build up a fake Call node so we can extract its pieces */
+    dummy = Name(NEW_IDENTIFIER(CHILD(n, 1)), Load, LINENO(n), n->n_col_offset, c->c_arena);
+    call = ast_for_call(c, CHILD(n, 3), dummy);
+    if (!call)
         return NULL;
-
     s = ast_for_suite(c, CHILD(n, 6));
     if (!s)
         return NULL;
-    return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), bases, s, LINENO(n),
-                    n->n_col_offset, c->c_arena);
+
+    return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)),
+                    call->v.Call.args, call->v.Call.keywords,
+                    call->v.Call.starargs, call->v.Call.kwargs, s,
+                    LINENO(n), n->n_col_offset, c->c_arena);
 }
 
 static stmt_ty

Modified: python/branches/p3yk/Python/bltinmodule.c
==============================================================================
--- python/branches/p3yk/Python/bltinmodule.c	(original)
+++ python/branches/p3yk/Python/bltinmodule.c	Sun Mar 18 16:41:51 2007
@@ -31,6 +31,113 @@
 static PyObject *filtertuple (PyObject *, PyObject *);
 
 static PyObject *
+builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds)
+{
+	PyObject *func, *name, *bases, *mkw, *meta, *prep, *ns, *res;
+	Py_ssize_t nargs, nbases;
+
+	assert(args != NULL);
+	if (!PyTuple_Check(args)) {
+		PyErr_SetString(PyExc_TypeError,
+				"__build_class__: args is not a tuple");
+		return NULL;
+	}
+	nargs = PyTuple_GET_SIZE(args);
+	if (nargs < 2) {
+		PyErr_SetString(PyExc_TypeError,
+				"__build_class__: not enough arguments");
+		return NULL;
+	}
+	func = PyTuple_GET_ITEM(args, 0); /* Better be callable */
+	name = PyTuple_GET_ITEM(args, 1);
+	if (!PyString_Check(name)) {
+		PyErr_SetString(PyExc_TypeError,
+				"__build_class__: name is not a string");
+		return NULL;
+	}
+	bases = PyTuple_GetSlice(args, 2, nargs);
+	if (bases == NULL)
+		return NULL;
+	nbases = nargs - 2;
+
+	if (kwds == NULL) {
+		meta = NULL;
+                mkw = NULL;
+        }
+	else {
+		mkw = PyDict_Copy(kwds); /* Don't modify kwds passed in! */
+		if (mkw == NULL) {
+			Py_DECREF(bases);
+			return NULL;
+		}
+		meta = PyDict_GetItemString(mkw, "metaclass");
+		if (meta != NULL) {
+			Py_INCREF(meta);
+			if (PyDict_DelItemString(mkw, "metaclass") < 0) {
+				Py_DECREF(meta);
+				Py_DECREF(mkw);
+				Py_DECREF(bases);
+				return NULL;
+			}
+		}
+	}
+	if (meta == NULL) {
+		if (PyTuple_GET_SIZE(bases) == 0)
+			meta = (PyObject *) (&PyType_Type);
+		else {
+			PyObject *base0 = PyTuple_GET_ITEM(bases, 0);
+			meta = (PyObject *) (base0->ob_type);
+		}
+		Py_INCREF(meta);
+	}
+	prep = PyObject_GetAttrString(meta, "__prepare__");
+	if (prep == NULL) {
+		PyErr_Clear();
+		ns = PyDict_New();
+	}
+	else {
+		PyObject *pargs = Py_BuildValue("OO", name, bases);
+		if (pargs == NULL) {
+			Py_DECREF(prep);
+			Py_DECREF(meta);
+			Py_XDECREF(mkw);
+			Py_DECREF(bases);
+			return NULL;
+		}
+		ns = PyEval_CallObjectWithKeywords(prep, pargs, mkw);
+		Py_DECREF(pargs);
+		Py_DECREF(prep);
+		if (ns == NULL) {
+			Py_DECREF(meta);
+			Py_XDECREF(mkw);
+			Py_DECREF(bases);
+			return NULL;
+		}
+	}
+	res = PyObject_CallFunctionObjArgs(func, ns, NULL);
+	if (res != NULL) {
+		PyObject *margs;
+		Py_DECREF(res);
+		res = NULL;
+		margs = Py_BuildValue("OOO", name, bases, ns);
+		if (margs != NULL) {
+			res = PyEval_CallObjectWithKeywords(meta, margs, mkw);
+			Py_DECREF(margs);
+		}
+	}
+	Py_DECREF(ns);
+	Py_DECREF(meta);
+	Py_XDECREF(mkw);
+	Py_DECREF(bases);
+	return res;
+}
+
+PyDoc_STRVAR(build_class_doc,
+"__build_class__(func, name, *bases, metaclass=None, **kwds) -> class\n\
+\n\
+Internal helper function used by the class statement.");
+
+static PyObject *
 builtin___import__(PyObject *self, PyObject *args, PyObject *kwds)
 {
 	static char *kwlist[] = {"name", "globals", "locals", "fromlist",
@@ -2103,6 +2210,8 @@
 
 
 static PyMethodDef builtin_methods[] = {
+ 	{"__build_class__", (PyCFunction)builtin___build_class__,
+         METH_VARARGS | METH_KEYWORDS, build_class_doc},
  	{"__import__",	(PyCFunction)builtin___import__, METH_VARARGS | METH_KEYWORDS, import_doc},
  	{"abs",		builtin_abs,        METH_O, abs_doc},
  	{"all",		builtin_all,        METH_O, all_doc},

Modified: python/branches/p3yk/Python/ceval.c
==============================================================================
--- python/branches/p3yk/Python/ceval.c	(original)
+++ python/branches/p3yk/Python/ceval.c	Sun Mar 18 16:41:51 2007
@@ -117,7 +117,6 @@
 static PyObject * cmp_outcome(int, PyObject *, PyObject *);
 static PyObject * import_from(PyObject *, PyObject *);
 static int import_all_from(PyObject *, PyObject *);
-static PyObject * build_class(PyObject *, PyObject *, PyObject *);
 static void set_exc_info(PyThreadState *, PyObject *, PyObject *, PyObject *);
 static void reset_exc_info(PyThreadState *);
 static void format_exc_check_arg(PyObject *, char *, PyObject *);
@@ -1532,14 +1531,12 @@
 			}
 			break;
 
-		case LOAD_LOCALS:
-			if ((x = f->f_locals) != NULL) {
-				Py_INCREF(x);
-				PUSH(x);
-				continue;
-			}
-			PyErr_SetString(PyExc_SystemError, "no locals");
-			break;
+		case STORE_LOCALS:
+			x = POP();
+			v = f->f_locals;
+			Py_XDECREF(v);
+			f->f_locals = x;
+			continue;
 
 		case RETURN_VALUE:
 			retval = POP();
@@ -1586,16 +1583,16 @@
 			Py_DECREF(v);
 			break;
 
-		case BUILD_CLASS:
-			u = TOP();
-			v = SECOND();
-			w = THIRD();
-			STACKADJ(-2);
-			x = build_class(u, v, w);
-			SET_TOP(x);
-			Py_DECREF(u);
-			Py_DECREF(v);
-			Py_DECREF(w);
+		case LOAD_BUILD_CLASS:
+			x = PyDict_GetItemString(f->f_builtins,
+						 "__build_class__");
+			if (x == NULL) {
+				PyErr_SetString(PyExc_ImportError,
+						"__build_class__ not found");
+				break;
+			}
+			Py_INCREF(x);
+			PUSH(x);
 			break;
 
 		case STORE_NAME:
@@ -4023,60 +4020,6 @@
 	return err;
 }
 
-static PyObject *
-build_class(PyObject *methods, PyObject *bases, PyObject *name)
-{
-	PyObject *metaclass = NULL, *result, *base;
-
-	if (PyDict_Check(methods))
-		metaclass = PyDict_GetItemString(methods, "__metaclass__");
-	if (metaclass != NULL)
-		Py_INCREF(metaclass);
-	else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
-		base = PyTuple_GET_ITEM(bases, 0);
-		metaclass = PyObject_GetAttrString(base, "__class__");
-		if (metaclass == NULL) {
-			PyErr_Clear();
-			metaclass = (PyObject *)base->ob_type;
-			Py_INCREF(metaclass);
-		}
-	}
-	else {
-		PyObject *g = PyEval_GetGlobals();
-		if (g != NULL && PyDict_Check(g))
-			metaclass = PyDict_GetItemString(g, "__metaclass__");
-		if (metaclass == NULL)
-			metaclass = (PyObject *) &PyType_Type;
-		Py_INCREF(metaclass);
-	}
-	result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods,
-                                              NULL);
-	Py_DECREF(metaclass);
-	if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) {
-		/* A type error here likely means that the user passed
-		   in a base that was not a class (such the random module
-		   instead of the random.random type).  Help them out with
-		   by augmenting the error message with more information.*/
-
-		PyObject *ptype, *pvalue, *ptraceback;
-
-		PyErr_Fetch(&ptype, &pvalue, &ptraceback);
-		if (PyString_Check(pvalue)) {
-			PyObject *newmsg;
-			newmsg = PyString_FromFormat(
-				"Error when calling the metaclass bases\n"
-                                "    %s",
-				PyString_AS_STRING(pvalue));
-			if (newmsg != NULL) {
-				Py_DECREF(pvalue);
-				pvalue = newmsg;
-			}
-		}
-		PyErr_Restore(ptype, pvalue, ptraceback);
-	}
-	return result;
-}
-
 static void
 format_exc_check_arg(PyObject *exc, char *format_str, PyObject *obj)
 {

Modified: python/branches/p3yk/Python/compile.c
==============================================================================
--- python/branches/p3yk/Python/compile.c	(original)
+++ python/branches/p3yk/Python/compile.c	Sun Mar 18 16:41:51 2007
@@ -176,6 +176,11 @@
 static int expr_constant(expr_ty e);
 
 static int compiler_with(struct compiler *, stmt_ty);
+static int compiler_call_helper(struct compiler *c, int n,
+				asdl_seq *args,
+				asdl_seq *keywords,
+				expr_ty starargs,
+				expr_ty kwargs);
 
 static PyCodeObject *assemble(struct compiler *, int addNone);
 static PyObject *__doc__;
@@ -734,6 +739,8 @@
 
 		case PRINT_EXPR:
 			return -1;
+		case LOAD_BUILD_CLASS:
+			return 1;
 		case INPLACE_LSHIFT:
 		case INPLACE_RSHIFT:
 		case INPLACE_AND:
@@ -744,8 +751,8 @@
 			return 0;
 		case WITH_CLEANUP:
 			return -1; /* XXX Sometimes more */
-		case LOAD_LOCALS:
-			return 1;
+		case STORE_LOCALS:
+			return -1;
 		case RETURN_VALUE:
 			return -1;
 		case IMPORT_STAR:
@@ -757,8 +764,6 @@
 			return 0;
 		case END_FINALLY:
 			return -1; /* or -2 or -3 if exception occurred */
-		case BUILD_CLASS:
-			return -2;
 
 		case STORE_NAME:
 			return -1;
@@ -1509,54 +1514,107 @@
 static int
 compiler_class(struct compiler *c, stmt_ty s)
 {
-	int n;
+	static PyObject *build_class = NULL;
+	static PyObject *locals = NULL;
 	PyCodeObject *co;
 	PyObject *str;
-	/* push class name on stack, needed by BUILD_CLASS */
-	ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts);
-	/* push the tuple of base classes on the stack */
-	n = asdl_seq_LEN(s->v.ClassDef.bases);
-	if (n > 0)
-		VISIT_SEQ(c, expr, s->v.ClassDef.bases);
-	ADDOP_I(c, BUILD_TUPLE, n);
-	if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s,
-				  s->lineno))
-		return 0;
-	c->u->u_private = s->v.ClassDef.name;
-	Py_INCREF(c->u->u_private);
-	str = PyString_InternFromString("__name__");
-	if (!str || !compiler_nameop(c, str, Load)) {
-		Py_XDECREF(str);
-		compiler_exit_scope(c);
-		return 0;
+	PySTEntryObject *ste;
+
+	/* initialize statics */
+	if (build_class == NULL) {
+		build_class = PyString_FromString("__build_class__");
+		if (build_class == NULL)
+			return 0;
 	}
-	
-	Py_DECREF(str);
-	str = PyString_InternFromString("__module__");
-	if (!str || !compiler_nameop(c, str, Store)) {
-		Py_XDECREF(str);
-		compiler_exit_scope(c);
-		return 0;
+	if (locals == NULL) {
+		locals = PyString_FromString("__locals__");
+		if (locals == NULL)
+			return 0;
 	}
-	Py_DECREF(str);
 
-	if (!compiler_body(c, s->v.ClassDef.body)) {
-		compiler_exit_scope(c);
-		return 0;
-	}
+	/* ultimately generate code for:
+	     <name> = __build_class__(<func>, <name>, *<bases>, **<keywords>)
+	   where:
+	     <func> is a function/closure created from the class body
+	     <name> is the class name
+             <bases> is the positional arguments and *varargs argument
+	     <keywords> is the keyword arguments and **kwds argument
+	   This borrows from compiler_call.
+	*/
 
-	ADDOP_IN_SCOPE(c, LOAD_LOCALS);
-	ADDOP_IN_SCOPE(c, RETURN_VALUE);
-	co = assemble(c, 1);
+	/* 0. Create a fake variable named __locals__ */
+	ste = PySymtable_Lookup(c->c_st, s);
+	if (ste == NULL)
+		return 0;
+	assert(PyList_Check(ste->ste_varnames));
+	if (PyList_Append(ste->ste_varnames, locals) < 0)
+		return 0;
+
+	/* 1. compile the class body into a code object */
+	if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, s->lineno))
+		return 0;
+	/* this block represents what we do in the new scope */
+	{
+		/* use the class name for name mangling */
+		Py_INCREF(s->v.ClassDef.name);
+		c->u->u_private = s->v.ClassDef.name;
+		/* force it to have one mandatory argument */
+		c->u->u_argcount = 1;
+		/* load the first argument ... */
+		ADDOP_I(c, LOAD_FAST, 0);
+		/* ... and store it into f_locals */
+		ADDOP_IN_SCOPE(c, STORE_LOCALS);
+		/* load __name__ ... */
+		str = PyString_InternFromString("__name__");
+		if (!str || !compiler_nameop(c, str, Load)) {
+			Py_XDECREF(str);
+			compiler_exit_scope(c);
+			return 0;
+		}
+		Py_DECREF(str);
+		/* ... and store it as __module__ */
+		str = PyString_InternFromString("__module__");
+		if (!str || !compiler_nameop(c, str, Store)) {
+			Py_XDECREF(str);
+			compiler_exit_scope(c);
+			return 0;
+		}
+		Py_DECREF(str);
+		/* compile the body proper */
+		if (!compiler_body(c, s->v.ClassDef.body)) {
+			compiler_exit_scope(c);
+			return 0;
+		}
+		/* return None */
+		ADDOP_O(c, LOAD_CONST, Py_None, consts);
+		ADDOP_IN_SCOPE(c, RETURN_VALUE);
+		/* create the code object */
+		co = assemble(c, 1);
+	}
+	/* leave the new scope */
 	compiler_exit_scope(c);
 	if (co == NULL)
 		return 0;
 
+	/* 2. load the 'build_class' function */
+	ADDOP(c, LOAD_BUILD_CLASS);
+
+	/* 3. load a function (or closure) made from the code object */
 	compiler_make_closure(c, co, 0);
 	Py_DECREF(co);
 
-	ADDOP_I(c, CALL_FUNCTION, 0);
-	ADDOP(c, BUILD_CLASS);
+	/* 4. load class name */
+	ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts);
+
+	/* 5. generate the rest of the code for the call */
+	if (!compiler_call_helper(c, 2,
+				  s->v.ClassDef.bases,
+				  s->v.ClassDef.keywords,
+				  s->v.ClassDef.starargs,
+				  s->v.ClassDef.kwargs))
+		return 0;
+
+	/* 6. store into <name> */
 	if (!compiler_nameop(c, s->v.ClassDef.name, Store))
 		return 0;
 	return 1;
@@ -2613,21 +2671,37 @@
 static int
 compiler_call(struct compiler *c, expr_ty e)
 {
-	int n, code = 0;
-
 	VISIT(c, expr, e->v.Call.func);
-	n = asdl_seq_LEN(e->v.Call.args);
-	VISIT_SEQ(c, expr, e->v.Call.args);
-	if (e->v.Call.keywords) {
-		VISIT_SEQ(c, keyword, e->v.Call.keywords);
-		n |= asdl_seq_LEN(e->v.Call.keywords) << 8;
+	return compiler_call_helper(c, 0,
+				    e->v.Call.args,
+				    e->v.Call.keywords,
+				    e->v.Call.starargs,
+				    e->v.Call.kwargs);
+}
+
+/* shared code between compiler_call and compiler_class */
+static int
+compiler_call_helper(struct compiler *c,
+		     int n, /* Args already pushed */
+		     asdl_seq *args,
+		     asdl_seq *keywords,
+		     expr_ty starargs,
+		     expr_ty kwargs)
+{
+	int code = 0;
+
+	n += asdl_seq_LEN(args);
+	VISIT_SEQ(c, expr, args);
+	if (keywords) {
+		VISIT_SEQ(c, keyword, keywords);
+		n |= asdl_seq_LEN(keywords) << 8;
 	}
-	if (e->v.Call.starargs) {
-		VISIT(c, expr, e->v.Call.starargs);
+	if (starargs) {
+		VISIT(c, expr, starargs);
 		code |= 1;
 	}
-	if (e->v.Call.kwargs) {
-		VISIT(c, expr, e->v.Call.kwargs);
+	if (kwargs) {
+		VISIT(c, expr, kwargs);
 		code |= 2;
 	}
 	switch (code) {

Modified: python/branches/p3yk/Python/graminit.c
==============================================================================
--- python/branches/p3yk/Python/graminit.c	(original)
+++ python/branches/p3yk/Python/graminit.c	Sun Mar 18 16:41:51 2007
@@ -1635,7 +1635,7 @@
 	{23, 4},
 };
 static arc arcs_76_3[2] = {
-	{9, 5},
+	{14, 5},
 	{15, 6},
 };
 static arc arcs_76_4[1] = {

Modified: python/branches/p3yk/Python/import.c
==============================================================================
--- python/branches/p3yk/Python/import.c	(original)
+++ python/branches/p3yk/Python/import.c	Sun Mar 18 16:41:51 2007
@@ -72,9 +72,10 @@
 		      3030 (added keyword-only parameters)
 		      3040 (added signature annotations)
 		      3050 (print becomes a function)
+		      3060 (PEP 3115 metaclass syntax)
 .
 */
-#define MAGIC (3050 | ((long)'\r'<<16) | ((long)'\n'<<24))
+#define MAGIC (3060 | ((long)'\r'<<16) | ((long)'\n'<<24))
 
 /* Magic word as global; note that _PyImport_Init() can change the
    value of this global to accommodate for alterations of how the

Modified: python/branches/p3yk/Python/symtable.c
==============================================================================
--- python/branches/p3yk/Python/symtable.c	(original)
+++ python/branches/p3yk/Python/symtable.c	Sun Mar 18 16:41:51 2007
@@ -983,6 +983,11 @@
 		if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL))
 			return 0;
 		VISIT_SEQ(st, expr, s->v.ClassDef.bases);
+		VISIT_SEQ(st, keyword, s->v.ClassDef.keywords);
+		if (s->v.ClassDef.starargs)
+			VISIT(st, expr, s->v.ClassDef.starargs);
+		if (s->v.ClassDef.kwargs)
+			VISIT(st, expr, s->v.ClassDef.kwargs);
 		if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, 
 					  (void *)s, s->lineno))
 			return 0;


More information about the Python-3000-checkins mailing list