1
2cimport cython
3
4class Base(type):
5    def __new__(cls, name, bases, attrs):
6        attrs['metaclass_was_here'] = True
7        return type.__new__(cls, name, bases, attrs)
8
9@cython.test_assert_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
10class Foo(object):
11    """
12    >>> obj = Foo()
13    >>> obj.metaclass_was_here
14    True
15    """
16    __metaclass__ = Base
17
18
19def non_type_metaclass(name, bases, namespace):
20    namespace['BASES'] = [b.__name__ for b in bases]
21    namespace['NAME'] = name
22    return type(name, bases, namespace)
23
24class FunctionAsPy2Metaclass(object):
25    """
26    >>> obj = FunctionAsPy2Metaclass()
27    >>> obj.NAME
28    'FunctionAsPy2Metaclass'
29    >>> obj.BASES
30    ['object']
31    >>> obj.x
32    1
33    """
34    __metaclass__ = non_type_metaclass
35    x = 1
36
37
38class ODict(dict):
39    def __init__(self):
40        dict.__init__(self)
41        self._order = []
42        dict.__setitem__(self, '_order', self._order)
43
44    def __setitem__(self, key, value):
45        dict.__setitem__(self, key, value)
46        self._order.append(key)
47
48class Py3MetaclassPlusAttr(type):
49    def __new__(cls, name, bases, attrs, **kwargs):
50        assert isinstance(attrs, ODict), str(type(attrs))
51        for key, value in kwargs.items():
52            attrs[key] = value
53        attrs['metaclass_was_here'] = True
54        return type.__new__(cls, name, bases, attrs)
55
56    def __init__(self, cls, attrs, obj, **kwargs):
57        pass
58
59    @staticmethod
60    def __prepare__(*args, **kwargs):
61        return ODict()
62
63@cython.test_fail_if_path_exists("//PyClassMetaclassNode")
64@cython.test_assert_path_exists("//Py3ClassNode")
65class Py3ClassMCOnly(object, metaclass=Py3MetaclassPlusAttr):
66    """
67    >>> obj = Py3ClassMCOnly()
68    >>> obj.bar
69    321
70    >>> obj.metaclass_was_here
71    True
72    >>> obj._order
73    ['__module__', '__qualname__', '__doc__', 'bar', 'metaclass_was_here']
74    """
75    bar = 321
76
77class Py3InheritedMetaclass(Py3ClassMCOnly):
78    """
79    >>> obj = Py3InheritedMetaclass()
80    >>> obj.bar
81    345
82    >>> obj.metaclass_was_here
83    True
84    >>> obj._order
85    ['__module__', '__qualname__', '__doc__', 'bar', 'metaclass_was_here']
86    """
87    bar = 345
88
89class Py3Base(type):
90    def __new__(cls, name, bases, attrs, **kwargs):
91        assert isinstance(attrs, ODict), str(type(attrs))
92        for key, value in kwargs.items():
93            attrs[key] = value
94        return type.__new__(cls, name, bases, attrs)
95
96    def __init__(self, cls, attrs, obj, **kwargs):
97        pass
98
99    @staticmethod
100    def __prepare__(*args, **kwargs):
101        return ODict()
102
103@cython.test_fail_if_path_exists("//PyClassMetaclassNode")
104@cython.test_assert_path_exists("//Py3ClassNode")
105class Py3Foo(object, metaclass=Py3Base, foo=123):
106    """
107    >>> obj = Py3Foo()
108    >>> obj.foo
109    123
110    >>> obj.bar
111    321
112    >>> obj._order
113    ['__module__', '__qualname__', '__doc__', 'bar', 'foo']
114    """
115    bar = 321
116
117@cython.test_assert_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
118class Py3FooInherited(Py3Foo, foo=567):
119    """
120    >>> obj = Py3FooInherited()
121    >>> obj.foo
122    567
123    >>> obj.bar
124    321
125    >>> obj._order
126    ['__module__', '__qualname__', '__doc__', 'bar', 'foo']
127    """
128    bar = 321
129
130kwargs = {'foo': 123, 'bar': 456}
131
132@cython.test_assert_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
133class Py3Mixed(metaclass=Py3Base, **kwargs):
134    """
135    >>> Py3Mixed.foo
136    123
137    >>> Py3Mixed.bar
138    456
139    """
140
141kwargs['metaclass'] = Py3Base
142
143@cython.test_assert_path_exists("//PyClassMetaclassNode")
144class Py3Kwargs(**kwargs):
145    """
146    >>> Py3Kwargs.foo
147    123
148    >>> Py3Kwargs.bar
149    456
150    """
151
152class Base3(type):
153    def __new__(cls, name, bases, attrs, **kwargs):
154        kwargs['b'] = 2
155        return type.__new__(cls, name, bases, attrs)
156
157    def __init__(self, *args, **kwargs):
158        self.kwargs = kwargs
159
160    @staticmethod
161    def __prepare__(*args, **kwargs):
162        kwargs['a'] = 1
163        return {}
164
165kwargs = {'c': 0}
166
167@cython.test_assert_path_exists("//PyClassMetaclassNode", "//Py3ClassNode")
168class Foo3(metaclass=Base3, a=0, b=0, **kwargs):
169    """
170    >>> sorted(Foo3.kwargs.items())
171    [('a', 0), ('b', 0), ('c', 0)]
172    """
173
174class PyClassWithNew(object):
175    """
176    >>> PyClassWithNew(389)
177    389
178    """
179    def __new__(self, arg):
180        return arg
181