PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/rlib/test/test_objectmodel.py

https://bitbucket.org/pypy/pypy/
Python | 840 lines | 719 code | 115 blank | 6 comment | 56 complexity | b3c363b5883770c48a8b3972164dec35 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from collections import OrderedDict
  2. import py
  3. from rpython.rlib.objectmodel import (
  4. r_dict, UnboxedValue, Symbolic, compute_hash, compute_identity_hash,
  5. compute_unique_id, current_object_addr_as_int, we_are_translated,
  6. prepare_dict_update, reversed_dict, specialize, enforceargs, newlist_hint,
  7. resizelist_hint, is_annotation_constant, always_inline, NOT_CONSTANT,
  8. iterkeys_with_hash, iteritems_with_hash, contains_with_hash,
  9. setitem_with_hash, getitem_with_hash, delitem_with_hash, import_from_mixin,
  10. fetch_translated_config)
  11. from rpython.translator.translator import TranslationContext, graphof
  12. from rpython.rtyper.test.tool import BaseRtypingTest
  13. from rpython.rtyper.test.test_llinterp import interpret
  14. from rpython.conftest import option
  15. def strange_key_eq(key1, key2):
  16. return key1[0] == key2[0] # only the 1st character is relevant
  17. def strange_key_hash(key):
  18. return ord(key[0])
  19. def play_with_r_dict(d):
  20. d['hello'] = 41
  21. d['hello'] = 42
  22. assert d['hi there'] == 42
  23. try:
  24. unexpected = d["dumb"]
  25. except KeyError:
  26. pass
  27. else:
  28. assert False, "should have raised, got %s" % unexpected
  29. assert len(d) == 1
  30. assert 'oops' not in d
  31. count = 0
  32. for x in d:
  33. assert x == 'hello'
  34. count += 1
  35. assert count == 1
  36. assert d.get('hola', -1) == 42
  37. assert d.get('salut', -1) == -1
  38. d1 = d.copy()
  39. del d['hu!']
  40. assert len(d) == 0
  41. assert d1.keys() == ['hello']
  42. d.update(d1)
  43. assert d.values() == [42]
  44. lst = d.items()
  45. assert len(lst) == 1 and len(lst[0]) == 2
  46. assert lst[0][0] == 'hello' and lst[0][1] == 42
  47. count = 0
  48. for x in d.iterkeys():
  49. assert x == 'hello'
  50. count += 1
  51. assert count == 1
  52. count = 0
  53. for x in d.itervalues():
  54. assert x == 42
  55. count += 1
  56. assert count == 1
  57. count = 0
  58. for x in d.iteritems():
  59. assert len(x) == 2 and x[0] == 'hello' and x[1] == 42
  60. count += 1
  61. assert count == 1
  62. d.clear()
  63. assert d.keys() == []
  64. return True # for the tests below
  65. def test_recursive_r_dict_repr():
  66. import operator
  67. rdic = r_dict(operator.eq, hash)
  68. rdic['x'] = rdic
  69. assert str(rdic) == "r_dict({'x': r_dict({...})})"
  70. assert repr(rdic) == "r_dict({'x': r_dict({...})})"
  71. def func_r_dict():
  72. # NB. this test function is also annotated/rtyped by the next tests
  73. d = r_dict(strange_key_eq, strange_key_hash)
  74. return play_with_r_dict(d)
  75. class Strange:
  76. def key_eq(strange, key1, key2):
  77. return key1[0] == key2[0] # only the 1st character is relevant
  78. def key_hash(strange, key):
  79. return ord(key[0])
  80. def func_r_dict_bm():
  81. # NB. this test function is also annotated by the next tests
  82. strange = Strange()
  83. d = r_dict(strange.key_eq, strange.key_hash)
  84. return play_with_r_dict(d)
  85. def test_annotate_r_dict():
  86. t = TranslationContext()
  87. a = t.buildannotator()
  88. a.build_types(func_r_dict, [])
  89. #t.view()
  90. graph = graphof(t, strange_key_eq)
  91. assert a.binding(graph.getargs()[0]).knowntype == str
  92. assert a.binding(graph.getargs()[1]).knowntype == str
  93. graph = graphof(t, strange_key_hash)
  94. assert a.binding(graph.getargs()[0]).knowntype == str
  95. def test_annotate_r_dict_bm():
  96. t = TranslationContext()
  97. a = t.buildannotator()
  98. a.build_types(func_r_dict_bm, [])
  99. #t.view()
  100. strange_key_eq = Strange.key_eq.im_func
  101. strange_key_hash = Strange.key_hash.im_func
  102. Strange_def = a.bookkeeper.getuniqueclassdef(Strange)
  103. graph = graphof(t, strange_key_eq)
  104. assert a.binding(graph.getargs()[0]).classdef == Strange_def
  105. assert a.binding(graph.getargs()[1]).knowntype == str
  106. assert a.binding(graph.getargs()[2]).knowntype == str
  107. graph = graphof(t, strange_key_hash)
  108. assert a.binding(graph.getargs()[0]).classdef == Strange_def
  109. assert a.binding(graph.getargs()[1]).knowntype == str
  110. def test_unboxed_value():
  111. class Base(object):
  112. __slots__ = ()
  113. class C(Base, UnboxedValue):
  114. __slots__ = 'smallint'
  115. assert C(17).smallint == 17
  116. assert C(17).get_untagged_value() == 17
  117. class A(UnboxedValue):
  118. __slots__ = ['value']
  119. assert A(12098).value == 12098
  120. assert A(12098).get_untagged_value() == 12098
  121. def test_symbolic():
  122. py.test.skip("xxx no test here")
  123. def test_symbolic_raises():
  124. s1 = Symbolic()
  125. s2 = Symbolic()
  126. py.test.raises(TypeError, "s1 < s2")
  127. py.test.raises(TypeError, "hash(s1)")
  128. def test_compute_hash():
  129. from rpython.rlib.objectmodel import _hash_string, _hash_float, _hash_tuple
  130. assert compute_hash("Hello") == _hash_string("Hello")
  131. assert compute_hash(7) == 7
  132. assert compute_hash(-3.5) == _hash_float(-3.5)
  133. assert compute_hash(None) == 0
  134. assert compute_hash(("world", None, 7)) == _hash_tuple(("world", None, 7))
  135. #
  136. class Foo(object):
  137. def __hash__(self):
  138. return 42
  139. foo = Foo()
  140. h = compute_hash(foo)
  141. assert h == object.__hash__(foo)
  142. assert h == getattr(foo, '__precomputed_identity_hash')
  143. assert compute_hash(None) == 0
  144. def test_compute_hash_float():
  145. from rpython.rlib.rfloat import INFINITY, NAN
  146. assert compute_hash(INFINITY) == 314159
  147. assert compute_hash(-INFINITY) == -271828
  148. assert compute_hash(NAN) == 0
  149. def test_compute_identity_hash():
  150. class Foo(object):
  151. def __hash__(self):
  152. return 42
  153. foo = Foo()
  154. h = compute_identity_hash(foo)
  155. assert h == object.__hash__(foo)
  156. assert h == getattr(foo, '__precomputed_identity_hash')
  157. def test_compute_unique_id():
  158. from rpython.rlib.rarithmetic import intmask
  159. class Foo(object):
  160. pass
  161. foo = Foo()
  162. x = compute_unique_id(foo)
  163. assert type(x) is int
  164. assert x == intmask(id(foo))
  165. def test_current_object_addr_as_int():
  166. from rpython.rlib.rarithmetic import intmask
  167. class Foo(object):
  168. pass
  169. foo = Foo()
  170. assert current_object_addr_as_int(foo) == intmask(id(foo))
  171. class TestObjectModel(BaseRtypingTest):
  172. def test_we_are_translated(self):
  173. assert we_are_translated() is False
  174. def fn():
  175. return we_are_translated()
  176. res = self.interpret(fn, [])
  177. assert res is True
  178. def test_rtype_r_dict(self):
  179. res = self.interpret(func_r_dict, [])
  180. assert res is True
  181. def test_rtype_r_dict_bm(self):
  182. res = self.interpret(func_r_dict_bm, [])
  183. assert res is True
  184. def test_rtype_constant_r_dicts(self):
  185. d1 = r_dict(strange_key_eq, strange_key_hash)
  186. d1['hello'] = 666
  187. d2 = r_dict(strange_key_eq, strange_key_hash)
  188. d2['hello'] = 777
  189. d2['world'] = 888
  190. def fn(i):
  191. if i == 1:
  192. d = d1
  193. else:
  194. d = d2
  195. return len(d)
  196. res = self.interpret(fn, [1])
  197. assert res == 1
  198. res = self.interpret(fn, [2])
  199. assert res == 2
  200. def test_rtype_r_dict_singlefrozen_func(self):
  201. class FreezingClass(Strange):
  202. def _freeze_(self):
  203. return True
  204. obj = FreezingClass()
  205. def fn():
  206. d = r_dict(obj.key_eq, obj.key_hash)
  207. return play_with_r_dict(d)
  208. assert self.interpret(fn, []) is True
  209. def test_rtype_r_dict_singlefrozen_func_pbc(self):
  210. class FreezingClass(Strange):
  211. def _freeze_(self):
  212. return True
  213. obj = FreezingClass()
  214. pbc_d = r_dict(obj.key_eq, obj.key_hash)
  215. def fn():
  216. return play_with_r_dict(pbc_d)
  217. assert self.interpret(fn, []) is True
  218. def test_rtype_r_dict_exceptions(self):
  219. def raising_hash(obj):
  220. if obj.startswith("bla"):
  221. raise TypeError
  222. return 1
  223. def eq(obj1, obj2):
  224. return obj1 is obj2
  225. def f():
  226. d1 = r_dict(eq, raising_hash)
  227. d1['xxx'] = 1
  228. try:
  229. x = d1["blabla"]
  230. except Exception:
  231. return 42
  232. return x
  233. res = self.interpret(f, [])
  234. assert res == 42
  235. def f():
  236. d1 = r_dict(eq, raising_hash)
  237. d1['xxx'] = 1
  238. try:
  239. x = d1["blabla"]
  240. except TypeError:
  241. return 42
  242. return x
  243. res = self.interpret(f, [])
  244. assert res == 42
  245. def f():
  246. d1 = r_dict(eq, raising_hash)
  247. d1['xxx'] = 1
  248. try:
  249. d1["blabla"] = 2
  250. except TypeError:
  251. return 42
  252. return 0
  253. res = self.interpret(f, [])
  254. assert res == 42
  255. def test_access_in_try(self):
  256. h = lambda x: 1
  257. eq = lambda x, y: x == y
  258. def f(d):
  259. try:
  260. return d[2]
  261. except ZeroDivisionError:
  262. return 42
  263. return -1
  264. def g(n):
  265. d = r_dict(eq, h)
  266. d[1] = n
  267. d[2] = 2 * n
  268. return f(d)
  269. res = self.interpret(g, [3])
  270. assert res == 6
  271. def test_access_in_try_set(self):
  272. h = lambda x: 1
  273. eq = lambda x, y: x == y
  274. def f(d):
  275. try:
  276. d[2] = 77
  277. except ZeroDivisionError:
  278. return 42
  279. return -1
  280. def g(n):
  281. d = r_dict(eq, h)
  282. d[1] = n
  283. f(d)
  284. return d[2]
  285. res = self.interpret(g, [3])
  286. assert res == 77
  287. def test_prepare_dict_update(self):
  288. def g(n):
  289. d = {}
  290. prepare_dict_update(d, n)
  291. return 42
  292. res = self.interpret(g, [3])
  293. assert res == 42 # "did not crash"
  294. def test_prepare_dict_update_2(self):
  295. def g(n):
  296. d = OrderedDict()
  297. prepare_dict_update(d, n)
  298. return 42
  299. res = self.interpret(g, [3])
  300. assert res == 42 # "did not crash"
  301. def test_reversed_dict(self):
  302. d1 = {2: 3, 4: 5, 6: 7}
  303. def g():
  304. n1 = 0
  305. for key in d1:
  306. n1 = n1 * 10 + key
  307. n2 = 0
  308. for key in reversed_dict(d1):
  309. n2 = n2 * 10 + key
  310. return n1 * 10000 + n2
  311. got = str(g())
  312. assert len(got) == 7 and got[3] == '0' and got[:3] == got[6:3:-1]
  313. got = str(self.interpret(g, []))
  314. assert len(got) == 7 and got[3] == '0' and got[:3] == got[6:3:-1]
  315. def test_compute_hash(self):
  316. class Foo(object):
  317. pass
  318. def f(i):
  319. assert compute_hash(i) == compute_hash(42)
  320. assert compute_hash(i + 1.0) == compute_hash(43.0)
  321. assert compute_hash("Hello" + str(i)) == compute_hash("Hello42")
  322. if i == 42:
  323. p = None
  324. else:
  325. p = Foo()
  326. assert compute_hash(p) == compute_hash(None)
  327. assert (compute_hash(("world", None, i, 7.5)) ==
  328. compute_hash(("world", None, 42, 7.5)))
  329. q = Foo()
  330. assert compute_hash(q) == compute_identity_hash(q)
  331. from rpython.rlib.rfloat import INFINITY, NAN
  332. assert compute_hash(INFINITY) == 314159
  333. assert compute_hash(-INFINITY) == -271828
  334. assert compute_hash(NAN) == 0
  335. return i * 2
  336. res = self.interpret(f, [42])
  337. assert res == 84
  338. def test_isconstant(self):
  339. @specialize.arg_or_var(0)
  340. def f(arg):
  341. if is_annotation_constant(arg):
  342. return 1
  343. return 10
  344. def fn(arg):
  345. return f(arg) + f(3)
  346. assert self.interpret(fn, [15]) == 11
  347. def test_rtype_keepalive(self):
  348. from rpython.rlib import objectmodel
  349. def f():
  350. x = [1]
  351. y = ['b']
  352. objectmodel.keepalive_until_here(x, y)
  353. return 1
  354. res = self.interpret(f, [])
  355. assert res == 1
  356. def test_compute_hash_across_translation(self):
  357. class Foo(object):
  358. pass
  359. q = Foo()
  360. def f(i):
  361. assert compute_hash(None) == 0
  362. assert compute_hash(i) == h_42
  363. assert compute_hash(i + 1.0) == h_43_dot_0
  364. assert compute_hash((i + 3) / 6.0) == h_7_dot_5
  365. assert compute_hash("Hello" + str(i)) == h_Hello42
  366. if i == 42:
  367. p = None
  368. else:
  369. p = Foo()
  370. assert compute_hash(p) == h_None
  371. assert compute_hash(("world", None, i, 7.5)) == h_tuple
  372. assert compute_hash(q) == h_q
  373. return i * 2
  374. h_42 = compute_hash(42)
  375. h_43_dot_0 = compute_hash(43.0)
  376. h_7_dot_5 = compute_hash(7.5)
  377. h_Hello42 = compute_hash("Hello42")
  378. h_None = compute_hash(None)
  379. h_tuple = compute_hash(("world", None, 42, 7.5))
  380. h_q = compute_hash(q)
  381. res = self.interpret(f, [42])
  382. assert res == 84
  383. def test_fetch_translated_config(self):
  384. assert fetch_translated_config() is None
  385. def f():
  386. return fetch_translated_config().translation.continuation
  387. res = self.interpret(f, [])
  388. assert res is False
  389. def test_specialize_decorator():
  390. def f():
  391. pass
  392. specialize.memo()(f)
  393. assert f._annspecialcase_ == 'specialize:memo'
  394. specialize.arg(0)(f)
  395. assert f._annspecialcase_ == 'specialize:arg(0)'
  396. specialize.arg(1)(f)
  397. assert f._annspecialcase_ == 'specialize:arg(1)'
  398. def test_enforceargs_decorator():
  399. @enforceargs(int, str, None)
  400. def f(a, b, c):
  401. return a, b, c
  402. f.foo = 'foo'
  403. assert f._annenforceargs_ == (int, str, None)
  404. assert f.func_name == 'f'
  405. assert f.foo == 'foo'
  406. assert f(1, 'hello', 42) == (1, 'hello', 42)
  407. exc = py.test.raises(TypeError, "f(1, 2, 3)")
  408. assert exc.value.message == "f argument 'b' must be of type <type 'str'>"
  409. py.test.raises(TypeError, "f('hello', 'world', 3)")
  410. def test_always_inline():
  411. @always_inline
  412. def f(a, b, c):
  413. return a, b, c
  414. assert f._always_inline_ is True
  415. def test_enforceargs_defaults():
  416. @enforceargs(int, int)
  417. def f(a, b=40):
  418. return a + b
  419. assert f(2) == 42
  420. def test_enforceargs_keywords():
  421. @enforceargs(b=int)
  422. def f(a, b, c):
  423. return a + b
  424. assert f._annenforceargs_ == (None, int, None)
  425. def test_enforceargs_int_float_promotion():
  426. @enforceargs(float)
  427. def f(x):
  428. return x
  429. # in RPython there is an implicit int->float promotion
  430. assert f(42) == 42
  431. def test_enforceargs_None_string():
  432. @enforceargs(str, unicode)
  433. def f(a, b):
  434. return a, b
  435. assert f(None, None) == (None, None)
  436. def test_enforceargs_complex_types():
  437. @enforceargs([int], {str: int})
  438. def f(a, b):
  439. return a, b
  440. x = [0, 1, 2]
  441. y = {'a': 1, 'b': 2}
  442. assert f(x, y) == (x, y)
  443. assert f([], {}) == ([], {})
  444. assert f(None, None) == (None, None)
  445. py.test.raises(TypeError, "f(['hello'], y)")
  446. py.test.raises(TypeError, "f(x, {'a': 'hello'})")
  447. py.test.raises(TypeError, "f(x, {0: 42})")
  448. def test_enforceargs_no_typecheck():
  449. @enforceargs(int, str, None, typecheck=False)
  450. def f(a, b, c):
  451. return a, b, c
  452. assert f._annenforceargs_ == (int, str, None)
  453. assert f(1, 2, 3) == (1, 2, 3) # no typecheck
  454. def test_enforceargs_translates():
  455. from rpython.rtyper.lltypesystem import lltype
  456. @enforceargs(int, float)
  457. def f(a, b):
  458. return a, b
  459. graph = getgraph(f, [int, int])
  460. TYPES = [v.concretetype for v in graph.getargs()]
  461. assert TYPES == [lltype.Signed, lltype.Float]
  462. def test_enforceargs_not_constant():
  463. from rpython.translator.translator import TranslationContext, graphof
  464. @enforceargs(NOT_CONSTANT)
  465. def f(a):
  466. return a
  467. def f42():
  468. return f(42)
  469. t = TranslationContext()
  470. a = t.buildannotator()
  471. s = a.build_types(f42, [])
  472. assert not hasattr(s, 'const')
  473. def getgraph(f, argtypes):
  474. from rpython.translator.translator import TranslationContext, graphof
  475. from rpython.translator.backendopt.all import backend_optimizations
  476. t = TranslationContext()
  477. a = t.buildannotator()
  478. typer = t.buildrtyper()
  479. a.build_types(f, argtypes)
  480. typer.specialize()
  481. backend_optimizations(t)
  482. graph = graphof(t, f)
  483. if option.view:
  484. graph.show()
  485. return graph
  486. def test_newlist():
  487. def f(z):
  488. x = newlist_hint(sizehint=38)
  489. if z < 0:
  490. x.append(1)
  491. return len(x)
  492. graph = getgraph(f, [int])
  493. for llop in graph.startblock.operations:
  494. if llop.opname == 'malloc_varsize':
  495. break
  496. assert llop.args[2].value == 38
  497. def test_newlist_nonconst():
  498. def f(z):
  499. x = newlist_hint(sizehint=z)
  500. return len(x)
  501. graph = getgraph(f, [int])
  502. for llop in graph.startblock.operations:
  503. if llop.opname == 'malloc_varsize':
  504. break
  505. assert llop.args[2] is graph.startblock.inputargs[0]
  506. def test_resizelist_hint():
  507. def f(z):
  508. x = []
  509. resizelist_hint(x, 39)
  510. return len(x)
  511. graph = getgraph(f, [int])
  512. for _, op in graph.iterblockops():
  513. if op.opname == 'direct_call':
  514. break
  515. call_name = op.args[0].value._obj.graph.name
  516. assert call_name.startswith('_ll_list_resize_hint')
  517. call_arg2 = op.args[2].value
  518. assert call_arg2 == 39
  519. def test_resizelist_hint_len():
  520. def f(i):
  521. l = [44]
  522. resizelist_hint(l, i)
  523. return len(l)
  524. r = interpret(f, [29])
  525. assert r == 1
  526. def test_iterkeys_with_hash():
  527. def f(i):
  528. d = {i + .0: 5, i + .5: 6}
  529. total = 0
  530. for k, h in iterkeys_with_hash(d):
  531. total += k * h
  532. total -= (i + 0.0) * compute_hash(i + 0.0)
  533. total -= (i + 0.5) * compute_hash(i + 0.5)
  534. return total
  535. assert f(29) == 0.0
  536. r = interpret(f, [29])
  537. assert r == 0.0
  538. def test_iteritems_with_hash():
  539. def f(i):
  540. d = {i + .0: 5, i + .5: 6}
  541. total = 0
  542. for k, v, h in iteritems_with_hash(d):
  543. total += k * h * v
  544. total -= (i + 0.0) * compute_hash(i + 0.0) * 5
  545. total -= (i + 0.5) * compute_hash(i + 0.5) * 6
  546. return total
  547. assert f(29) == 0.0
  548. r = interpret(f, [29])
  549. assert r == 0.0
  550. def test_contains_with_hash():
  551. def f(i):
  552. d = {i + .5: 5}
  553. assert contains_with_hash(d, i + .5, compute_hash(i + .5))
  554. assert not contains_with_hash(d, i + .3, compute_hash(i + .3))
  555. return 0
  556. f(29)
  557. interpret(f, [29])
  558. def test_setitem_with_hash():
  559. def f(i):
  560. d = {}
  561. setitem_with_hash(d, i + .5, compute_hash(i + .5), 42)
  562. setitem_with_hash(d, i + .6, compute_hash(i + .6), -612)
  563. return d[i + .5]
  564. assert f(29) == 42
  565. res = interpret(f, [27])
  566. assert res == 42
  567. def test_getitem_with_hash():
  568. def f(i):
  569. d = {i + .5: 42, i + .6: -612}
  570. return getitem_with_hash(d, i + .5, compute_hash(i + .5))
  571. assert f(29) == 42
  572. res = interpret(f, [27])
  573. assert res == 42
  574. def test_delitem_with_hash():
  575. def f(i):
  576. d = {i + .5: 42, i + .6: -612}
  577. delitem_with_hash(d, i + .5, compute_hash(i + .5))
  578. try:
  579. delitem_with_hash(d, i + .5, compute_hash(i + .5))
  580. except KeyError:
  581. pass
  582. else:
  583. raise AssertionError
  584. return 0
  585. f(29)
  586. interpret(f, [27])
  587. def test_rdict_with_hash():
  588. def f(i):
  589. d = r_dict(strange_key_eq, strange_key_hash)
  590. h = strange_key_hash("abc")
  591. assert h == strange_key_hash("aXX") and strange_key_eq("abc", "aXX")
  592. setitem_with_hash(d, "abc", h, i)
  593. assert getitem_with_hash(d, "aXX", h) == i
  594. try:
  595. getitem_with_hash(d, "bYY", strange_key_hash("bYY"))
  596. except KeyError:
  597. pass
  598. else:
  599. raise AssertionError
  600. return 0
  601. assert f(29) == 0
  602. interpret(f, [27])
  603. def test_import_from_mixin():
  604. class M: # old-style
  605. def f(self):
  606. pass
  607. class A: # old-style
  608. import_from_mixin(M)
  609. assert A.f.im_func is not M.f.im_func
  610. class M(object):
  611. def f(self):
  612. pass
  613. class A: # old-style
  614. import_from_mixin(M)
  615. assert A.f.im_func is not M.f.im_func
  616. class M: # old-style
  617. def f(self):
  618. pass
  619. class A(object):
  620. import_from_mixin(M)
  621. assert A.f.im_func is not M.f.im_func
  622. class M(object):
  623. def f(self):
  624. pass
  625. class A(object):
  626. import_from_mixin(M)
  627. assert A.f.im_func is not M.f.im_func
  628. class MBase(object):
  629. a = 42
  630. b = 43
  631. c = 1000
  632. def f(self):
  633. return "hi"
  634. def g(self):
  635. return self.c - 1
  636. class M(MBase):
  637. a = 84
  638. def f(self):
  639. return "there"
  640. class A(object):
  641. import_from_mixin(M)
  642. c = 88
  643. assert A.f.im_func is not M.f.im_func
  644. assert A.f.im_func is not MBase.f.im_func
  645. assert A.g.im_func is not MBase.g.im_func
  646. assert A().f() == "there"
  647. assert A.a == 84
  648. assert A.b == 43
  649. assert A.c == 88
  650. assert A().g() == 87
  651. try:
  652. class B(object):
  653. a = 63
  654. import_from_mixin(M)
  655. except Exception as e:
  656. assert ("would overwrite the value already defined locally for 'a'"
  657. in str(e))
  658. else:
  659. raise AssertionError("failed to detect overwritten attribute")
  660. class M(object):
  661. def __str__(self):
  662. return "m!"
  663. class A(object):
  664. import_from_mixin(M)
  665. class B(object):
  666. import_from_mixin(M, special_methods=['__str__'])
  667. assert str(A()).startswith('<')
  668. assert str(B()) == "m!"
  669. class M(object):
  670. pass
  671. class A(object):
  672. def __init__(self):
  673. self.foo = 42
  674. class B(A):
  675. import_from_mixin(M)
  676. assert B().foo == 42
  677. d = dict(__name__='foo')
  678. exec """class M(object):
  679. @staticmethod
  680. def f(): pass
  681. """ in d
  682. M = d['M']
  683. class A(object):
  684. import_from_mixin(M)
  685. assert A.f is not M.f
  686. assert A.f.__module__ != M.f.__module__
  687. def test_import_from_mixin_immutable_fields():
  688. class A(object):
  689. _immutable_fields_ = ['a']
  690. class B(object):
  691. _immutable_fields_ = ['b']
  692. import_from_mixin(A)
  693. assert B._immutable_fields_ == ['b', 'a']
  694. assert A._immutable_fields_ == ['a']
  695. class B(object):
  696. import_from_mixin(A)
  697. assert B._immutable_fields_ == ['a']
  698. class C(A):
  699. _immutable_fields_ = ['c']
  700. class B(object):
  701. import_from_mixin(C)
  702. assert B._immutable_fields_ == ['c', 'a']
  703. class B(object):
  704. _immutable_fields_ = ['b']
  705. import_from_mixin(C)
  706. assert B._immutable_fields_ == ['b', 'c', 'a']
  707. class B(object):
  708. _immutable_fields_ = ['b']
  709. class BA(B):
  710. import_from_mixin(C)
  711. assert BA._immutable_fields_ == ['c', 'a']