summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2007-03-18 15:41:51 (GMT)
committerGuido van Rossum <guido@python.org>2007-03-18 15:41:51 (GMT)
commit52cc1d838f4fee573e57b5b182d8e5f5db63240f (patch)
tree0ea50468d2b04ee12131c155c5918e8a70dafe1c /Lib
parentef17c16b366b09a78dfe5fc5171fe2b0b29f60e5 (diff)
downloadcpython-52cc1d838f4fee573e57b5b182d8e5f5db63240f.zip
cpython-52cc1d838f4fee573e57b5b182d8e5f5db63240f.tar.gz
cpython-52cc1d838f4fee573e57b5b182d8e5f5db63240f.tar.bz2
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.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/build_class.py0
-rw-r--r--Lib/ctypes/_endian.py6
-rw-r--r--Lib/opcode.py5
-rw-r--r--Lib/string.py3
-rw-r--r--Lib/test/crashers/modify_dict_attr.py3
-rw-r--r--Lib/test/leakers/test_selftype.py4
-rw-r--r--Lib/test/pickletester.py4
-rw-r--r--Lib/test/test_ast.py8
-rw-r--r--Lib/test/test_copy.py4
-rw-r--r--Lib/test/test_descr.py81
-rw-r--r--Lib/test/test_metaclass.py218
-rw-r--r--Lib/unittest.py3
12 files changed, 278 insertions, 61 deletions
diff --git a/Lib/build_class.py b/Lib/build_class.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Lib/build_class.py
diff --git a/Lib/ctypes/_endian.py b/Lib/ctypes/_endian.py
index 6de0d47..61ac334 100644
--- a/Lib/ctypes/_endian.py
+++ b/Lib/ctypes/_endian.py
@@ -42,18 +42,16 @@ if sys.byteorder == "little":
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:
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 69982f2..61b288a 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -98,8 +98,10 @@ def_op('BINARY_XOR', 65)
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_XOR', 78)
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:
diff --git a/Lib/string.py b/Lib/string.py
index 8281936..6aafb65 100644
--- a/Lib/string.py
+++ b/Lib/string.py
@@ -119,9 +119,8 @@ class _TemplateMetaclass(type):
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]*'
diff --git a/Lib/test/crashers/modify_dict_attr.py b/Lib/test/crashers/modify_dict_attr.py
index 2a8fce0..ac1f0a8 100644
--- a/Lib/test/crashers/modify_dict_attr.py
+++ b/Lib/test/crashers/modify_dict_attr.py
@@ -7,11 +7,10 @@ class Y(object):
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__':
diff --git a/Lib/test/leakers/test_selftype.py b/Lib/test/leakers/test_selftype.py
index 4207c32..12f2934 100644
--- a/Lib/test/leakers/test_selftype.py
+++ b/Lib/test/leakers/test_selftype.py
@@ -6,8 +6,8 @@ import gc
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()
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index cb4b431..b10c57d 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -88,8 +88,8 @@ class initarg(C):
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().
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 5d22053..c702ab1 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -144,13 +144,19 @@ def run_tests():
(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))]),
diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py
index fd6109c..dbca158 100644
--- a/Lib/test/test_copy.py
+++ b/Lib/test/test_copy.py
@@ -191,8 +191,8 @@ class TestCopy(unittest.TestCase):
# 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):
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index e8db29e..6cd8ccd 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -616,9 +616,8 @@ def pylists():
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 @@ def metaclass():
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 metaclass():
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 @@ def metaclass():
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 @@ def metaclass():
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 @@ def metaclass():
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 @@ def metaclass():
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 @@ def metaclass():
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 @@ def dynamics():
# 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 @@ def altmro():
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 @@ def test_mutable_bases_with_failing_mro():
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 subclass_right_op():
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():
diff --git a/Lib/test/test_metaclass.py b/Lib/test/test_metaclass.py
new file mode 100644
index 0000000..df81079
--- /dev/null
+++ b/Lib/test/test_metaclass.py
@@ -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)
diff --git a/Lib/unittest.py b/Lib/unittest.py
index cde310f..eab0372 100644
--- a/Lib/unittest.py
+++ b/Lib/unittest.py
@@ -84,9 +84,6 @@ if sys.version_info[:2] < (2, 2):
# 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__)