1# ticket: 808
2
3cimport cython
4
5cdef class MyType:
6    cdef public args, kwargs
7    def __cinit__(self, *args, **kwargs):
8        self.args, self.kwargs = args, kwargs
9        print "CINIT"
10    def __init__(self, *args, **kwargs):
11        print "INIT"
12
13cdef class MySubType(MyType):
14    def __cinit__(self, *args, **kwargs):
15        self.args, self.kwargs = args, kwargs
16        print "CINIT(SUB)"
17    def __init__(self, *args, **kwargs):
18        print "INIT"
19
20class MyClass(object):
21    def __cinit__(self, *args, **kwargs):
22        self.args, self.kwargs = args, kwargs
23        print "CINIT"
24    def __init__(self, *args, **kwargs):
25        print "INIT"
26
27class MyTypeSubClass(MyType):
28    def __cinit__(self, *args, **kwargs):
29        # not called: Python class!
30        print "CINIT(PYSUB)"
31    def __init__(self, *args, **kwargs):
32        print "INIT"
33
34# See ticket T808, vtab must be set even if there is no __cinit__.
35
36cdef class Base(object):
37    pass
38
39cdef class Derived(Base):
40    cpdef int f(self):
41        return 42
42
43def test_derived_vtab():
44    """
45    >>> test_derived_vtab()
46    42
47    """
48    cdef Derived d = Derived.__new__(Derived)
49    return d.f()
50
51
52# only these can be safely optimised:
53
54@cython.test_assert_path_exists('//PythonCapiCallNode')
55@cython.test_fail_if_path_exists(
56    '//SimpleCallNode/AttributeNode',
57    '//PyMethodCallNode',
58)
59def make_new():
60    """
61    >>> isinstance(make_new(), MyType)
62    CINIT
63    True
64    """
65    m = MyType.__new__(MyType)
66    return m
67
68@cython.test_assert_path_exists('//PythonCapiCallNode')
69@cython.test_fail_if_path_exists(
70    '//SimpleCallNode/AttributeNode',
71    '//PyMethodCallNode',
72)
73def make_new_typed_target():
74    """
75    >>> isinstance(make_new_typed_target(), MyType)
76    CINIT
77    True
78    """
79    cdef MyType m
80    m = MyType.__new__(MyType)
81    return m
82
83@cython.test_assert_path_exists('//PythonCapiCallNode')
84@cython.test_fail_if_path_exists(
85    '//SimpleCallNode/AttributeNode',
86    '//PyMethodCallNode',
87)
88def make_new_with_args():
89    """
90    >>> isinstance(make_new_with_args(), MyType)
91    CINIT
92    (1, 2, 3)
93    {}
94    True
95    """
96    m = MyType.__new__(MyType, 1, 2 ,3)
97    print m.args
98    print m.kwargs
99    return m
100
101@cython.test_assert_path_exists('//PythonCapiCallNode')
102@cython.test_fail_if_path_exists(
103    '//SimpleCallNode/AttributeNode',
104    '//PyMethodCallNode',
105)
106def make_new_with_args_kwargs():
107    """
108    >>> isinstance(make_new_with_args_kwargs(), MyType)
109    CINIT
110    (1, 2, 3)
111    {'a': 4}
112    True
113    """
114    m = MyType.__new__(MyType, 1, 2 ,3, a=4)
115    print m.args
116    print m.kwargs
117    return m
118
119@cython.test_assert_path_exists('//PythonCapiCallNode')
120@cython.test_fail_if_path_exists(
121    '//SimpleCallNode/AttributeNode',
122    '//PyMethodCallNode',
123)
124def make_new_builtin():
125    """
126    >>> isinstance(make_new_builtin(), tuple)
127    True
128    """
129    m = dict.__new__(dict)
130    m = list.__new__(list)
131    m = tuple.__new__(tuple)
132    return m
133
134@cython.test_assert_path_exists('//PythonCapiCallNode')
135@cython.test_fail_if_path_exists(
136    '//SimpleCallNode/AttributeNode',
137    '//PyMethodCallNode',
138)
139def make_new_none(type t=None):
140    """
141    >>> make_new_none()  # doctest: +ELLIPSIS
142    Traceback (most recent call last):
143    TypeError: ... is not a type object (NoneType)
144    """
145    m = t.__new__(t)
146    return m
147
148@cython.test_assert_path_exists('//PythonCapiCallNode')
149@cython.test_fail_if_path_exists(
150    '//SimpleCallNode/AttributeNode',
151    '//PyMethodCallNode',
152)
153def make_new_kwargs(type t=None):
154    """
155    >>> m = make_new_kwargs(MyType)
156    CINIT
157    >>> isinstance(m, MyType)
158    True
159    >>> m.args
160    (1, 2, 3)
161    >>> m.kwargs
162    {'a': 5}
163    """
164    m = t.__new__(t, 1, 2, 3, a=5)
165    return m
166
167# these cannot:
168
169@cython.test_assert_path_exists('//PyMethodCallNode/AttributeNode')
170@cython.test_fail_if_path_exists('//PythonCapiCallNode')
171def make_new_pyclass():
172    """
173    >>> isinstance(make_new_pyclass(), MyTypeSubClass)
174    CINIT
175    True
176    """
177    m = MyClass.__new__(MyClass)
178    m = MyTypeSubClass.__new__(MyTypeSubClass)
179    return m
180
181@cython.test_assert_path_exists('//PyMethodCallNode/AttributeNode')
182@cython.test_fail_if_path_exists('//PythonCapiCallNode')
183def make_new_args(type t1=None, type t2=None):
184    """
185    >>> isinstance(make_new_args(), MyType)
186    CINIT
187    True
188    >>> isinstance(make_new_args(MyType), MyType)
189    CINIT
190    True
191    >>> isinstance(make_new_args(MyType, MyType), MyType)
192    CINIT
193    True
194
195    >>> isinstance(make_new_args(MyType, MySubType), MySubType)
196    Traceback (most recent call last):
197    TypeError: tp_new.MyType.__new__(tp_new.MySubType) is not safe, use tp_new.MySubType.__new__()
198    >>> isinstance(make_new_args(MySubType, MyType), MyType)
199    Traceback (most recent call last):
200    TypeError: tp_new.MySubType.__new__(tp_new.MyType): tp_new.MyType is not a subtype of tp_new.MySubType
201    """
202    if t1 is None:
203        t1 = MyType
204    if t2 is None:
205        t2 = MyType
206    m = t1.__new__(t2)
207    return m
208
209@cython.test_assert_path_exists('//PyMethodCallNode/AttributeNode')
210@cython.test_fail_if_path_exists('//PythonCapiCallNode')
211def make_new_none_typed(tuple t=None):
212    """
213    >>> make_new_none_typed()  # doctest: +ELLIPSIS
214    Traceback (most recent call last):
215    TypeError: ... is not a type object (NoneType)
216    """
217    m = t.__new__(t)
218    return m
219
220@cython.test_assert_path_exists('//PyMethodCallNode/AttributeNode')
221@cython.test_fail_if_path_exists('//PythonCapiCallNode')
222def make_new_untyped(t):
223    """
224    >>> make_new_untyped(None)  # doctest: +ELLIPSIS
225    Traceback (most recent call last):
226    TypeError: ... is not a type object (NoneType)
227    """
228    m = t.__new__(t)
229    return m
230