PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cpyext/object.py

https://bitbucket.org/dac_io/pypy
Python | 482 lines | 422 code | 29 blank | 31 comment | 8 complexity | fa43479ea50817cab806662c8d1f4512 MD5 | raw file
  1. from pypy.rpython.lltypesystem import rffi, lltype
  2. from pypy.module.cpyext.api import (
  3. cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
  4. PyVarObject, Py_buffer,
  5. Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
  6. Py_GE, CONST_STRING, FILEP, fwrite)
  7. from pypy.module.cpyext.pyobject import (
  8. PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef,
  9. track_reference, get_typedescr, _Py_NewReference, RefcountState)
  10. from pypy.module.cpyext.typeobject import PyTypeObjectPtr
  11. from pypy.module.cpyext.pyerrors import PyErr_NoMemory, PyErr_BadInternalCall
  12. from pypy.objspace.std.typeobject import W_TypeObject
  13. from pypy.interpreter.error import OperationError
  14. import pypy.module.__builtin__.operation as operation
  15. @cpython_api([Py_ssize_t], rffi.VOIDP)
  16. def PyObject_MALLOC(space, size):
  17. return lltype.malloc(rffi.VOIDP.TO, size,
  18. flavor='raw', zero=True)
  19. @cpython_api([rffi.VOIDP], lltype.Void)
  20. def PyObject_FREE(space, ptr):
  21. lltype.free(ptr, flavor='raw')
  22. @cpython_api([PyTypeObjectPtr], PyObject)
  23. def _PyObject_New(space, type):
  24. return _PyObject_NewVar(space, type, 0)
  25. @cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject)
  26. def _PyObject_NewVar(space, type, itemcount):
  27. w_type = from_ref(space, rffi.cast(PyObject, type))
  28. assert isinstance(w_type, W_TypeObject)
  29. typedescr = get_typedescr(w_type.instancetypedef)
  30. py_obj = typedescr.allocate(space, w_type, itemcount=itemcount)
  31. py_obj.c_ob_refcnt = 0
  32. if type.c_tp_itemsize == 0:
  33. w_obj = PyObject_Init(space, py_obj, type)
  34. else:
  35. py_objvar = rffi.cast(PyVarObject, py_obj)
  36. w_obj = PyObject_InitVar(space, py_objvar, type, itemcount)
  37. return py_obj
  38. @cpython_api([rffi.VOIDP], lltype.Void)
  39. def PyObject_Del(space, obj):
  40. lltype.free(obj, flavor='raw')
  41. @cpython_api([PyObject], lltype.Void)
  42. def PyObject_dealloc(space, obj):
  43. pto = obj.c_ob_type
  44. obj_voidp = rffi.cast(rffi.VOIDP, obj)
  45. generic_cpy_call(space, pto.c_tp_free, obj_voidp)
  46. if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
  47. Py_DecRef(space, rffi.cast(PyObject, pto))
  48. @cpython_api([PyTypeObjectPtr], PyObject)
  49. def _PyObject_GC_New(space, type):
  50. return _PyObject_New(space, type)
  51. @cpython_api([rffi.VOIDP], lltype.Void)
  52. def PyObject_GC_Del(space, obj):
  53. PyObject_Del(space, obj)
  54. @cpython_api([rffi.VOIDP], lltype.Void)
  55. def PyObject_GC_Track(space, op):
  56. """Adds the object op to the set of container objects tracked by the
  57. collector. The collector can run at unexpected times so objects must be
  58. valid while being tracked. This should be called once all the fields
  59. followed by the tp_traverse handler become valid, usually near the
  60. end of the constructor."""
  61. pass
  62. @cpython_api([rffi.VOIDP], lltype.Void)
  63. def PyObject_GC_UnTrack(space, op):
  64. """Remove the object op from the set of container objects tracked by the
  65. collector. Note that PyObject_GC_Track() can be called again on
  66. this object to add it back to the set of tracked objects. The deallocator
  67. (tp_dealloc handler) should call this for the object before any of
  68. the fields used by the tp_traverse handler become invalid."""
  69. pass
  70. @cpython_api([PyObject], PyObjectP, error=CANNOT_FAIL)
  71. def _PyObject_GetDictPtr(space, op):
  72. return lltype.nullptr(PyObjectP.TO)
  73. @cpython_api([PyObject], rffi.INT_real, error=-1)
  74. def PyObject_IsTrue(space, w_obj):
  75. return space.is_true(w_obj)
  76. @cpython_api([PyObject], rffi.INT_real, error=-1)
  77. def PyObject_Not(space, w_obj):
  78. return not space.is_true(w_obj)
  79. @cpython_api([PyObject, PyObject], PyObject)
  80. def PyObject_GetAttr(space, w_obj, w_name):
  81. """Retrieve an attribute named attr_name from object o. Returns the attribute
  82. value on success, or NULL on failure. This is the equivalent of the Python
  83. expression o.attr_name."""
  84. return space.getattr(w_obj, w_name)
  85. @cpython_api([PyObject, CONST_STRING], PyObject)
  86. def PyObject_GetAttrString(space, w_obj, name_ptr):
  87. """Retrieve an attribute named attr_name from object o. Returns the attribute
  88. value on success, or NULL on failure. This is the equivalent of the Python
  89. expression o.attr_name."""
  90. name = rffi.charp2str(name_ptr)
  91. return space.getattr(w_obj, space.wrap(name))
  92. @cpython_api([PyObject, PyObject], rffi.INT_real, error=CANNOT_FAIL)
  93. def PyObject_HasAttr(space, w_obj, w_name):
  94. try:
  95. w_res = operation.hasattr(space, w_obj, w_name)
  96. return space.is_true(w_res)
  97. except OperationError:
  98. return 0
  99. @cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=CANNOT_FAIL)
  100. def PyObject_HasAttrString(space, w_obj, name_ptr):
  101. try:
  102. name = rffi.charp2str(name_ptr)
  103. w_res = operation.hasattr(space, w_obj, space.wrap(name))
  104. return space.is_true(w_res)
  105. except OperationError:
  106. return 0
  107. @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
  108. def PyObject_SetAttr(space, w_obj, w_name, w_value):
  109. operation.setattr(space, w_obj, w_name, w_value)
  110. return 0
  111. @cpython_api([PyObject, CONST_STRING, PyObject], rffi.INT_real, error=-1)
  112. def PyObject_SetAttrString(space, w_obj, name_ptr, w_value):
  113. w_name = space.wrap(rffi.charp2str(name_ptr))
  114. operation.setattr(space, w_obj, w_name, w_value)
  115. return 0
  116. @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
  117. def PyObject_DelAttr(space, w_obj, w_name):
  118. """Delete attribute named attr_name, for object o. Returns -1 on failure.
  119. This is the equivalent of the Python statement del o.attr_name."""
  120. space.delattr(w_obj, w_name)
  121. return 0
  122. @cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=-1)
  123. def PyObject_DelAttrString(space, w_obj, name_ptr):
  124. """Delete attribute named attr_name, for object o. Returns -1 on failure.
  125. This is the equivalent of the Python statement del o.attr_name."""
  126. w_name = space.wrap(rffi.charp2str(name_ptr))
  127. space.delattr(w_obj, w_name)
  128. return 0
  129. @cpython_api([PyObject], lltype.Void)
  130. def PyObject_ClearWeakRefs(space, w_object):
  131. w_object.clear_all_weakrefs()
  132. @cpython_api([PyObject], Py_ssize_t, error=-1)
  133. def PyObject_Size(space, w_obj):
  134. return space.len_w(w_obj)
  135. @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
  136. def PyCallable_Check(space, w_obj):
  137. """Determine if the object o is callable. Return 1 if the object is callable
  138. and 0 otherwise. This function always succeeds."""
  139. return int(space.is_true(space.callable(w_obj)))
  140. @cpython_api([PyObject, PyObject], PyObject)
  141. def PyObject_GetItem(space, w_obj, w_key):
  142. """Return element of o corresponding to the object key or NULL on failure.
  143. This is the equivalent of the Python expression o[key]."""
  144. return space.getitem(w_obj, w_key)
  145. @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
  146. def PyObject_SetItem(space, w_obj, w_key, w_value):
  147. """Map the object key to the value v. Returns -1 on failure. This is the
  148. equivalent of the Python statement o[key] = v."""
  149. space.setitem(w_obj, w_key, w_value)
  150. return 0
  151. @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
  152. def PyObject_DelItem(space, w_obj, w_key):
  153. """Delete the mapping for key from o. Returns -1 on failure. This is the
  154. equivalent of the Python statement del o[key]."""
  155. space.delitem(w_obj, w_key)
  156. return 0
  157. @cpython_api([PyObject, PyTypeObjectPtr], PyObject)
  158. def PyObject_Init(space, obj, type):
  159. """Initialize a newly-allocated object op with its type and initial
  160. reference. Returns the initialized object. If type indicates that the
  161. object participates in the cyclic garbage detector, it is added to the
  162. detector's set of observed objects. Other fields of the object are not
  163. affected."""
  164. if not obj:
  165. PyErr_NoMemory(space)
  166. obj.c_ob_type = type
  167. obj.c_ob_refcnt = 1
  168. return obj
  169. @cpython_api([PyVarObject, PyTypeObjectPtr, Py_ssize_t], PyObject)
  170. def PyObject_InitVar(space, py_obj, type, size):
  171. """This does everything PyObject_Init() does, and also initializes the
  172. length information for a variable-size object."""
  173. if not py_obj:
  174. PyErr_NoMemory(space)
  175. py_obj.c_ob_size = size
  176. return PyObject_Init(space, rffi.cast(PyObject, py_obj), type)
  177. @cpython_api([PyObject], PyObject)
  178. def PyObject_Type(space, w_obj):
  179. """When o is non-NULL, returns a type object corresponding to the object type
  180. of object o. On failure, raises SystemError and returns NULL. This
  181. is equivalent to the Python expression type(o). This function increments the
  182. reference count of the return value. There's really no reason to use this
  183. function instead of the common expression o->ob_type, which returns a
  184. pointer of type PyTypeObject*, except when the incremented reference
  185. count is needed."""
  186. return space.type(w_obj)
  187. @cpython_api([PyObject], PyObject)
  188. def PyObject_Str(space, w_obj):
  189. return space.str(w_obj)
  190. @cpython_api([PyObject], PyObject)
  191. def PyObject_Repr(space, w_obj):
  192. """Compute a string representation of object o. Returns the string
  193. representation on success, NULL on failure. This is the equivalent of the
  194. Python expression repr(o). Called by the repr() built-in function and
  195. by reverse quotes."""
  196. return space.repr(w_obj)
  197. @cpython_api([PyObject], PyObject)
  198. def PyObject_Unicode(space, w_obj):
  199. """Compute a Unicode string representation of object o. Returns the Unicode
  200. string representation on success, NULL on failure. This is the equivalent of
  201. the Python expression unicode(o). Called by the unicode() built-in
  202. function."""
  203. return space.call_function(space.w_unicode, w_obj)
  204. @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
  205. def PyObject_Compare(space, w_o1, w_o2):
  206. """
  207. Compare the values of o1 and o2 using a routine provided by o1, if one
  208. exists, otherwise with a routine provided by o2. Returns the result of the
  209. comparison on success. On error, the value returned is undefined; use
  210. PyErr_Occurred() to detect an error. This is equivalent to the Python
  211. expression cmp(o1, o2)."""
  212. return space.int_w(space.cmp(w_o1, w_o2))
  213. @cpython_api([PyObject, PyObject, rffi.INTP], rffi.INT_real, error=-1)
  214. def PyObject_Cmp(space, w_o1, w_o2, result):
  215. """Compare the values of o1 and o2 using a routine provided by o1, if one
  216. exists, otherwise with a routine provided by o2. The result of the
  217. comparison is returned in result. Returns -1 on failure. This is the
  218. equivalent of the Python statement result = cmp(o1, o2)."""
  219. res = space.int_w(space.cmp(w_o1, w_o2))
  220. result[0] = rffi.cast(rffi.INT, res)
  221. return 0
  222. @cpython_api([PyObject, PyObject, rffi.INT_real], PyObject)
  223. def PyObject_RichCompare(space, w_o1, w_o2, opid_int):
  224. """Compare the values of o1 and o2 using the operation specified by opid,
  225. which must be one of Py_LT, Py_LE, Py_EQ,
  226. Py_NE, Py_GT, or Py_GE, corresponding to <,
  227. <=, ==, !=, >, or >= respectively. This is the equivalent of
  228. the Python expression o1 op o2, where op is the operator corresponding
  229. to opid. Returns the value of the comparison on success, or NULL on failure."""
  230. opid = rffi.cast(lltype.Signed, opid_int)
  231. if opid == Py_LT: return space.lt(w_o1, w_o2)
  232. if opid == Py_LE: return space.le(w_o1, w_o2)
  233. if opid == Py_EQ: return space.eq(w_o1, w_o2)
  234. if opid == Py_NE: return space.ne(w_o1, w_o2)
  235. if opid == Py_GT: return space.gt(w_o1, w_o2)
  236. if opid == Py_GE: return space.ge(w_o1, w_o2)
  237. PyErr_BadInternalCall(space)
  238. @cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
  239. def PyObject_RichCompareBool(space, ref1, ref2, opid):
  240. """Compare the values of o1 and o2 using the operation specified by opid,
  241. which must be one of Py_LT, Py_LE, Py_EQ,
  242. Py_NE, Py_GT, or Py_GE, corresponding to <,
  243. <=, ==, !=, >, or >= respectively. Returns -1 on error,
  244. 0 if the result is false, 1 otherwise. This is the equivalent of the
  245. Python expression o1 op o2, where op is the operator corresponding to
  246. opid."""
  247. w_res = PyObject_RichCompare(space, ref1, ref2, opid)
  248. return int(space.is_true(w_res))
  249. @cpython_api([PyObject], PyObject)
  250. def PyObject_SelfIter(space, ref):
  251. """Undocumented function, this is wat CPython does."""
  252. Py_IncRef(space, ref)
  253. return ref
  254. @cpython_api([PyObject, PyObject], PyObject)
  255. def PyObject_GenericGetAttr(space, w_obj, w_name):
  256. """Generic attribute getter function that is meant to be put into a type
  257. object's tp_getattro slot. It looks for a descriptor in the dictionary
  258. of classes in the object's MRO as well as an attribute in the object's
  259. __dict__ (if present). As outlined in descriptors, data
  260. descriptors take preference over instance attributes, while non-data
  261. descriptors don't. Otherwise, an AttributeError is raised."""
  262. from pypy.objspace.descroperation import object_getattribute
  263. w_descr = object_getattribute(space)
  264. return space.get_and_call_function(w_descr, w_obj, w_name)
  265. @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
  266. def PyObject_GenericSetAttr(space, w_obj, w_name, w_value):
  267. """Generic attribute setter function that is meant to be put into a type
  268. object's tp_setattro slot. It looks for a data descriptor in the
  269. dictionary of classes in the object's MRO, and if found it takes preference
  270. over setting the attribute in the instance dictionary. Otherwise, the
  271. attribute is set in the object's __dict__ (if present). Otherwise,
  272. an AttributeError is raised and -1 is returned."""
  273. from pypy.objspace.descroperation import object_setattr, object_delattr
  274. if w_value is not None:
  275. w_descr = object_setattr(space)
  276. space.get_and_call_function(w_descr, w_obj, w_name, w_value)
  277. else:
  278. w_descr = object_delattr(space)
  279. space.get_and_call_function(w_descr, w_obj, w_name)
  280. return 0
  281. @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
  282. def PyObject_IsInstance(space, w_inst, w_cls):
  283. """Returns 1 if inst is an instance of the class cls or a subclass of
  284. cls, or 0 if not. On error, returns -1 and sets an exception. If
  285. cls is a type object rather than a class object, PyObject_IsInstance()
  286. returns 1 if inst is of type cls. If cls is a tuple, the check will
  287. be done against every entry in cls. The result will be 1 when at least one
  288. of the checks returns 1, otherwise it will be 0. If inst is not a class
  289. instance and cls is neither a type object, nor a class object, nor a
  290. tuple, inst must have a __class__ attribute --- the class relationship
  291. of the value of that attribute with cls will be used to determine the result
  292. of this function."""
  293. from pypy.module.__builtin__.abstractinst import abstract_isinstance_w
  294. return abstract_isinstance_w(space, w_inst, w_cls)
  295. @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
  296. def PyObject_IsSubclass(space, w_derived, w_cls):
  297. """Returns 1 if the class derived is identical to or derived from the class
  298. cls, otherwise returns 0. In case of an error, returns -1. If cls
  299. is a tuple, the check will be done against every entry in cls. The result will
  300. be 1 when at least one of the checks returns 1, otherwise it will be
  301. 0. If either derived or cls is not an actual class object (or tuple),
  302. this function uses the generic algorithm described above."""
  303. from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
  304. return abstract_issubclass_w(space, w_derived, w_cls)
  305. @cpython_api([PyObject], rffi.INT_real, error=-1)
  306. def PyObject_AsFileDescriptor(space, w_obj):
  307. """Derives a file descriptor from a Python object. If the object is an
  308. integer or long integer, its value is returned. If not, the object's
  309. fileno() method is called if it exists; the method must return an integer or
  310. long integer, which is returned as the file descriptor value. Returns -1 on
  311. failure."""
  312. try:
  313. fd = space.int_w(w_obj)
  314. except OperationError:
  315. try:
  316. w_meth = space.getattr(w_obj, space.wrap('fileno'))
  317. except OperationError:
  318. raise OperationError(
  319. space.w_TypeError, space.wrap(
  320. "argument must be an int, or have a fileno() method."))
  321. else:
  322. w_fd = space.call_function(w_meth)
  323. fd = space.int_w(w_fd)
  324. if fd < 0:
  325. raise OperationError(
  326. space.w_ValueError, space.wrap(
  327. "file descriptor cannot be a negative integer"))
  328. return rffi.cast(rffi.INT_real, fd)
  329. @cpython_api([PyObject], lltype.Signed, error=-1)
  330. def PyObject_Hash(space, w_obj):
  331. """
  332. Compute and return the hash value of an object o. On failure, return -1.
  333. This is the equivalent of the Python expression hash(o)."""
  334. return space.int_w(space.hash(w_obj))
  335. @cpython_api([PyObject], PyObject)
  336. def PyObject_Dir(space, w_o):
  337. """This is equivalent to the Python expression dir(o), returning a (possibly
  338. empty) list of strings appropriate for the object argument, or NULL if there
  339. was an error. If the argument is NULL, this is like the Python dir(),
  340. returning the names of the current locals; in this case, if no execution frame
  341. is active then NULL is returned but PyErr_Occurred() will return false."""
  342. return space.call_function(space.builtin.get('dir'), w_o)
  343. @cpython_api([PyObject, rffi.CCHARPP, Py_ssize_tP], rffi.INT_real, error=-1)
  344. def PyObject_AsCharBuffer(space, obj, bufferp, sizep):
  345. """Returns a pointer to a read-only memory location usable as
  346. character-based input. The obj argument must support the single-segment
  347. character buffer interface. On success, returns 0, sets buffer to the
  348. memory location and size to the buffer length. Returns -1 and sets a
  349. TypeError on error.
  350. """
  351. pto = obj.c_ob_type
  352. pb = pto.c_tp_as_buffer
  353. if not (pb and pb.c_bf_getreadbuffer and pb.c_bf_getsegcount):
  354. raise OperationError(space.w_TypeError, space.wrap(
  355. "expected a character buffer object"))
  356. if generic_cpy_call(space, pb.c_bf_getsegcount,
  357. obj, lltype.nullptr(Py_ssize_tP.TO)) != 1:
  358. raise OperationError(space.w_TypeError, space.wrap(
  359. "expected a single-segment buffer object"))
  360. size = generic_cpy_call(space, pb.c_bf_getcharbuffer,
  361. obj, 0, bufferp)
  362. if size < 0:
  363. return -1
  364. sizep[0] = size
  365. return 0
  366. # Also in include/object.h
  367. Py_PRINT_RAW = 1 # No string quotes etc.
  368. @cpython_api([PyObject, FILEP, rffi.INT_real], rffi.INT_real, error=-1)
  369. def PyObject_Print(space, w_obj, fp, flags):
  370. """Print an object o, on file fp. Returns -1 on error. The flags argument
  371. is used to enable certain printing options. The only option currently
  372. supported is Py_PRINT_RAW; if given, the str() of the object is written
  373. instead of the repr()."""
  374. if rffi.cast(lltype.Signed, flags) & Py_PRINT_RAW:
  375. w_str = space.str(w_obj)
  376. else:
  377. w_str = space.repr(w_obj)
  378. count = space.len_w(w_str)
  379. data = space.str_w(w_str)
  380. buf = rffi.get_nonmovingbuffer(data)
  381. try:
  382. fwrite(buf, 1, count, fp)
  383. finally:
  384. rffi.free_nonmovingbuffer(data, buf)
  385. return 0
  386. PyBUF_WRITABLE = 0x0001 # Copied from object.h
  387. @cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, Py_ssize_t,
  388. lltype.Signed, lltype.Signed], rffi.INT, error=CANNOT_FAIL)
  389. def PyBuffer_FillInfo(space, view, obj, buf, length, readonly, flags):
  390. """
  391. Fills in a buffer-info structure correctly for an exporter that can only
  392. share a contiguous chunk of memory of "unsigned bytes" of the given
  393. length. Returns 0 on success and -1 (with raising an error) on error.
  394. This is not a complete re-implementation of the CPython API; it only
  395. provides a subset of CPython's behavior.
  396. """
  397. view.c_buf = buf
  398. view.c_len = length
  399. view.c_obj = obj
  400. Py_IncRef(space, obj)
  401. view.c_itemsize = 1
  402. if flags & PyBUF_WRITABLE:
  403. rffi.setintfield(view, 'c_readonly', 0)
  404. else:
  405. rffi.setintfield(view, 'c_readonly', 1)
  406. rffi.setintfield(view, 'c_ndim', 0)
  407. view.c_format = lltype.nullptr(rffi.CCHARP.TO)
  408. view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
  409. view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
  410. view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
  411. view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
  412. return 0
  413. @cpython_api([lltype.Ptr(Py_buffer)], lltype.Void, error=CANNOT_FAIL)
  414. def PyBuffer_Release(space, view):
  415. """
  416. Releases a Py_buffer obtained from getbuffer ParseTuple's s*.
  417. This is not a complete re-implementation of the CPython API; it only
  418. provides a subset of CPython's behavior.
  419. """
  420. Py_DecRef(space, view.c_obj)