PageRenderTime 23ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cpyext/typeobject.py

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