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

/pypy/module/cpyext/test/test_typeobject.py

https://bitbucket.org/pjenvey/pypy-mq
Python | 1151 lines | 1101 code | 31 blank | 19 comment | 3 complexity | bf3947a62681317fa2333d22d569b299 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0, BSD-3-Clause
  1. from pypy.interpreter import gateway
  2. from rpython.rtyper.lltypesystem import rffi
  3. from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
  4. from pypy.module.cpyext.test.test_api import BaseApiTest
  5. from pypy.module.cpyext.pyobject import make_ref, from_ref
  6. from pypy.module.cpyext.typeobject import PyTypeObjectPtr
  7. class AppTestTypeObject(AppTestCpythonExtensionBase):
  8. def test_typeobject(self):
  9. import sys
  10. module = self.import_module(name='foo')
  11. assert 'foo' in sys.modules
  12. assert "copy" in dir(module.fooType)
  13. obj = module.new()
  14. print(obj.foo)
  15. assert obj.foo == 42
  16. print("Obj has type", type(obj))
  17. assert type(obj) is module.fooType
  18. print("type of obj has type", type(type(obj)))
  19. print("type of type of obj has type", type(type(type(obj))))
  20. assert module.fooType.__doc__ == "foo is for testing."
  21. def test_typeobject_method_descriptor(self):
  22. module = self.import_module(name='foo')
  23. obj = module.new()
  24. obj2 = obj.copy()
  25. assert module.new().name == "Foo Example"
  26. c = module.fooType.copy
  27. assert not "im_func" in dir(module.fooType.copy)
  28. assert module.fooType.copy.__objclass__ is module.fooType
  29. assert "copy" in repr(module.fooType.copy)
  30. assert repr(module.fooType) == "<type 'foo.foo'>"
  31. assert repr(obj2) == "<Foo>"
  32. assert repr(module.fooType.__call__) == "<slot wrapper '__call__' of 'foo.foo' objects>"
  33. assert obj2(foo=1, bar=2) == dict(foo=1, bar=2)
  34. print(obj.foo)
  35. assert obj.foo == 42
  36. assert obj.int_member == obj.foo
  37. def test_typeobject_data_member(self):
  38. module = self.import_module(name='foo')
  39. obj = module.new()
  40. obj.int_member = 23
  41. assert obj.int_member == 23
  42. obj.int_member = 42
  43. raises(TypeError, "obj.int_member = 'not a number'")
  44. raises(TypeError, "del obj.int_member")
  45. raises(TypeError, "obj.int_member_readonly = 42")
  46. exc = raises(TypeError, "del obj.int_member_readonly")
  47. assert "readonly" in str(exc.value)
  48. raises(SystemError, "obj.broken_member")
  49. raises(SystemError, "obj.broken_member = 42")
  50. assert module.fooType.broken_member.__doc__ is None
  51. assert module.fooType.object_member.__doc__ == "A Python object."
  52. assert str(type(module.fooType.int_member)) == "<type 'member_descriptor'>"
  53. def test_typeobject_object_member(self):
  54. module = self.import_module(name='foo')
  55. obj = module.new()
  56. assert obj.object_member is None
  57. obj.object_member = "hello"
  58. assert obj.object_member == "hello"
  59. del obj.object_member
  60. del obj.object_member
  61. assert obj.object_member is None
  62. raises(AttributeError, "obj.object_member_ex")
  63. obj.object_member_ex = None
  64. assert obj.object_member_ex is None
  65. obj.object_member_ex = 42
  66. assert obj.object_member_ex == 42
  67. del obj.object_member_ex
  68. raises(AttributeError, "del obj.object_member_ex")
  69. obj.set_foo = 32
  70. assert obj.foo == 32
  71. def test_typeobject_string_member(self):
  72. module = self.import_module(name='foo')
  73. obj = module.new()
  74. assert obj.string_member == "Hello from PyPy"
  75. raises(TypeError, "obj.string_member = 42")
  76. raises(TypeError, "del obj.string_member")
  77. obj.unset_string_member()
  78. assert obj.string_member is None
  79. assert obj.string_member_inplace == "spam"
  80. raises(TypeError, "obj.string_member_inplace = 42")
  81. raises(TypeError, "del obj.string_member_inplace")
  82. assert obj.char_member == "s"
  83. obj.char_member = "a"
  84. assert obj.char_member == "a"
  85. raises(TypeError, "obj.char_member = 'spam'")
  86. raises(TypeError, "obj.char_member = 42")
  87. #
  88. import sys
  89. bignum = sys.maxint - 42
  90. obj.short_member = -12345; assert obj.short_member == -12345
  91. obj.long_member = -bignum; assert obj.long_member == -bignum
  92. obj.ushort_member = 45678; assert obj.ushort_member == 45678
  93. obj.uint_member = 3000000000; assert obj.uint_member == 3000000000
  94. obj.ulong_member = 2*bignum; assert obj.ulong_member == 2*bignum
  95. obj.byte_member = -99; assert obj.byte_member == -99
  96. obj.ubyte_member = 199; assert obj.ubyte_member == 199
  97. obj.bool_member = True; assert obj.bool_member is True
  98. obj.float_member = 9.25; assert obj.float_member == 9.25
  99. obj.double_member = 9.25; assert obj.double_member == 9.25
  100. obj.longlong_member = -2**59; assert obj.longlong_member == -2**59
  101. obj.ulonglong_member = 2**63; assert obj.ulonglong_member == 2**63
  102. obj.ssizet_member = sys.maxint;assert obj.ssizet_member == sys.maxint
  103. #
  104. def test_staticmethod(self):
  105. module = self.import_module(name="foo")
  106. obj = module.fooType.create()
  107. assert obj.foo == 42
  108. obj2 = obj.create()
  109. assert obj2.foo == 42
  110. def test_classmethod(self):
  111. module = self.import_module(name="foo")
  112. obj = module.fooType.classmeth()
  113. assert obj is module.fooType
  114. def test_new(self):
  115. # XXX cpython segfaults but if run singly (with -k test_new) this passes
  116. module = self.import_module(name='foo')
  117. obj = module.new()
  118. # call __new__
  119. newobj = module.UnicodeSubtype(u"xyz")
  120. assert newobj == u"xyz"
  121. assert isinstance(newobj, module.UnicodeSubtype)
  122. assert isinstance(module.fooType(), module.fooType)
  123. class bar(module.fooType):
  124. pass
  125. assert isinstance(bar(), bar)
  126. fuu = module.UnicodeSubtype
  127. class fuu2(fuu):
  128. def baz(self):
  129. return self
  130. assert fuu2(u"abc").baz().escape()
  131. raises(TypeError, module.fooType.object_member.__get__, 1)
  132. def test_multiple_inheritance(self):
  133. module = self.import_module(name='foo')
  134. obj = module.UnicodeSubtype(u'xyz')
  135. obj2 = module.UnicodeSubtype2()
  136. obj3 = module.UnicodeSubtype3()
  137. assert obj3.get_val() == 42
  138. assert len(type(obj3).mro()) == 6
  139. def test_init(self):
  140. module = self.import_module(name="foo")
  141. newobj = module.UnicodeSubtype()
  142. assert newobj.get_val() == 42
  143. # this subtype should inherit tp_init
  144. newobj = module.UnicodeSubtype2()
  145. assert newobj.get_val() == 42
  146. # this subclass redefines __init__
  147. class UnicodeSubclass2(module.UnicodeSubtype):
  148. def __init__(self):
  149. self.foobar = 32
  150. super(UnicodeSubclass2, self).__init__()
  151. newobj = UnicodeSubclass2()
  152. assert newobj.get_val() == 42
  153. assert newobj.foobar == 32
  154. def test_metatype(self):
  155. module = self.import_module(name='foo')
  156. assert module.MetaType.__mro__ == (module.MetaType, type, object)
  157. x = module.MetaType('name', (), {})
  158. assert isinstance(x, type)
  159. assert isinstance(x, module.MetaType)
  160. x()
  161. def test_metaclass_compatible(self):
  162. # metaclasses should not conflict here
  163. module = self.import_module(name='foo')
  164. assert module.MetaType.__mro__ == (module.MetaType, type, object)
  165. assert type(module.fooType).__mro__ == (type, object)
  166. y = module.MetaType('other', (module.MetaType,), {})
  167. assert isinstance(y, module.MetaType)
  168. x = y('something', (type(y),), {})
  169. del x, y
  170. def test_metaclass_compatible2(self):
  171. skip('fails even with -A, fooType has BASETYPE flag')
  172. # XXX FIX - must raise since fooType (which is a base type)
  173. # does not have flag Py_TPFLAGS_BASETYPE
  174. module = self.import_module(name='foo')
  175. raises(TypeError, module.MetaType, 'other', (module.fooType,), {})
  176. def test_sre(self):
  177. import sys
  178. for m in ['_sre', 'sre_compile', 'sre_constants', 'sre_parse', 're']:
  179. # clear out these modules
  180. try:
  181. del sys.modules[m]
  182. except KeyError:
  183. pass
  184. module = self.import_module(name='_sre')
  185. import re
  186. assert re.sre_compile._sre is module
  187. s = u"Foo " * 1000 + u"Bar"
  188. prog = re.compile(ur"Foo.*Bar")
  189. assert prog.match(s)
  190. m = re.search(u"xyz", u"xyzxyz")
  191. assert m
  192. m = re.search("xyz", "xyzxyz")
  193. assert m
  194. assert "groupdict" in dir(m)
  195. re._cache.clear()
  196. re._cache_repl.clear()
  197. del prog, m
  198. def test_init_error(self):
  199. module = self.import_module("foo")
  200. raises(ValueError, module.InitErrType)
  201. def test_cmps(self):
  202. module = self.import_module("comparisons")
  203. cmpr = module.CmpType()
  204. assert cmpr == 3
  205. assert cmpr != 42
  206. def test_richcompare(self):
  207. module = self.import_module("comparisons")
  208. cmpr = module.CmpType()
  209. # should not crash
  210. cmpr < 4
  211. cmpr <= 4
  212. cmpr > 4
  213. cmpr >= 4
  214. assert cmpr.__le__(4) is NotImplemented
  215. def test_tpcompare(self):
  216. module = self.import_module("comparisons")
  217. cmpr = module.OldCmpType()
  218. assert cmpr < cmpr
  219. def test_hash(self):
  220. module = self.import_module("comparisons")
  221. cmpr = module.CmpType()
  222. assert hash(cmpr) == 3
  223. d = {}
  224. d[cmpr] = 72
  225. assert d[cmpr] == 72
  226. assert d[3] == 72
  227. def test_descriptor(self):
  228. module = self.import_module("foo")
  229. prop = module.Property()
  230. class C(object):
  231. x = prop
  232. obj = C()
  233. assert obj.x == (prop, obj, C)
  234. assert C.x == (prop, None, C)
  235. obj.x = 2
  236. assert obj.y == (prop, 2)
  237. del obj.x
  238. assert obj.z == prop
  239. def test_tp_dict(self):
  240. foo = self.import_module("foo")
  241. module = self.import_extension('test', [
  242. ("read_tp_dict", "METH_O",
  243. '''
  244. PyObject *method;
  245. if (!args->ob_type->tp_dict)
  246. {
  247. PyErr_SetNone(PyExc_ValueError);
  248. return NULL;
  249. }
  250. method = PyDict_GetItemString(
  251. args->ob_type->tp_dict, "copy");
  252. Py_INCREF(method);
  253. return method;
  254. '''),
  255. ("get_type_dict", "METH_O",
  256. '''
  257. PyObject* value = args->ob_type->tp_dict;
  258. if (value == NULL) value = Py_None;
  259. Py_INCREF(value);
  260. return value;
  261. '''),
  262. ])
  263. obj = foo.new()
  264. assert module.read_tp_dict(obj) == foo.fooType.copy
  265. d = module.get_type_dict(obj)
  266. assert type(d) is dict
  267. d["_some_attribute"] = 1
  268. assert type(obj)._some_attribute == 1
  269. del d["_some_attribute"]
  270. class A(object):
  271. pass
  272. obj = A()
  273. d = module.get_type_dict(obj)
  274. assert type(d) is dict
  275. d["_some_attribute"] = 1
  276. assert type(obj)._some_attribute == 1
  277. del d["_some_attribute"]
  278. d = module.get_type_dict(1)
  279. assert type(d) is dict
  280. try:
  281. d["_some_attribute"] = 1
  282. except TypeError: # on PyPy, int.__dict__ is really immutable
  283. pass
  284. else:
  285. assert int._some_attribute == 1
  286. del d["_some_attribute"]
  287. def test_custom_allocation(self):
  288. foo = self.import_module("foo")
  289. obj = foo.newCustom()
  290. assert type(obj) is foo.Custom
  291. assert type(foo.Custom) is foo.MetaType
  292. def test_heaptype(self):
  293. module = self.import_extension('foo', [
  294. ("name_by_heaptype", "METH_O",
  295. '''
  296. PyHeapTypeObject *heaptype = (PyHeapTypeObject *)args;
  297. Py_INCREF(heaptype->ht_name);
  298. return heaptype->ht_name;
  299. '''
  300. )
  301. ])
  302. class C(object):
  303. pass
  304. assert module.name_by_heaptype(C) == "C"
  305. def test_type_dict(self):
  306. foo = self.import_module("foo")
  307. module = self.import_extension('test', [
  308. ("hack_tp_dict", "METH_O",
  309. '''
  310. PyTypeObject *type = args->ob_type;
  311. PyObject *a1 = PyLong_FromLong(1);
  312. PyObject *a2 = PyLong_FromLong(2);
  313. PyObject *value;
  314. if (PyDict_SetItemString(type->tp_dict, "a",
  315. a1) < 0)
  316. return NULL;
  317. Py_DECREF(a1);
  318. PyType_Modified(type);
  319. value = PyObject_GetAttrString((PyObject*)type, "a");
  320. Py_DECREF(value);
  321. if (PyDict_SetItemString(type->tp_dict, "a",
  322. a2) < 0)
  323. return NULL;
  324. Py_DECREF(a2);
  325. PyType_Modified(type);
  326. value = PyObject_GetAttrString((PyObject*)type, "a");
  327. return value;
  328. '''
  329. )
  330. ])
  331. obj = foo.new()
  332. assert module.hack_tp_dict(obj) == 2
  333. class TestTypes(BaseApiTest):
  334. def test_type_attributes(self, space, api):
  335. w_class = space.appexec([], """():
  336. class A(object):
  337. pass
  338. return A
  339. """)
  340. ref = make_ref(space, w_class)
  341. py_type = rffi.cast(PyTypeObjectPtr, ref)
  342. assert py_type.c_tp_alloc
  343. assert from_ref(space, py_type.c_tp_mro).wrappeditems is w_class.mro_w
  344. api.Py_DecRef(ref)
  345. def test_type_dict(self, space, api):
  346. w_class = space.appexec([], """():
  347. class A(object):
  348. pass
  349. return A
  350. """)
  351. ref = make_ref(space, w_class)
  352. py_type = rffi.cast(PyTypeObjectPtr, ref)
  353. w_dict = from_ref(space, py_type.c_tp_dict)
  354. w_name = space.wrap('a')
  355. space.setitem(w_dict, w_name, space.wrap(1))
  356. assert space.int_w(space.getattr(w_class, w_name)) == 1
  357. space.delitem(w_dict, w_name)
  358. def test_multiple_inheritance(self, space, api):
  359. w_class = space.appexec([], """():
  360. class A(object):
  361. pass
  362. class B(object):
  363. pass
  364. class C(A, B):
  365. pass
  366. return C
  367. """)
  368. ref = make_ref(space, w_class)
  369. api.Py_DecRef(ref)
  370. def test_lookup(self, space, api):
  371. w_type = space.w_str
  372. w_obj = api._PyType_Lookup(w_type, space.wrap("upper"))
  373. assert space.is_w(w_obj, space.w_str.getdictvalue(space, "upper"))
  374. w_obj = api._PyType_Lookup(w_type, space.wrap("__invalid"))
  375. assert w_obj is None
  376. assert api.PyErr_Occurred() is None
  377. def test_ndarray_ref(self, space, api):
  378. w_obj = space.appexec([], """():
  379. import _numpypy
  380. return _numpypy.multiarray.dtype('int64').type(2)""")
  381. ref = make_ref(space, w_obj)
  382. api.Py_DecRef(ref)
  383. class AppTestSlots(AppTestCpythonExtensionBase):
  384. def setup_class(cls):
  385. AppTestCpythonExtensionBase.setup_class.im_func(cls)
  386. def _check_type_object(w_X):
  387. assert w_X.is_cpytype()
  388. assert not w_X.is_heaptype()
  389. cls.w__check_type_object = cls.space.wrap(
  390. gateway.interp2app(_check_type_object))
  391. def test_some_slots(self):
  392. module = self.import_extension('foo', [
  393. ("test_type", "METH_O",
  394. '''
  395. /* "args->ob_type" is a strange way to get at 'type',
  396. which should have a different tp_getattro/tp_setattro
  397. than its tp_base, which is 'object'.
  398. */
  399. if (!args->ob_type->tp_setattro)
  400. {
  401. PyErr_SetString(PyExc_ValueError, "missing tp_setattro");
  402. return NULL;
  403. }
  404. if (args->ob_type->tp_setattro ==
  405. args->ob_type->tp_base->tp_setattro)
  406. {
  407. /* Note that unlike CPython, in PyPy 'type.tp_setattro'
  408. is the same function as 'object.tp_setattro'. This
  409. test used to check that it was not, but that was an
  410. artifact of the bootstrap logic only---in the final
  411. C sources I checked and they are indeed the same.
  412. So we ignore this problem here. */
  413. }
  414. if (!args->ob_type->tp_getattro)
  415. {
  416. PyErr_SetString(PyExc_ValueError, "missing tp_getattro");
  417. return NULL;
  418. }
  419. if (args->ob_type->tp_getattro ==
  420. args->ob_type->tp_base->tp_getattro)
  421. {
  422. PyErr_SetString(PyExc_ValueError, "recursive tp_getattro");
  423. return NULL;
  424. }
  425. Py_RETURN_TRUE;
  426. '''
  427. )
  428. ])
  429. assert module.test_type(type(None))
  430. def test_tp_getattro(self):
  431. module = self.import_extension('foo', [
  432. ("test_tp_getattro", "METH_VARARGS",
  433. '''
  434. PyObject *name, *obj = PyTuple_GET_ITEM(args, 0);
  435. PyIntObject *attr, *value = (PyIntObject*) PyTuple_GET_ITEM(args, 1);
  436. if (!obj->ob_type->tp_getattro)
  437. {
  438. PyErr_SetString(PyExc_ValueError, "missing tp_getattro");
  439. return NULL;
  440. }
  441. name = PyString_FromString("attr1");
  442. attr = (PyIntObject*) obj->ob_type->tp_getattro(obj, name);
  443. if (attr->ob_ival != value->ob_ival)
  444. {
  445. PyErr_SetString(PyExc_ValueError,
  446. "tp_getattro returned wrong value");
  447. return NULL;
  448. }
  449. Py_DECREF(name);
  450. Py_DECREF(attr);
  451. name = PyString_FromString("attr2");
  452. attr = (PyIntObject*) obj->ob_type->tp_getattro(obj, name);
  453. if (attr == NULL && PyErr_ExceptionMatches(PyExc_AttributeError))
  454. {
  455. PyErr_Clear();
  456. } else {
  457. PyErr_SetString(PyExc_ValueError,
  458. "tp_getattro should have raised");
  459. return NULL;
  460. }
  461. Py_DECREF(name);
  462. Py_RETURN_TRUE;
  463. '''
  464. )
  465. ])
  466. class C:
  467. def __init__(self):
  468. self.attr1 = 123
  469. assert module.test_tp_getattro(C(), 123)
  470. def test_nb_int(self):
  471. module = self.import_extension('foo', [
  472. ("nb_int", "METH_VARARGS",
  473. '''
  474. PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
  475. PyObject *obj = PyTuple_GET_ITEM(args, 1);
  476. if (!type->tp_as_number ||
  477. !type->tp_as_number->nb_int)
  478. {
  479. PyErr_SetNone(PyExc_ValueError);
  480. return NULL;
  481. }
  482. return type->tp_as_number->nb_int(obj);
  483. '''
  484. )
  485. ])
  486. assert module.nb_int(int, 10) == 10
  487. assert module.nb_int(float, -12.3) == -12
  488. raises(ValueError, module.nb_int, str, "123")
  489. class F(float):
  490. def __int__(self):
  491. return 666
  492. # as long as issue 2248 is not fixed, 'expected' is 666 on pypy,
  493. # but it should be -12. This test is not concerned about that,
  494. # but only about getting the same answer with module.nb_int().
  495. expected = float.__int__(F(-12.3))
  496. assert module.nb_int(float, F(-12.3)) == expected
  497. def test_nb_float(self):
  498. module = self.import_extension('foo', [
  499. ("nb_float", "METH_VARARGS",
  500. '''
  501. PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
  502. PyObject *obj = PyTuple_GET_ITEM(args, 1);
  503. if (!type->tp_as_number ||
  504. !type->tp_as_number->nb_float)
  505. {
  506. PyErr_SetNone(PyExc_ValueError);
  507. return NULL;
  508. }
  509. return type->tp_as_number->nb_float(obj);
  510. '''
  511. )
  512. ])
  513. assert module.nb_float(int, 10) == 10.0
  514. assert module.nb_float(float, -12.3) == -12.3
  515. raises(ValueError, module.nb_float, str, "123")
  516. #
  517. # check that calling PyInt_Type->tp_as_number->nb_float(x)
  518. # does not invoke a user-defined __float__()
  519. class I(int):
  520. def __float__(self):
  521. return -55.55
  522. class F(float):
  523. def __float__(self):
  524. return -66.66
  525. assert float(I(10)) == -55.55
  526. assert float(F(10.5)) == -66.66
  527. assert module.nb_float(int, I(10)) == 10.0
  528. assert module.nb_float(float, F(10.5)) == 10.5
  529. # XXX but the subtype's tp_as_number->nb_float(x) should really invoke
  530. # the user-defined __float__(); it doesn't so far
  531. #assert module.nb_float(I, I(10)) == -55.55
  532. #assert module.nb_float(F, F(10.5)) == -66.66
  533. def test_tp_call(self):
  534. module = self.import_extension('foo', [
  535. ("tp_call", "METH_VARARGS",
  536. '''
  537. PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
  538. PyObject *obj = PyTuple_GET_ITEM(args, 1);
  539. PyObject *c_args = PyTuple_GET_ITEM(args, 2);
  540. if (!type->tp_call)
  541. {
  542. PyErr_SetNone(PyExc_ValueError);
  543. return NULL;
  544. }
  545. return type->tp_call(obj, c_args, NULL);
  546. '''
  547. )
  548. ])
  549. class C:
  550. def __call__(self, *args):
  551. return args
  552. assert module.tp_call(type(C()), C(), ('x', 2)) == ('x', 2)
  553. class D(type):
  554. def __call__(self, *args):
  555. return "foo! %r" % (args,)
  556. typ1 = D('d', (), {})
  557. #assert module.tp_call(D, typ1, ()) == "foo! ()" XXX not working so far
  558. assert isinstance(module.tp_call(type, typ1, ()), typ1)
  559. def test_tp_init(self):
  560. module = self.import_extension('foo', [
  561. ("tp_init", "METH_VARARGS",
  562. '''
  563. PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
  564. PyObject *obj = PyTuple_GET_ITEM(args, 1);
  565. PyObject *c_args = PyTuple_GET_ITEM(args, 2);
  566. if (!type->tp_init)
  567. {
  568. PyErr_SetNone(PyExc_ValueError);
  569. return NULL;
  570. }
  571. if (type->tp_init(obj, c_args, NULL) < 0)
  572. return NULL;
  573. Py_INCREF(Py_None);
  574. return Py_None;
  575. '''
  576. )
  577. ])
  578. x = [42]
  579. assert module.tp_init(list, x, ("hi",)) is None
  580. assert x == ["h", "i"]
  581. class LL(list):
  582. def __init__(self, *ignored):
  583. raise Exception
  584. x = LL.__new__(LL)
  585. assert module.tp_init(list, x, ("hi",)) is None
  586. assert x == ["h", "i"]
  587. def test_tp_str(self):
  588. module = self.import_extension('foo', [
  589. ("tp_str", "METH_VARARGS",
  590. '''
  591. PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
  592. PyObject *obj = PyTuple_GET_ITEM(args, 1);
  593. if (!type->tp_str)
  594. {
  595. PyErr_SetNone(PyExc_ValueError);
  596. return NULL;
  597. }
  598. return type->tp_str(obj);
  599. '''
  600. )
  601. ])
  602. class C:
  603. def __str__(self):
  604. return "text"
  605. assert module.tp_str(type(C()), C()) == "text"
  606. class D(int):
  607. def __str__(self):
  608. return "more text"
  609. assert module.tp_str(int, D(42)) == "42"
  610. def test_mp_ass_subscript(self):
  611. module = self.import_extension('foo', [
  612. ("new_obj", "METH_NOARGS",
  613. '''
  614. PyObject *obj;
  615. Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT;
  616. Foo_Type.tp_as_mapping = &tp_as_mapping;
  617. tp_as_mapping.mp_ass_subscript = mp_ass_subscript;
  618. if (PyType_Ready(&Foo_Type) < 0) return NULL;
  619. obj = PyObject_New(PyObject, &Foo_Type);
  620. return obj;
  621. '''
  622. )],
  623. '''
  624. static int
  625. mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value)
  626. {
  627. if (PyInt_Check(key)) {
  628. PyErr_SetNone(PyExc_ZeroDivisionError);
  629. return -1;
  630. }
  631. return 0;
  632. }
  633. PyMappingMethods tp_as_mapping;
  634. static PyTypeObject Foo_Type = {
  635. PyVarObject_HEAD_INIT(NULL, 0)
  636. "foo.foo",
  637. };
  638. ''')
  639. obj = module.new_obj()
  640. raises(ZeroDivisionError, obj.__setitem__, 5, None)
  641. res = obj.__setitem__('foo', None)
  642. assert res is None
  643. def test_sq_contains(self):
  644. module = self.import_extension('foo', [
  645. ("new_obj", "METH_NOARGS",
  646. '''
  647. PyObject *obj;
  648. Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT;
  649. Foo_Type.tp_as_sequence = &tp_as_sequence;
  650. tp_as_sequence.sq_contains = sq_contains;
  651. if (PyType_Ready(&Foo_Type) < 0) return NULL;
  652. obj = PyObject_New(PyObject, &Foo_Type);
  653. return obj;
  654. '''
  655. )],
  656. '''
  657. static int
  658. sq_contains(PyObject *self, PyObject *value)
  659. {
  660. return 42;
  661. }
  662. PySequenceMethods tp_as_sequence;
  663. static PyTypeObject Foo_Type = {
  664. PyVarObject_HEAD_INIT(NULL, 0)
  665. "foo.foo",
  666. };
  667. ''')
  668. obj = module.new_obj()
  669. res = "foo" in obj
  670. assert res is True
  671. def test_tp_iter(self):
  672. module = self.import_extension('foo', [
  673. ("tp_iter", "METH_VARARGS",
  674. '''
  675. PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
  676. PyObject *obj = PyTuple_GET_ITEM(args, 1);
  677. if (!type->tp_iter)
  678. {
  679. PyErr_SetNone(PyExc_ValueError);
  680. return NULL;
  681. }
  682. return type->tp_iter(obj);
  683. '''
  684. ),
  685. ("tp_iternext", "METH_VARARGS",
  686. '''
  687. PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0);
  688. PyObject *obj = PyTuple_GET_ITEM(args, 1);
  689. PyObject *result;
  690. if (!type->tp_iternext)
  691. {
  692. PyErr_SetNone(PyExc_ValueError);
  693. return NULL;
  694. }
  695. result = type->tp_iternext(obj);
  696. if (!result && !PyErr_Occurred())
  697. result = PyString_FromString("stop!");
  698. return result;
  699. '''
  700. )
  701. ])
  702. l = [1]
  703. it = module.tp_iter(list, l)
  704. assert type(it) is type(iter([]))
  705. assert module.tp_iternext(type(it), it) == 1
  706. assert module.tp_iternext(type(it), it) == "stop!"
  707. #
  708. class LL(list):
  709. def __iter__(self):
  710. return iter(())
  711. ll = LL([1])
  712. it = module.tp_iter(list, ll)
  713. assert type(it) is type(iter([]))
  714. x = list(it)
  715. assert x == [1]
  716. def test_intlike(self):
  717. module = self.import_extension('foo', [
  718. ("newInt", "METH_VARARGS",
  719. """
  720. IntLikeObject *intObj;
  721. int intval;
  722. if (!PyArg_ParseTuple(args, "i", &intval))
  723. return NULL;
  724. intObj = PyObject_New(IntLikeObject, &IntLike_Type);
  725. if (!intObj) {
  726. return NULL;
  727. }
  728. intObj->value = intval;
  729. return (PyObject *)intObj;
  730. """),
  731. ("check", "METH_VARARGS", """
  732. IntLikeObject *intObj;
  733. int intval, isint;
  734. if (!PyArg_ParseTuple(args, "i", &intval))
  735. return NULL;
  736. intObj = PyObject_New(IntLikeObject, &IntLike_Type);
  737. if (!intObj) {
  738. return NULL;
  739. }
  740. intObj->value = intval;
  741. isint = PyNumber_Check((PyObject*)intObj);
  742. Py_DECREF((PyObject*)intObj);
  743. return PyInt_FromLong(isint);
  744. """),
  745. ], prologue= """
  746. typedef struct
  747. {
  748. PyObject_HEAD
  749. int value;
  750. } IntLikeObject;
  751. static int
  752. intlike_nb_nonzero(PyObject *o)
  753. {
  754. IntLikeObject *v = (IntLikeObject*)o;
  755. if (v->value == -42) {
  756. PyErr_SetNone(PyExc_ValueError);
  757. return -1;
  758. }
  759. /* Returning -1 should be for exceptions only! */
  760. return v->value;
  761. }
  762. static PyObject*
  763. intlike_nb_int(PyObject* o)
  764. {
  765. IntLikeObject *v = (IntLikeObject*)o;
  766. return PyInt_FromLong(v->value);
  767. }
  768. PyTypeObject IntLike_Type = {
  769. PyObject_HEAD_INIT(0)
  770. /*ob_size*/ 0,
  771. /*tp_name*/ "IntLike",
  772. /*tp_basicsize*/ sizeof(IntLikeObject),
  773. };
  774. static PyNumberMethods intlike_as_number;
  775. """, more_init="""
  776. IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT;
  777. IntLike_Type.tp_as_number = &intlike_as_number;
  778. intlike_as_number.nb_nonzero = intlike_nb_nonzero;
  779. intlike_as_number.nb_int = intlike_nb_int;
  780. PyType_Ready(&IntLike_Type);
  781. """)
  782. assert not bool(module.newInt(0))
  783. assert bool(module.newInt(1))
  784. raises(SystemError, bool, module.newInt(-1))
  785. raises(ValueError, bool, module.newInt(-42))
  786. val = module.check(10);
  787. assert val == 1
  788. def test_mathfunc(self):
  789. module = self.import_extension('foo', [
  790. ("newInt", "METH_VARARGS",
  791. """
  792. IntLikeObject *intObj;
  793. long intval;
  794. if (!PyArg_ParseTuple(args, "l", &intval))
  795. return NULL;
  796. IntLike_Type.tp_as_number = &intlike_as_number;
  797. IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES;
  798. intlike_as_number.nb_add = intlike_nb_add;
  799. intlike_as_number.nb_power = intlike_nb_pow;
  800. if (PyType_Ready(&IntLike_Type) < 0) return NULL;
  801. intObj = PyObject_New(IntLikeObject, &IntLike_Type);
  802. if (!intObj) {
  803. return NULL;
  804. }
  805. intObj->ival = intval;
  806. return (PyObject *)intObj;
  807. """),
  808. ("newIntNoOp", "METH_VARARGS",
  809. """
  810. IntLikeObjectNoOp *intObjNoOp;
  811. long intval;
  812. if (!PyArg_ParseTuple(args, "l", &intval))
  813. return NULL;
  814. IntLike_Type_NoOp.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES;
  815. if (PyType_Ready(&IntLike_Type_NoOp) < 0) return NULL;
  816. intObjNoOp = PyObject_New(IntLikeObjectNoOp, &IntLike_Type_NoOp);
  817. if (!intObjNoOp) {
  818. return NULL;
  819. }
  820. intObjNoOp->ival = intval;
  821. return (PyObject *)intObjNoOp;
  822. """)], prologue=
  823. """
  824. #include <math.h>
  825. typedef struct
  826. {
  827. PyObject_HEAD
  828. long ival;
  829. } IntLikeObject;
  830. static PyObject *
  831. intlike_nb_add(PyObject *self, PyObject *other)
  832. {
  833. long val2, val1 = ((IntLikeObject *)(self))->ival;
  834. if (PyInt_Check(other)) {
  835. long val2 = PyInt_AsLong(other);
  836. return PyInt_FromLong(val1+val2);
  837. }
  838. val2 = ((IntLikeObject *)(other))->ival;
  839. return PyInt_FromLong(val1+val2);
  840. }
  841. static PyObject *
  842. intlike_nb_pow(PyObject *self, PyObject *other, PyObject * z)
  843. {
  844. long val2, val1 = ((IntLikeObject *)(self))->ival;
  845. if (PyInt_Check(other)) {
  846. long val2 = PyInt_AsLong(other);
  847. return PyInt_FromLong(val1+val2);
  848. }
  849. val2 = ((IntLikeObject *)(other))->ival;
  850. return PyInt_FromLong((int)pow(val1,val2));
  851. }
  852. PyTypeObject IntLike_Type = {
  853. PyObject_HEAD_INIT(0)
  854. /*ob_size*/ 0,
  855. /*tp_name*/ "IntLike",
  856. /*tp_basicsize*/ sizeof(IntLikeObject),
  857. };
  858. static PyNumberMethods intlike_as_number;
  859. typedef struct
  860. {
  861. PyObject_HEAD
  862. long ival;
  863. } IntLikeObjectNoOp;
  864. PyTypeObject IntLike_Type_NoOp = {
  865. PyObject_HEAD_INIT(0)
  866. /*ob_size*/ 0,
  867. /*tp_name*/ "IntLikeNoOp",
  868. /*tp_basicsize*/ sizeof(IntLikeObjectNoOp),
  869. };
  870. """)
  871. a = module.newInt(1)
  872. b = module.newInt(2)
  873. c = 3
  874. d = module.newIntNoOp(4)
  875. assert (a + b) == 3
  876. assert (b + c) == 5
  877. assert (d + a) == 5
  878. assert pow(d,b) == 16
  879. def test_tp_new_in_subclass_of_type(self):
  880. module = self.import_module(name='foo3')
  881. module.footype("X", (object,), {})
  882. def test_app_subclass_of_c_type(self):
  883. import sys
  884. module = self.import_module(name='foo')
  885. size = module.size_of_instances(module.fooType)
  886. class f1(object):
  887. pass
  888. class f2(module.fooType):
  889. pass
  890. class bar(f1, f2):
  891. pass
  892. assert bar.__base__ is f2
  893. # On cpython, the size changes.
  894. if '__pypy__' in sys.builtin_module_names:
  895. assert module.size_of_instances(bar) == size
  896. else:
  897. assert module.size_of_instances(bar) >= size
  898. def test_app_cant_subclass_two_types(self):
  899. module = self.import_module(name='foo')
  900. try:
  901. class bar(module.fooType, module.UnicodeSubtype):
  902. pass
  903. except TypeError as e:
  904. import sys
  905. if '__pypy__' in sys.builtin_module_names:
  906. assert str(e) == 'instance layout conflicts in multiple inheritance'
  907. else:
  908. assert str(e) == ('Error when calling the metaclass bases\n'
  909. ' multiple bases have instance lay-out conflict')
  910. else:
  911. raise AssertionError("did not get TypeError!")
  912. def test_call_tp_dealloc_when_created_from_python(self):
  913. module = self.import_extension('foo', [
  914. ("fetchFooType", "METH_VARARGS",
  915. """
  916. PyObject *o;
  917. Foo_Type.tp_basicsize = sizeof(FooObject);
  918. Foo_Type.tp_dealloc = &dealloc_foo;
  919. Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES
  920. | Py_TPFLAGS_BASETYPE;
  921. Foo_Type.tp_new = &new_foo;
  922. Foo_Type.tp_free = &PyObject_Del;
  923. if (PyType_Ready(&Foo_Type) < 0) return NULL;
  924. o = PyObject_New(PyObject, &Foo_Type);
  925. init_foo(o);
  926. Py_DECREF(o); /* calls dealloc_foo immediately */
  927. Py_INCREF(&Foo_Type);
  928. return (PyObject *)&Foo_Type;
  929. """),
  930. ("newInstance", "METH_O",
  931. """
  932. PyTypeObject *tp = (PyTypeObject *)args;
  933. PyObject *e = PyTuple_New(0);
  934. PyObject *o = tp->tp_new(tp, e, NULL);
  935. Py_DECREF(e);
  936. return o;
  937. """),
  938. ("getCounter", "METH_VARARGS",
  939. """
  940. return PyInt_FromLong(foo_counter);
  941. """)], prologue=
  942. """
  943. typedef struct {
  944. PyObject_HEAD
  945. int someval[99];
  946. } FooObject;
  947. static int foo_counter = 1000;
  948. static void dealloc_foo(PyObject *foo) {
  949. int i;
  950. foo_counter += 10;
  951. for (i = 0; i < 99; i++)
  952. if (((FooObject *)foo)->someval[i] != 1000 + i)
  953. foo_counter += 100000; /* error! */
  954. Py_TYPE(foo)->tp_free(foo);
  955. }
  956. static void init_foo(PyObject *o)
  957. {
  958. int i;
  959. if (o->ob_type->tp_basicsize < sizeof(FooObject))
  960. abort();
  961. for (i = 0; i < 99; i++)
  962. ((FooObject *)o)->someval[i] = 1000 + i;
  963. }
  964. static PyObject *new_foo(PyTypeObject *t, PyObject *a, PyObject *k)
  965. {
  966. PyObject *o;
  967. foo_counter += 1000;
  968. o = t->tp_alloc(t, 0);
  969. init_foo(o);
  970. return o;
  971. }
  972. static PyTypeObject Foo_Type = {
  973. PyVarObject_HEAD_INIT(NULL, 0)
  974. "foo.foo",
  975. };
  976. """)
  977. Foo = module.fetchFooType()
  978. assert module.getCounter() == 1010
  979. Foo(); Foo()
  980. for i in range(10):
  981. if module.getCounter() >= 3030:
  982. break
  983. # NB. use self.debug_collect() instead of gc.collect(),
  984. # otherwise rawrefcount's dealloc callback doesn't trigger
  985. self.debug_collect()
  986. assert module.getCounter() == 3030
  987. #
  988. class Bar(Foo):
  989. pass
  990. assert Foo.__new__ is Bar.__new__
  991. Bar(); Bar()
  992. for i in range(10):
  993. if module.getCounter() >= 5050:
  994. break
  995. self.debug_collect()
  996. assert module.getCounter() == 5050
  997. #
  998. module.newInstance(Foo)
  999. for i in range(10):
  1000. if module.getCounter() >= 6060:
  1001. break
  1002. self.debug_collect()
  1003. assert module.getCounter() == 6060
  1004. #
  1005. module.newInstance(Bar)
  1006. for i in range(10):
  1007. if module.getCounter() >= 7070:
  1008. break
  1009. self.debug_collect()
  1010. assert module.getCounter() == 7070
  1011. def test_tp_call_reverse(self):
  1012. module = self.import_extension('foo', [
  1013. ("new_obj", "METH_NOARGS",
  1014. '''
  1015. PyObject *obj;
  1016. Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT;
  1017. Foo_Type.tp_call = &my_tp_call;
  1018. if (PyType_Ready(&Foo_Type) < 0) return NULL;
  1019. obj = PyObject_New(PyObject, &Foo_Type);
  1020. return obj;
  1021. '''
  1022. )],
  1023. '''
  1024. static PyObject *
  1025. my_tp_call(PyObject *self, PyObject *args, PyObject *kwds)
  1026. {
  1027. return PyInt_FromLong(42);
  1028. }
  1029. static PyTypeObject Foo_Type = {
  1030. PyVarObject_HEAD_INIT(NULL, 0)
  1031. "foo.foo",
  1032. };
  1033. ''')
  1034. x = module.new_obj()
  1035. assert x() == 42
  1036. assert x(4, bar=5) == 42
  1037. def test_custom_metaclass(self):
  1038. module = self.import_extension('foo', [
  1039. ("getMetaClass", "METH_NOARGS",
  1040. '''
  1041. FooType_Type.tp_flags = Py_TPFLAGS_DEFAULT;
  1042. FooType_Type.tp_base = &PyType_Type;
  1043. if (PyType_Ready(&FooType_Type) < 0) return NULL;
  1044. Py_INCREF(&FooType_Type);
  1045. return (PyObject *)&FooType_Type;
  1046. '''
  1047. )],
  1048. '''
  1049. static PyTypeObject FooType_Type = {
  1050. PyVarObject_HEAD_INIT(NULL, 0)
  1051. "foo.Type",
  1052. };
  1053. ''')
  1054. FooType = module.getMetaClass()
  1055. if not self.runappdirect:
  1056. self._check_type_object(FooType)
  1057. class X(object):
  1058. __metaclass__ = FooType
  1059. print repr(X)
  1060. X()