/pypy/module/cpyext/typeobject.py
Python | 662 lines | 517 code | 84 blank | 61 comment | 89 complexity | e11a996b3bbd53535e1215cbdef7b772 MD5 | raw file
1import os
2import sys
3
4from pypy.rpython.lltypesystem import rffi, lltype
5from pypy.rpython.annlowlevel import llhelper
6from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
7from pypy.objspace.std.typeobject import W_TypeObject
8from pypy.interpreter.typedef import GetSetProperty
9from pypy.module.cpyext.api import (
10 cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
11 generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
12 Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
13 Py_TPFLAGS_HAVE_GETCHARBUFFER,
14 build_type_checkers)
15from pypy.module.cpyext.pyobject import (
16 PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
17 track_reference, RefcountState, borrow_from)
18from pypy.interpreter.module import Module
19from pypy.module.cpyext import structmemberdefs
20from pypy.module.cpyext.modsupport import convert_method_defs
21from pypy.module.cpyext.state import State
22from pypy.module.cpyext.methodobject import (
23 PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef)
24from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef, _Py_Dealloc
25from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
26from pypy.module.cpyext.typeobjectdefs import (
27 PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
28 PyNumberMethods, PySequenceMethods, PyBufferProcs)
29from pypy.module.cpyext.slotdefs import (
30 slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
31from pypy.interpreter.error import OperationError
32from pypy.rlib.rstring import rsplit
33from pypy.rlib.objectmodel import specialize
34from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
35from pypy.module.__builtin__.interp_classobj import W_ClassObject
36from pypy.rlib import jit
37
38WARN_ABOUT_MISSING_SLOT_FUNCTIONS = False
39
40PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type")
41
42class W_GetSetPropertyEx(GetSetProperty):
43 def __init__(self, getset, w_type):
44 self.getset = getset
45 self.name = rffi.charp2str(getset.c_name)
46 self.w_type = w_type
47 doc = set = get = None
48 if doc:
49 doc = rffi.charp2str(getset.c_doc)
50 if getset.c_get:
51 get = GettersAndSetters.getter.im_func
52 if getset.c_set:
53 set = GettersAndSetters.setter.im_func
54 GetSetProperty.__init__(self, get, set, None, doc,
55 cls=None, use_closure=True,
56 tag="cpyext_1")
57
58def PyDescr_NewGetSet(space, getset, w_type):
59 return space.wrap(W_GetSetPropertyEx(getset, w_type))
60
61class W_MemberDescr(GetSetProperty):
62 def __init__(self, member, w_type):
63 self.member = member
64 self.name = rffi.charp2str(member.c_name)
65 self.w_type = w_type
66 flags = rffi.cast(lltype.Signed, member.c_flags)
67 doc = set = None
68 if member.c_doc:
69 doc = rffi.charp2str(member.c_doc)
70 get = GettersAndSetters.member_getter.im_func
71 del_ = GettersAndSetters.member_delete.im_func
72 if not (flags & structmemberdefs.READONLY):
73 set = GettersAndSetters.member_setter.im_func
74 GetSetProperty.__init__(self, get, set, del_, doc,
75 cls=None, use_closure=True,
76 tag="cpyext_2")
77
78def convert_getset_defs(space, dict_w, getsets, w_type):
79 getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
80 if getsets:
81 i = -1
82 while True:
83 i = i + 1
84 getset = getsets[i]
85 name = getset.c_name
86 if not name:
87 break
88 name = rffi.charp2str(name)
89 w_descr = PyDescr_NewGetSet(space, getset, w_type)
90 dict_w[name] = w_descr
91
92def convert_member_defs(space, dict_w, members, w_type):
93 members = rffi.cast(rffi.CArrayPtr(PyMemberDef), members)
94 if members:
95 i = 0
96 while True:
97 member = members[i]
98 name = member.c_name
99 if not name:
100 break
101 name = rffi.charp2str(name)
102 w_descr = space.wrap(W_MemberDescr(member, w_type))
103 dict_w[name] = w_descr
104 i += 1
105
106def update_all_slots(space, w_type, pto):
107 # XXX fill slots in pto
108
109 typedef = w_type.instancetypedef
110 for method_name, slot_name, slot_names, slot_func in slotdefs_for_tp_slots:
111 w_descr = w_type.lookup(method_name)
112 if w_descr is None:
113 # XXX special case iternext
114 continue
115
116 slot_func_helper = None
117
118 if slot_func is None and typedef is not None:
119 get_slot = get_slot_tp_function(space, typedef, slot_name)
120 if get_slot:
121 slot_func_helper = get_slot()
122 elif slot_func:
123 slot_func_helper = llhelper(slot_func.api_func.functype,
124 slot_func.api_func.get_wrapper(space))
125
126 if slot_func_helper is None:
127 if WARN_ABOUT_MISSING_SLOT_FUNCTIONS:
128 os.write(2, method_name + " defined by the type but no slot function defined!\n")
129 continue
130
131 # XXX special case wrapper-functions and use a "specific" slot func
132
133 if len(slot_names) == 1:
134 setattr(pto, slot_names[0], slot_func_helper)
135 else:
136 assert len(slot_names) == 2
137 struct = getattr(pto, slot_names[0])
138 if not struct:
139 if slot_names[0] == 'c_tp_as_number':
140 STRUCT_TYPE = PyNumberMethods
141 elif slot_names[0] == 'c_tp_as_sequence':
142 STRUCT_TYPE = PySequenceMethods
143 else:
144 raise AssertionError(
145 "Structure not allocated: %s" % (slot_names[0],))
146 struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
147 setattr(pto, slot_names[0], struct)
148
149 setattr(struct, slot_names[1], slot_func_helper)
150
151def add_operators(space, dict_w, pto):
152 # XXX support PyObject_HashNotImplemented
153 for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
154 if method_name in dict_w:
155 continue
156 if len(slot_names) == 1:
157 func = getattr(pto, slot_names[0])
158 else:
159 assert len(slot_names) == 2
160 struct = getattr(pto, slot_names[0])
161 if not struct:
162 continue
163 func = getattr(struct, slot_names[1])
164 func_voidp = rffi.cast(rffi.VOIDP, func)
165 if not func:
166 continue
167 if wrapper_func is None and wrapper_func_kwds is None:
168 continue
169 dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
170 wrapper_func_kwds, doc, func_voidp)
171 if pto.c_tp_new:
172 add_tp_new_wrapper(space, dict_w, pto)
173
174@cpython_api([PyObject, PyObject, PyObject], PyObject, external=False)
175def tp_new_wrapper(space, self, w_args, w_kwds):
176 tp_new = rffi.cast(PyTypeObjectPtr, self).c_tp_new
177
178 # Check that the user doesn't do something silly and unsafe like
179 # object.__new__(dict). To do this, we check that the most
180 # derived base that's not a heap type is this type.
181 # XXX do it
182
183 args_w = space.fixedview(w_args)
184 w_subtype = args_w[0]
185 w_args = space.newtuple(args_w[1:])
186
187 subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
188 try:
189 w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
190 finally:
191 Py_DecRef(space, w_subtype)
192 return w_obj
193
194@specialize.memo()
195def get_new_method_def(space):
196 state = space.fromcache(State)
197 if state.new_method_def:
198 return state.new_method_def
199 from pypy.module.cpyext.modsupport import PyMethodDef
200 ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
201 immortal=True)
202 ptr.c_ml_name = rffi.str2charp("__new__")
203 lltype.render_immortal(ptr.c_ml_name)
204 rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
205 ptr.c_ml_doc = rffi.str2charp(
206 "T.__new__(S, ...) -> a new object with type S, a subtype of T")
207 lltype.render_immortal(ptr.c_ml_doc)
208 state.new_method_def = ptr
209 return ptr
210
211def setup_new_method_def(space):
212 ptr = get_new_method_def(space)
213 ptr.c_ml_meth = rffi.cast(PyCFunction_typedef,
214 llhelper(tp_new_wrapper.api_func.functype,
215 tp_new_wrapper.api_func.get_wrapper(space)))
216
217def add_tp_new_wrapper(space, dict_w, pto):
218 if "__new__" in dict_w:
219 return
220 pyo = rffi.cast(PyObject, pto)
221 dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
222 from_ref(space, pyo), None)
223
224def inherit_special(space, pto, base_pto):
225 # XXX missing: copy basicsize and flags in a magical way
226 flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
227 base_object_pyo = make_ref(space, space.w_object)
228 base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
229 if base_pto != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE:
230 if not pto.c_tp_new:
231 pto.c_tp_new = base_pto.c_tp_new
232 Py_DecRef(space, base_object_pyo)
233
234def check_descr(space, w_self, w_type):
235 if not space.is_true(space.isinstance(w_self, w_type)):
236 raise DescrMismatch()
237
238class GettersAndSetters:
239 def getter(self, space, w_self):
240 assert isinstance(self, W_GetSetPropertyEx)
241 check_descr(space, w_self, self.w_type)
242 return generic_cpy_call(
243 space, self.getset.c_get, w_self,
244 self.getset.c_closure)
245
246 def setter(self, space, w_self, w_value):
247 assert isinstance(self, W_GetSetPropertyEx)
248 check_descr(space, w_self, self.w_type)
249 res = generic_cpy_call(
250 space, self.getset.c_set, w_self, w_value,
251 self.getset.c_closure)
252 if rffi.cast(lltype.Signed, res) < 0:
253 state = space.fromcache(State)
254 state.check_and_raise_exception()
255
256 def member_getter(self, space, w_self):
257 assert isinstance(self, W_MemberDescr)
258 check_descr(space, w_self, self.w_type)
259 return PyMember_GetOne(space, w_self, self.member)
260
261 def member_delete(self, space, w_self):
262 assert isinstance(self, W_MemberDescr)
263 check_descr(space, w_self, self.w_type)
264 PyMember_SetOne(space, w_self, self.member, None)
265
266 def member_setter(self, space, w_self, w_value):
267 assert isinstance(self, W_MemberDescr)
268 check_descr(space, w_self, self.w_type)
269 PyMember_SetOne(space, w_self, self.member, w_value)
270
271class W_PyCTypeObject(W_TypeObject):
272 @jit.dont_look_inside
273 def __init__(self, space, pto):
274 bases_w = space.fixedview(from_ref(space, pto.c_tp_bases))
275 dict_w = {}
276
277 add_operators(space, dict_w, pto)
278 convert_method_defs(space, dict_w, pto.c_tp_methods, self)
279 convert_getset_defs(space, dict_w, pto.c_tp_getset, self)
280 convert_member_defs(space, dict_w, pto.c_tp_members, self)
281
282 full_name = rffi.charp2str(pto.c_tp_name)
283 if '.' in full_name:
284 module_name, extension_name = rsplit(full_name, ".", 1)
285 dict_w["__module__"] = space.wrap(module_name)
286 else:
287 extension_name = full_name
288
289 W_TypeObject.__init__(self, space, extension_name,
290 bases_w or [space.w_object], dict_w)
291 if not space.is_true(space.issubtype(self, space.w_type)):
292 self.flag_cpytype = True
293 self.flag_heaptype = False
294
295@bootstrap_function
296def init_typeobject(space):
297 # Probably a hack
298 space.model.typeorder[W_PyCTypeObject] = [(W_PyCTypeObject, None),
299 (W_TypeObject, None),
300 (W_Root, None)]
301
302 make_typedescr(space.w_type.instancetypedef,
303 basestruct=PyTypeObject,
304 attach=type_attach,
305 realize=type_realize,
306 dealloc=type_dealloc)
307
308 # some types are difficult to create because of cycles.
309 # - object.ob_type = type
310 # - type.ob_type = type
311 # - tuple.ob_type = type
312 # - type.tp_base = object
313 # - tuple.tp_base = object
314 # - type.tp_bases is a tuple
315 # - object.tp_bases is a tuple
316 # - tuple.tp_bases is a tuple
317
318 # insert null placeholders to please create_ref()
319 track_reference(space, lltype.nullptr(PyObject.TO), space.w_type)
320 track_reference(space, lltype.nullptr(PyObject.TO), space.w_object)
321 track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple)
322
323 # create the objects
324 py_type = create_ref(space, space.w_type)
325 py_object = create_ref(space, space.w_object)
326 py_tuple = create_ref(space, space.w_tuple)
327
328 # form cycles
329 pto_type = rffi.cast(PyTypeObjectPtr, py_type)
330 py_type.c_ob_type = pto_type
331 py_object.c_ob_type = pto_type
332 py_tuple.c_ob_type = pto_type
333
334 pto_object = rffi.cast(PyTypeObjectPtr, py_object)
335 pto_type.c_tp_base = pto_object
336 pto_tuple = rffi.cast(PyTypeObjectPtr, py_tuple)
337 pto_tuple.c_tp_base = pto_object
338
339 pto_type.c_tp_bases.c_ob_type = pto_tuple
340 pto_object.c_tp_bases.c_ob_type = pto_tuple
341 pto_tuple.c_tp_bases.c_ob_type = pto_tuple
342
343 # Restore the mapping
344 track_reference(space, py_type, space.w_type, replace=True)
345 track_reference(space, py_object, space.w_object, replace=True)
346 track_reference(space, py_tuple, space.w_tuple, replace=True)
347
348
349@cpython_api([PyObject], lltype.Void, external=False)
350def subtype_dealloc(space, obj):
351 pto = obj.c_ob_type
352 base = pto
353 this_func_ptr = llhelper(subtype_dealloc.api_func.functype,
354 subtype_dealloc.api_func.get_wrapper(space))
355 while base.c_tp_dealloc == this_func_ptr:
356 base = base.c_tp_base
357 assert base
358 dealloc = base.c_tp_dealloc
359 # XXX call tp_del if necessary
360 generic_cpy_call(space, dealloc, obj)
361 # XXX cpy decrefs the pto here but we do it in the base-dealloc
362 # hopefully this does not clash with the memory model assumed in
363 # extension modules
364
365@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False,
366 error=CANNOT_FAIL)
367def str_segcount(space, w_obj, ref):
368 if ref:
369 ref[0] = space.len_w(w_obj)
370 return 1
371
372@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
373 external=False, error=-1)
374def str_getreadbuffer(space, w_str, segment, ref):
375 from pypy.module.cpyext.stringobject import PyString_AsString
376 if segment != 0:
377 raise OperationError(space.w_SystemError, space.wrap
378 ("accessing non-existent string segment"))
379 pyref = make_ref(space, w_str)
380 ref[0] = PyString_AsString(space, pyref)
381 # Stolen reference: the object has better exist somewhere else
382 Py_DecRef(space, pyref)
383 return space.len_w(w_str)
384
385@cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
386 external=False, error=-1)
387def str_getcharbuffer(space, w_str, segment, ref):
388 from pypy.module.cpyext.stringobject import PyString_AsString
389 if segment != 0:
390 raise OperationError(space.w_SystemError, space.wrap
391 ("accessing non-existent string segment"))
392 pyref = make_ref(space, w_str)
393 ref[0] = PyString_AsString(space, pyref)
394 # Stolen reference: the object has better exist somewhere else
395 Py_DecRef(space, pyref)
396 return space.len_w(w_str)
397
398def setup_string_buffer_procs(space, pto):
399 c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
400 c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
401 str_segcount.api_func.get_wrapper(space))
402 c_buf.c_bf_getreadbuffer = llhelper(str_getreadbuffer.api_func.functype,
403 str_getreadbuffer.api_func.get_wrapper(space))
404 c_buf.c_bf_getcharbuffer = llhelper(str_getcharbuffer.api_func.functype,
405 str_getcharbuffer.api_func.get_wrapper(space))
406 pto.c_tp_as_buffer = c_buf
407 pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
408
409@cpython_api([PyObject], lltype.Void, external=False)
410def type_dealloc(space, obj):
411 from pypy.module.cpyext.object import PyObject_dealloc
412 obj_pto = rffi.cast(PyTypeObjectPtr, obj)
413 base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
414 Py_DecRef(space, obj_pto.c_tp_bases)
415 Py_DecRef(space, obj_pto.c_tp_mro)
416 Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
417 Py_DecRef(space, obj_pto.c_tp_dict)
418 if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
419 if obj_pto.c_tp_as_buffer:
420 lltype.free(obj_pto.c_tp_as_buffer, flavor='raw')
421 if obj_pto.c_tp_as_number:
422 lltype.free(obj_pto.c_tp_as_number, flavor='raw')
423 if obj_pto.c_tp_as_sequence:
424 lltype.free(obj_pto.c_tp_as_sequence, flavor='raw')
425 Py_DecRef(space, base_pyo)
426 rffi.free_charp(obj_pto.c_tp_name)
427 PyObject_dealloc(space, obj)
428
429
430def type_attach(space, py_obj, w_type):
431 """
432 Fills a newly allocated PyTypeObject from an existing type.
433 """
434 from pypy.module.cpyext.object import PyObject_Del
435
436 assert isinstance(w_type, W_TypeObject)
437
438 pto = rffi.cast(PyTypeObjectPtr, py_obj)
439
440 typedescr = get_typedescr(w_type.instancetypedef)
441
442 # dealloc
443 pto.c_tp_dealloc = typedescr.get_dealloc(space)
444 # buffer protocol
445 if space.is_w(w_type, space.w_str):
446 setup_string_buffer_procs(space, pto)
447
448 pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE
449 pto.c_tp_free = llhelper(PyObject_Del.api_func.functype,
450 PyObject_Del.api_func.get_wrapper(space))
451 pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype,
452 PyType_GenericAlloc.api_func.get_wrapper(space))
453 pto.c_tp_name = rffi.str2charp(w_type.getname(space, "?"))
454 pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out
455 pto.c_tp_itemsize = 0
456 # uninitialized fields:
457 # c_tp_print, c_tp_getattr, c_tp_setattr
458 # XXX implement
459 # c_tp_compare and the following fields (see http://docs.python.org/c-api/typeobj.html )
460 w_base = best_base(space, w_type.bases_w)
461 pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
462
463 finish_type_1(space, pto)
464 finish_type_2(space, pto, w_type)
465
466 pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
467 if pto.c_tp_base:
468 if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
469 pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
470
471 # will be filled later on with the correct value
472 # may not be 0
473 if space.is_w(w_type, space.w_object):
474 pto.c_tp_new = rffi.cast(newfunc, 1)
475 update_all_slots(space, w_type, pto)
476 pto.c_tp_flags |= Py_TPFLAGS_READY
477 return pto
478
479@cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
480def PyType_Ready(space, pto):
481 if pto.c_tp_flags & Py_TPFLAGS_READY:
482 return 0
483 type_realize(space, rffi.cast(PyObject, pto))
484 return 0
485
486def type_realize(space, py_obj):
487 pto = rffi.cast(PyTypeObjectPtr, py_obj)
488 assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
489 pto.c_tp_flags |= Py_TPFLAGS_READYING
490 try:
491 w_obj = _type_realize(space, py_obj)
492 finally:
493 pto.c_tp_flags &= ~Py_TPFLAGS_READYING
494 pto.c_tp_flags |= Py_TPFLAGS_READY
495 return w_obj
496
497def solid_base(space, w_type):
498 typedef = w_type.instancetypedef
499 return space.gettypeobject(typedef)
500
501def best_base(space, bases_w):
502 if not bases_w:
503 return None
504
505 w_winner = None
506 w_base = None
507 for w_base_i in bases_w:
508 if isinstance(w_base_i, W_ClassObject):
509 # old-style base
510 continue
511 assert isinstance(w_base_i, W_TypeObject)
512 w_candidate = solid_base(space, w_base_i)
513 if not w_winner:
514 w_winner = w_candidate
515 w_base = w_base_i
516 elif space.abstract_issubclass_w(w_winner, w_candidate):
517 pass
518 elif space.abstract_issubclass_w(w_candidate, w_winner):
519 w_winner = w_candidate
520 w_base = w_base_i
521 else:
522 raise OperationError(
523 space.w_TypeError,
524 space.wrap("multiple bases have instance lay-out conflict"))
525 if w_base is None:
526 raise OperationError(
527 space.w_TypeError,
528 space.wrap("a new-style class can't have only classic bases"))
529
530 return w_base
531
532def inherit_slots(space, pto, w_base):
533 # XXX missing: nearly everything
534 base_pyo = make_ref(space, w_base)
535 try:
536 base = rffi.cast(PyTypeObjectPtr, base_pyo)
537 if not pto.c_tp_dealloc:
538 pto.c_tp_dealloc = base.c_tp_dealloc
539 if not pto.c_tp_init:
540 pto.c_tp_init = base.c_tp_init
541 if not pto.c_tp_alloc:
542 pto.c_tp_alloc = base.c_tp_alloc
543 # XXX check for correct GC flags!
544 if not pto.c_tp_free:
545 pto.c_tp_free = base.c_tp_free
546 if not pto.c_tp_setattro:
547 pto.c_tp_setattro = base.c_tp_setattro
548 finally:
549 Py_DecRef(space, base_pyo)
550
551def _type_realize(space, py_obj):
552 """
553 Creates an interpreter type from a PyTypeObject structure.
554 """
555 # missing:
556 # setting __doc__ if not defined and tp_doc defined
557 # inheriting tp_as_* slots
558 # unsupported:
559 # tp_mro, tp_subclasses
560 py_type = rffi.cast(PyTypeObjectPtr, py_obj)
561
562 if not py_type.c_tp_base:
563 # borrowed reference, but w_object is unlikely to disappear
564 base = make_ref(space, space.w_object)
565 Py_DecRef(space, base)
566 py_type.c_tp_base = rffi.cast(PyTypeObjectPtr, base)
567
568 finish_type_1(space, py_type)
569
570 w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
571
572 w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
573 track_reference(space, py_obj, w_obj)
574 w_obj.__init__(space, py_type)
575 w_obj.ready()
576
577 finish_type_2(space, py_type, w_obj)
578
579 state = space.fromcache(RefcountState)
580 state.non_heaptypes_w.append(w_obj)
581
582 return w_obj
583
584def finish_type_1(space, pto):
585 """
586 Sets up tp_bases, necessary before creating the interpreter type.
587 """
588 base = pto.c_tp_base
589 base_pyo = rffi.cast(PyObject, pto.c_tp_base)
590 if base and not base.c_tp_flags & Py_TPFLAGS_READY:
591 type_realize(space, rffi.cast(PyObject, base_pyo))
592 if base and not pto.c_ob_type: # will be filled later
593 pto.c_ob_type = base.c_ob_type
594 if not pto.c_tp_bases:
595 if not base:
596 bases = space.newtuple([])
597 else:
598 bases = space.newtuple([from_ref(space, base_pyo)])
599 pto.c_tp_bases = make_ref(space, bases)
600
601def finish_type_2(space, pto, w_obj):
602 """
603 Sets up other attributes, when the interpreter type has been created.
604 """
605 pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
606 base = pto.c_tp_base
607 if base:
608 inherit_special(space, pto, base)
609 for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
610 inherit_slots(space, pto, w_base)
611
612 if not pto.c_tp_setattro:
613 from pypy.module.cpyext.object import PyObject_GenericSetAttr
614 pto.c_tp_setattro = llhelper(
615 PyObject_GenericSetAttr.api_func.functype,
616 PyObject_GenericSetAttr.api_func.get_wrapper(space))
617
618 if w_obj.is_cpytype():
619 Py_DecRef(space, pto.c_tp_dict)
620 w_dict = w_obj.getdict(space)
621 pto.c_tp_dict = make_ref(space, w_dict)
622
623@cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
624def PyType_IsSubtype(space, a, b):
625 """Return true if a is a subtype of b.
626 """
627 w_type1 = from_ref(space, rffi.cast(PyObject, a))
628 w_type2 = from_ref(space, rffi.cast(PyObject, b))
629 return int(abstract_issubclass_w(space, w_type1, w_type2)) #XXX correct?
630
631@cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject)
632def PyType_GenericAlloc(space, type, nitems):
633 from pypy.module.cpyext.object import _PyObject_NewVar
634 return _PyObject_NewVar(space, type, nitems)
635
636@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject)
637def PyType_GenericNew(space, type, w_args, w_kwds):
638 return generic_cpy_call(
639 space, type.c_tp_alloc, type, 0)
640
641@cpython_api([PyTypeObjectPtr, PyObject], PyObject, error=CANNOT_FAIL)
642def _PyType_Lookup(space, type, w_name):
643 """Internal API to look for a name through the MRO.
644 This returns a borrowed reference, and doesn't set an exception!"""
645 w_type = from_ref(space, rffi.cast(PyObject, type))
646 assert isinstance(w_type, W_TypeObject)
647
648 if not space.isinstance_w(w_name, space.w_str):
649 return None
650 name = space.str_w(w_name)
651 w_obj = w_type.lookup(name)
652 return borrow_from(w_type, w_obj)
653
654@cpython_api([PyTypeObjectPtr], lltype.Void)
655def PyType_Modified(space, w_obj):
656 """Invalidate the internal lookup cache for the type and all of its
657 subtypes. This function must be called after any manual
658 modification of the attributes or base classes of the type.
659 """
660 # PyPy already takes care of direct modifications to type.__dict__
661 # (which is a W_DictProxyObject).
662 pass