vector_test.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. import os
  2. import pickle
  3. import pytest
  4. from pyrsistent._pvector import python_pvector
  5. @pytest.fixture(scope='session', params=['pyrsistent._pvector', 'pvectorc'])
  6. def pvector(request):
  7. if request.param == 'pvectorc' and os.environ.get('PYRSISTENT_NO_C_EXTENSION'):
  8. pytest.skip('Configured to not run tests for C extension')
  9. m = pytest.importorskip(request.param)
  10. if request.param == 'pyrsistent._pvector':
  11. return m.python_pvector
  12. return m.pvector
  13. def test_literalish_works():
  14. from pyrsistent import pvector, v
  15. assert v() is pvector()
  16. assert v(1, 2) == pvector([1, 2])
  17. def test_empty_initialization(pvector):
  18. seq = pvector()
  19. assert len(seq) == 0
  20. with pytest.raises(IndexError) as error:
  21. x = seq[0]
  22. assert str(error.value) == 'Index out of range: 0'
  23. def test_initialization_with_one_element(pvector):
  24. seq = pvector([3])
  25. assert len(seq) == 1
  26. assert seq[0] == 3
  27. def test_append_works_and_does_not_affect_original_within_tail(pvector):
  28. seq1 = pvector([3])
  29. seq2 = seq1.append(2)
  30. assert len(seq1) == 1
  31. assert seq1[0] == 3
  32. assert len(seq2) == 2
  33. assert seq2[0] == 3
  34. assert seq2[1] == 2
  35. def test_append_works_and_does_not_affect_original_outside_tail(pvector):
  36. original = pvector([])
  37. seq = original
  38. for x in range(33):
  39. seq = seq.append(x)
  40. assert len(seq) == 33
  41. assert seq[0] == 0
  42. assert seq[31] == 31
  43. assert seq[32] == 32
  44. assert len(original) == 0
  45. def test_append_when_root_overflows(pvector):
  46. seq = pvector([])
  47. for x in range(32 * 33):
  48. seq = seq.append(x)
  49. seq = seq.append(10001)
  50. for i in range(32 * 33):
  51. assert seq[i] == i
  52. assert seq[32 * 33] == 10001
  53. def test_multi_level_sequence(pvector):
  54. seq = pvector(range(8000))
  55. seq2 = seq.append(11)
  56. assert seq[5] == 5
  57. assert seq2[7373] == 7373
  58. assert seq2[8000] == 11
  59. def test_multi_level_sequence_from_iterator(pvector):
  60. seq = pvector(iter(range(8000)))
  61. seq2 = seq.append(11)
  62. assert seq[5] == 5
  63. assert seq2[7373] == 7373
  64. assert seq2[8000] == 11
  65. def test_random_insert_within_tail(pvector):
  66. seq = pvector([1, 2, 3])
  67. seq2 = seq.set(1, 4)
  68. assert seq2[1] == 4
  69. assert seq[1] == 2
  70. def test_random_insert_outside_tail(pvector):
  71. seq = pvector(range(20000))
  72. seq2 = seq.set(19000, 4)
  73. assert seq2[19000] == 4
  74. assert seq[19000] == 19000
  75. def test_insert_beyond_end(pvector):
  76. seq = pvector(range(2))
  77. seq2 = seq.set(2, 50)
  78. assert seq2[2] == 50
  79. with pytest.raises(IndexError) as error:
  80. seq2.set(19, 4)
  81. assert str(error.value) == 'Index out of range: 19'
  82. def test_insert_with_index_from_the_end(pvector):
  83. x = pvector([1, 2, 3, 4])
  84. assert x.set(-2, 5) == pvector([1, 2, 5, 4])
  85. def test_insert_with_too_negative_index(pvector):
  86. x = pvector([1, 2, 3, 4])
  87. with pytest.raises(IndexError):
  88. x.set(-5, 17)
  89. def test_iteration(pvector):
  90. y = 0
  91. seq = pvector(range(2000))
  92. for x in seq:
  93. assert x == y
  94. y += 1
  95. assert y == 2000
  96. def test_zero_extend(pvector):
  97. the_list = []
  98. seq = pvector()
  99. seq2 = seq.extend(the_list)
  100. assert seq == seq2
  101. def test_short_extend(pvector):
  102. # Extend within tail length
  103. the_list = [1, 2]
  104. seq = pvector()
  105. seq2 = seq.extend(the_list)
  106. assert len(seq2) == len(the_list)
  107. assert seq2[0] == the_list[0]
  108. assert seq2[1] == the_list[1]
  109. def test_long_extend(pvector):
  110. # Multi level extend
  111. seq = pvector()
  112. length = 2137
  113. # Extend from scratch
  114. seq2 = seq.extend(range(length))
  115. assert len(seq2) == length
  116. for i in range(length):
  117. assert seq2[i] == i
  118. # Extend already filled vector
  119. seq3 = seq2.extend(range(length, length + 5))
  120. assert len(seq3) == length + 5
  121. for i in range(length + 5):
  122. assert seq3[i] == i
  123. # Check that the original vector is still intact
  124. assert len(seq2) == length
  125. for i in range(length):
  126. assert seq2[i] == i
  127. def test_slicing_zero_length_range(pvector):
  128. seq = pvector(range(10))
  129. seq2 = seq[2:2]
  130. assert len(seq2) == 0
  131. def test_slicing_range(pvector):
  132. seq = pvector(range(10))
  133. seq2 = seq[2:4]
  134. assert list(seq2) == [2, 3]
  135. def test_slice_identity(pvector):
  136. # Pvector is immutable, no need to make a copy!
  137. seq = pvector(range(10))
  138. assert seq is seq[::]
  139. def test_slicing_range_with_step(pvector):
  140. seq = pvector(range(100))
  141. seq2 = seq[2:12:3]
  142. assert list(seq2) == [2, 5, 8, 11]
  143. def test_slicing_no_range_but_step(pvector):
  144. seq = pvector(range(10))
  145. seq2 = seq[::2]
  146. assert list(seq2) == [0, 2, 4, 6, 8]
  147. def test_slicing_reverse(pvector):
  148. seq = pvector(range(10))
  149. seq2 = seq[::-1]
  150. assert seq2[0] == 9
  151. assert seq2[1] == 8
  152. assert len(seq2) == 10
  153. seq3 = seq[-3: -7: -1]
  154. assert seq3[0] == 7
  155. assert seq3[3] == 4
  156. assert len(seq3) == 4
  157. def test_delete_index(pvector):
  158. seq = pvector([1, 2, 3])
  159. assert seq.delete(0) == pvector([2, 3])
  160. assert seq.delete(1) == pvector([1, 3])
  161. assert seq.delete(2) == pvector([1, 2])
  162. assert seq.delete(-1) == pvector([1, 2])
  163. assert seq.delete(-2) == pvector([1, 3])
  164. assert seq.delete(-3) == pvector([2, 3])
  165. def test_delete_index_out_of_bounds(pvector):
  166. with pytest.raises(IndexError):
  167. pvector([]).delete(0)
  168. with pytest.raises(IndexError):
  169. pvector([]).delete(-1)
  170. def test_delete_index_malformed(pvector):
  171. with pytest.raises(TypeError):
  172. pvector([]).delete('a')
  173. def test_delete_slice(pvector):
  174. seq = pvector(range(5))
  175. assert seq.delete(1, 4) == pvector([0, 4])
  176. assert seq.delete(4, 1) == seq
  177. assert seq.delete(0, 1) == pvector([1, 2, 3, 4])
  178. assert seq.delete(6, 8) == seq
  179. assert seq.delete(-1, 1) == seq
  180. assert seq.delete(1, -1) == pvector([0, 4])
  181. def test_remove(pvector):
  182. seq = pvector(range(5))
  183. assert seq.remove(3) == pvector([0, 1, 2, 4])
  184. def test_remove_first_only(pvector):
  185. seq = pvector([1, 2, 3, 2, 1])
  186. assert seq.remove(2) == pvector([1, 3, 2, 1])
  187. def test_remove_index_out_of_bounds(pvector):
  188. seq = pvector(range(5))
  189. with pytest.raises(ValueError) as err:
  190. seq.remove(5)
  191. assert 'not in' in str(err.value)
  192. def test_addition(pvector):
  193. v = pvector([1, 2]) + pvector([3, 4])
  194. assert list(v) == [1, 2, 3, 4]
  195. def test_sorted(pvector):
  196. seq = pvector([5, 2, 3, 1])
  197. assert [1, 2, 3, 5] == sorted(seq)
  198. def test_boolean_conversion(pvector):
  199. assert not bool(pvector())
  200. assert bool(pvector([1]))
  201. def test_access_with_negative_index(pvector):
  202. seq = pvector([1, 2, 3, 4])
  203. assert seq[-1] == 4
  204. assert seq[-4] == 1
  205. def test_index_error_positive(pvector):
  206. with pytest.raises(IndexError):
  207. pvector([1, 2, 3])[3]
  208. def test_index_error_negative(pvector):
  209. with pytest.raises(IndexError):
  210. pvector([1, 2, 3])[-4]
  211. def test_is_sequence(pvector):
  212. from pyrsistent._compat import Sequence
  213. assert isinstance(pvector(), Sequence)
  214. def test_empty_repr(pvector):
  215. assert str(pvector()) == "pvector([])"
  216. def test_non_empty_repr(pvector):
  217. v = pvector([1, 2, 3])
  218. assert str(v) == "pvector([1, 2, 3])"
  219. # There's some state that needs to be reset between calls in the native version,
  220. # test that multiple invocations work.
  221. assert str(v) == "pvector([1, 2, 3])"
  222. def test_repr_when_contained_object_contains_reference_to_self(pvector):
  223. x = [1, 2, 3]
  224. v = pvector([1, 2, x])
  225. x.append(v)
  226. assert str(v) == 'pvector([1, 2, [1, 2, 3, pvector([1, 2, [...]])]])'
  227. # Run a GC to provoke any potential misbehavior
  228. import gc
  229. gc.collect()
  230. def test_is_hashable(pvector):
  231. from pyrsistent._compat import Hashable
  232. v = pvector([1, 2, 3])
  233. v2 = pvector([1, 2, 3])
  234. assert hash(v) == hash(v2)
  235. assert isinstance(pvector(), Hashable)
  236. def test_refuses_to_hash_when_members_are_unhashable(pvector):
  237. v = pvector([1, 2, [1, 2]])
  238. with pytest.raises(TypeError):
  239. hash(v)
  240. def test_compare_same_vectors(pvector):
  241. v = pvector([1, 2])
  242. assert v == v
  243. assert pvector() == pvector()
  244. def test_compare_with_other_type_of_object(pvector):
  245. assert pvector([1, 2]) != 'foo'
  246. def test_compare_equal_vectors(pvector):
  247. v1 = pvector([1, 2])
  248. v2 = pvector([1, 2])
  249. assert v1 == v2
  250. assert v1 >= v2
  251. assert v1 <= v2
  252. def test_compare_different_vectors_same_size(pvector):
  253. v1 = pvector([1, 2])
  254. v2 = pvector([1, 3])
  255. assert v1 != v2
  256. def test_compare_different_vectors_different_sizes(pvector):
  257. v1 = pvector([1, 2])
  258. v2 = pvector([1, 2, 3])
  259. assert v1 != v2
  260. def test_compare_lt_gt(pvector):
  261. v1 = pvector([1, 2])
  262. v2 = pvector([1, 2, 3])
  263. assert v1 < v2
  264. assert v2 > v1
  265. def test_repeat(pvector):
  266. v = pvector([1, 2])
  267. assert 5 * pvector() is pvector()
  268. assert v is 1 * v
  269. assert 0 * v is pvector()
  270. assert 2 * pvector([1, 2]) == pvector([1, 2, 1, 2])
  271. assert -3 * pvector([1, 2]) is pvector()
  272. def test_transform_zero_key_length(pvector):
  273. x = pvector([1, 2])
  274. assert x.transform([], 3) == 3
  275. def test_transform_base_case(pvector):
  276. x = pvector([1, 2])
  277. assert x.transform([1], 3) == pvector([1, 3])
  278. def test_transform_nested_vectors(pvector):
  279. x = pvector([1, 2, pvector([3, 4]), 5])
  280. assert x.transform([2, 0], 999) == pvector([1, 2, pvector([999, 4]), 5])
  281. def test_transform_when_appending(pvector):
  282. from pyrsistent import m
  283. x = pvector([1, 2])
  284. assert x.transform([2, 'd'], 999) == pvector([1, 2, m(d=999)])
  285. def test_transform_index_error_out_range(pvector):
  286. x = pvector([1, 2, pvector([3, 4]), 5])
  287. with pytest.raises(IndexError):
  288. x.transform([2, 10], 999)
  289. def test_transform_index_error_wrong_type(pvector):
  290. x = pvector([1, 2, pvector([3, 4]), 5])
  291. with pytest.raises(TypeError):
  292. x.transform([2, 'foo'], 999)
  293. def test_transform_non_setable_type(pvector):
  294. x = pvector([1, 2, 5])
  295. with pytest.raises(TypeError):
  296. x.transform([2, 3], 999)
  297. def test_reverse(pvector):
  298. x = pvector([1, 2, 5])
  299. assert list(reversed(x)) == [5, 2, 1]
  300. def test_contains(pvector):
  301. x = pvector([1, 2, 5])
  302. assert 2 in x
  303. assert 3 not in x
  304. def test_index(pvector):
  305. x = pvector([1, 2, 5])
  306. assert x.index(5) == 2
  307. def test_index_not_found(pvector):
  308. x = pvector([1, 2, 5])
  309. with pytest.raises(ValueError):
  310. x.index(7)
  311. def test_index_not_found_with_limits(pvector):
  312. x = pvector([1, 2, 5, 1])
  313. with pytest.raises(ValueError):
  314. x.index(1, 1, 3)
  315. def test_count(pvector):
  316. x = pvector([1, 2, 5, 1])
  317. assert x.count(1) == 2
  318. assert x.count(4) == 0
  319. def test_empty_truthiness(pvector):
  320. assert pvector([1])
  321. assert not pvector([])
  322. def test_pickling_empty_vector(pvector):
  323. assert pickle.loads(pickle.dumps(pvector(), -1)) == pvector()
  324. def test_pickling_non_empty_vector(pvector):
  325. assert pickle.loads(pickle.dumps(pvector([1, 'a']), -1)) == pvector([1, 'a'])
  326. def test_mset_basic_assignments(pvector):
  327. v1 = pvector(range(2000))
  328. v2 = v1.mset(1, -1, 505, -505, 1998, -1998)
  329. # Original not changed
  330. assert v1[1] == 1
  331. assert v1[505] == 505
  332. assert v1[1998] == 1998
  333. # Other updated
  334. assert v2[1] == -1
  335. assert v2[505] == -505
  336. assert v2[1998] == -1998
  337. def test_mset_odd_number_of_arguments(pvector):
  338. v = pvector([0, 1])
  339. with pytest.raises(TypeError):
  340. v.mset(0, 10, 1)
  341. def test_mset_index_out_of_range(pvector):
  342. v = pvector([0, 1])
  343. with pytest.raises(IndexError):
  344. v.mset(3, 10)
  345. def test_evolver_no_update(pvector):
  346. # This is mostly a test against memory leaks in the C implementation
  347. v = pvector(range(40))
  348. assert v.evolver().persistent() == v
  349. def test_evolver_deallocate_dirty_evolver(pvector):
  350. # Ref count handling in native implementation
  351. v = pvector(range(3220))
  352. e = v.evolver()
  353. e[10] = -10
  354. e[3220] = -3220
  355. def test_evolver_simple_update_in_tree(pvector):
  356. v = pvector(range(35))
  357. e = v.evolver()
  358. e[10] = -10
  359. assert e[10] == -10
  360. assert e.persistent()[10] == -10
  361. def test_evolver_set_out_of_range(pvector):
  362. v = pvector([0])
  363. e = v.evolver()
  364. with pytest.raises(IndexError) as error:
  365. e[10] = 1
  366. assert str(error.value) == "Index out of range: 10"
  367. def test_evolver_multi_level_multi_update_in_tree(pvector):
  368. # This test is mostly to detect memory/ref count issues in the native implementation
  369. v = pvector(range(3500))
  370. e = v.evolver()
  371. # Update differs between first and second time since the
  372. # corresponding node will be marked as dirty the first time only.
  373. e[10] = -10
  374. e[11] = -11
  375. e[10] = -1000
  376. # Update in neighbour node
  377. e[50] = -50
  378. e[50] = -5000
  379. # Update in node in other half of vector
  380. e[3000] = -3000
  381. e[3000] = -30000
  382. # Before freezing
  383. assert e[10] == -1000
  384. assert e[11] == -11
  385. assert e[50] == -5000
  386. assert e[3000] == -30000
  387. # Run a GC to provoke any potential misbehavior
  388. import gc
  389. gc.collect()
  390. v2 = e.persistent()
  391. assert v2[10] == -1000
  392. assert v2[50] == -5000
  393. assert v2[3000] == -30000
  394. # Run a GC to provoke any potential misbehavior
  395. gc.collect()
  396. # After freezing
  397. assert e[10] == -1000
  398. assert e[11] == -11
  399. assert e[50] == -5000
  400. assert e[3000] == -30000
  401. # Original stays the same
  402. assert v[10] == 10
  403. assert v[50] == 50
  404. assert v[3000] == 3000
  405. def test_evolver_simple_update_in_tail(pvector):
  406. v = pvector(range(35))
  407. e = v.evolver()
  408. e[33] = -33
  409. assert e[33] == -33
  410. assert e.persistent()[33] == -33
  411. assert v[33] == 33
  412. def test_evolver_simple_update_just_outside_vector(pvector):
  413. v = pvector()
  414. e = v.evolver()
  415. e[0] = 1
  416. assert e[0] == 1
  417. assert e.persistent()[0] == 1
  418. assert len(v) == 0
  419. def test_evolver_append(pvector):
  420. v = pvector()
  421. e = v.evolver()
  422. e.append(1000)
  423. assert e[0] == 1000
  424. e[0] = 2000
  425. assert e[0] == 2000
  426. assert list(e.persistent()) == [2000]
  427. assert list(v) == []
  428. def test_evolver_extend(pvector):
  429. v = pvector([1000])
  430. e = v.evolver()
  431. e.extend([2000, 3000])
  432. e[2] = 20000
  433. assert list(e.persistent()) == [1000, 2000, 20000]
  434. assert list(v) == [1000]
  435. def test_evolver_assign_and_read_with_negative_indices(pvector):
  436. v = pvector([1, 2, 3])
  437. e = v.evolver()
  438. e[-1] = 4
  439. e.extend([11, 12, 13])
  440. e[-1] = 33
  441. assert e[-1] == 33
  442. assert list(e.persistent()) == [1, 2, 4, 11, 12, 33]
  443. def test_evolver_non_integral_access(pvector):
  444. e = pvector([1]).evolver()
  445. with pytest.raises(TypeError):
  446. x = e['foo']
  447. def test_evolver_non_integral_assignment(pvector):
  448. e = pvector([1]).evolver()
  449. with pytest.raises(TypeError):
  450. e['foo'] = 1
  451. def test_evolver_out_of_bounds_access(pvector):
  452. e = pvector([1]).evolver()
  453. with pytest.raises(IndexError):
  454. x = e[1]
  455. def test_evolver_out_of_bounds_assignment(pvector):
  456. e = pvector([1]).evolver()
  457. with pytest.raises(IndexError):
  458. e[2] = 1
  459. def test_no_dependencies_between_evolvers_from_the_same_pvector(pvector):
  460. original_list = list(range(40))
  461. v = pvector(original_list)
  462. e1 = v.evolver()
  463. e2 = v.evolver()
  464. e1.extend([1, 2, 3])
  465. e1[2] = 20
  466. e1[35] = 350
  467. e2.extend([-1, -2, -3])
  468. e2[2] = -20
  469. e2[35] = -350
  470. e1_expected = original_list + [1, 2, 3]
  471. e1_expected[2] = 20
  472. e1_expected[35] = 350
  473. assert list(e1.persistent()) == e1_expected
  474. e2_expected = original_list + [-1, -2, -3]
  475. e2_expected[2] = -20
  476. e2_expected[35] = -350
  477. assert list(e2.persistent()) == e2_expected
  478. def test_pvectors_produced_from_the_same_evolver_do_not_interfere(pvector):
  479. original_list = list(range(40))
  480. v = pvector(original_list)
  481. e = v.evolver()
  482. e.extend([1, 2, 3])
  483. e[2] = 20
  484. e[35] = 350
  485. v1 = e.persistent()
  486. v1_expected = original_list + [1, 2, 3]
  487. v1_expected[2] = 20
  488. v1_expected[35] = 350
  489. e.extend([-1, -2, -3])
  490. e[3] = -30
  491. e[36] = -360
  492. v2 = e.persistent()
  493. v2_expected = v1_expected + [-1, -2, -3]
  494. v2_expected[3] = -30
  495. v2_expected[36] = -360
  496. assert list(v1) == v1_expected
  497. assert list(v2) == v2_expected
  498. def test_evolver_len(pvector):
  499. e = pvector([1, 2, 3]).evolver()
  500. e.extend([4, 5])
  501. assert len(e) == 5
  502. def test_evolver_is_dirty(pvector):
  503. e = pvector([1, 2, 3]).evolver()
  504. assert not e.is_dirty()
  505. e.append(4)
  506. assert e.is_dirty
  507. e.persistent()
  508. assert not e.is_dirty()
  509. e[2] = 2000
  510. assert e.is_dirty
  511. e.persistent()
  512. assert not e.is_dirty()
  513. def test_vector_insert_one_step_beyond_end(pvector):
  514. # This test exists to get the transform functionality under memory
  515. # leak supervision. Most of the transformation tests are in test_transform.py.
  516. v = pvector([1, 2])
  517. assert v.transform([2], 3) == pvector([1, 2, 3])
  518. def test_evolver_with_no_updates_returns_same_pvector(pvector):
  519. v = pvector([1, 2])
  520. assert v.evolver().persistent() is v
  521. def test_evolver_returns_itself_on_evolving_operations(pvector):
  522. # Does this to be able to chain operations
  523. v = pvector([1, 2])
  524. assert v.evolver().append(3).extend([4, 5]).set(1, 6).persistent() == pvector([1, 6, 3, 4, 5])
  525. def test_evolver_delete_by_index(pvector):
  526. e = pvector([1, 2, 3]).evolver()
  527. del e[0]
  528. assert e.persistent() == python_pvector([2, 3])
  529. assert e.append(4).persistent() == python_pvector([2, 3, 4])
  530. def test_evolver_delete_function_by_index(pvector):
  531. e = pvector([1, 2, 3]).evolver()
  532. assert e.delete(1).persistent() == python_pvector([1, 3])
  533. def test_evolver_delete_function_by_index_multiple_times(pvector):
  534. SIZE = 40
  535. e = pvector(range(SIZE)).evolver()
  536. for i in range(SIZE):
  537. assert e[0] == i
  538. assert list(e.persistent()) == list(range(i, SIZE))
  539. del e[0]
  540. assert e.persistent() == list()
  541. def test_evolver_delete_function_invalid_index(pvector):
  542. e = pvector([1, 2]).evolver()
  543. with pytest.raises(TypeError):
  544. del e["e"]
  545. def test_delete_of_non_existing_element(pvector):
  546. e = pvector([1, 2]).evolver()
  547. with pytest.raises(IndexError):
  548. del e[2]
  549. del e[0]
  550. del e[0]
  551. with pytest.raises(IndexError):
  552. del e[0]
  553. assert e.persistent() == pvector()
  554. def test_append_followed_by_delete(pvector):
  555. e = pvector([1, 2]).evolver()
  556. e.append(3)
  557. del e[2]
  558. def test_evolver_set_followed_by_delete(pvector):
  559. evolver = pvector([1, 2]).evolver()
  560. evolver[1] = 3
  561. assert [evolver[i] for i in range(len(evolver))] == [1, 3]
  562. del evolver[0]
  563. assert evolver.persistent() == pvector([3])
  564. def test_compare_with_list(pvector):
  565. v = pvector([1, 2, 3])
  566. assert v == [1, 2, 3]
  567. assert v != [1, 2]
  568. assert v > [1, 2]
  569. assert v < [2, 2]
  570. assert [1, 2] < v
  571. assert v <= [1, 2, 3]
  572. assert v <= [1, 2, 4]
  573. assert v >= [1, 2, 3]
  574. assert v >= [1, 2]
  575. def test_compare_with_non_iterable(pvector):
  576. assert pvector([1, 2, 3]) != 5
  577. assert not (pvector([1, 2, 3]) == 5)
  578. def test_python_no_c_extension_with_environment_variable():
  579. from six.moves import reload_module
  580. import pyrsistent._pvector
  581. import pyrsistent
  582. import os
  583. os.environ['PYRSISTENT_NO_C_EXTENSION'] = 'TRUE'
  584. reload_module(pyrsistent._pvector)
  585. reload_module(pyrsistent)
  586. assert type(pyrsistent.pvector()) is pyrsistent._pvector.PythonPVector
  587. del os.environ['PYRSISTENT_NO_C_EXTENSION']
  588. reload_module(pyrsistent._pvector)
  589. reload_module(pyrsistent)
  590. def test_supports_weakref(pvector):
  591. import weakref
  592. weakref.ref(pvector())
  593. def test_get_evolver_referents(pvector):
  594. """The C implementation of the evolver should expose the original PVector
  595. to the gc only once.
  596. """
  597. if pvector.__module__ == 'pyrsistent._pvector':
  598. pytest.skip("This test only applies to pvectorc")
  599. import gc
  600. v = pvector([1, 2, 3])
  601. e = v.evolver()
  602. assert len([x for x in gc.get_referents(e) if x is v]) == 1
  603. def test_failing_repr(pvector):
  604. # See https://github.com/tobgu/pyrsistent/issues/84
  605. class A(object):
  606. def __repr__(self):
  607. raise ValueError('oh no!')
  608. with pytest.raises(ValueError):
  609. repr(pvector([A()]))
  610. def test_iterable(pvector):
  611. """
  612. PVectors can be created from iterables even though they can't be len()
  613. hinted.
  614. """
  615. assert pvector(iter("a")) == pvector(iter("a"))