checked_vector_test.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import datetime
  2. import pickle
  3. import pytest
  4. from pyrsistent import CheckedPVector, InvariantException, optional, CheckedValueTypeError, PVector
  5. class Naturals(CheckedPVector):
  6. __type__ = int
  7. __invariant__ = lambda value: (value >= 0, 'Negative value')
  8. def test_instantiate():
  9. x = Naturals([1, 2, 3])
  10. assert list(x) == [1, 2, 3]
  11. assert isinstance(x, Naturals)
  12. assert isinstance(x, PVector)
  13. def test_append():
  14. x = Naturals()
  15. x2 = x.append(1)
  16. assert list(x2) == [1]
  17. assert isinstance(x2, Naturals)
  18. def test_extend():
  19. x = Naturals()
  20. x2 = x.extend([1])
  21. assert list(x2) == [1]
  22. assert isinstance(x2, Naturals)
  23. def test_set():
  24. x = Naturals([1, 2])
  25. x2 = x.set(1, 3)
  26. assert list(x2) == [1, 3]
  27. assert isinstance(x2, Naturals)
  28. def test_invalid_type():
  29. try:
  30. Naturals([1, 2.0])
  31. assert False
  32. except CheckedValueTypeError as e:
  33. assert e.expected_types == (int,)
  34. assert e.actual_type is float
  35. assert e.actual_value == 2.0
  36. assert e.source_class is Naturals
  37. x = Naturals([1, 2])
  38. with pytest.raises(TypeError):
  39. x.append(3.0)
  40. with pytest.raises(TypeError):
  41. x.extend([3, 4.0])
  42. with pytest.raises(TypeError):
  43. x.set(1, 2.0)
  44. with pytest.raises(TypeError):
  45. x.evolver()[1] = 2.0
  46. def test_breaking_invariant():
  47. try:
  48. Naturals([1, -1])
  49. assert False
  50. except InvariantException as e:
  51. assert e.invariant_errors == ('Negative value',)
  52. x = Naturals([1, 2])
  53. try:
  54. x.append(-1)
  55. assert False
  56. except InvariantException as e:
  57. assert e.invariant_errors == ('Negative value',)
  58. try:
  59. x.extend([-1])
  60. assert False
  61. except InvariantException as e:
  62. assert e.invariant_errors == ('Negative value',)
  63. try:
  64. x.set(1, -1)
  65. assert False
  66. except InvariantException as e:
  67. assert e.invariant_errors == ('Negative value',)
  68. def test_create_base_case():
  69. x = Naturals.create([1, 2, 3])
  70. assert isinstance(x, Naturals)
  71. assert x == Naturals([1, 2, 3])
  72. def test_create_with_instance_of_checked_pvector_returns_the_argument():
  73. x = Naturals([1, 2, 3])
  74. assert Naturals.create(x) is x
  75. class OptionalNaturals(CheckedPVector):
  76. __type__ = optional(int)
  77. __invariant__ = lambda value: (value is None or value >= 0, 'Negative value')
  78. def test_multiple_allowed_types():
  79. assert list(OptionalNaturals([1, None, 3])) == [1, None, 3]
  80. class NaturalsVector(CheckedPVector):
  81. __type__ = optional(Naturals)
  82. def test_create_of_nested_structure():
  83. assert NaturalsVector([Naturals([1, 2]), Naturals([3, 4]), None]) ==\
  84. NaturalsVector.create([[1, 2], [3, 4], None])
  85. def test_serialize_default_case():
  86. v = CheckedPVector([1, 2, 3])
  87. assert v.serialize() == [1, 2, 3]
  88. class Dates(CheckedPVector):
  89. __type__ = datetime.date
  90. @staticmethod
  91. def __serializer__(format, d):
  92. return d.strftime(format)
  93. def test_serialize_custom_serializer():
  94. d = datetime.date
  95. v = Dates([d(2015, 2, 2), d(2015, 2, 3)])
  96. assert v.serialize(format='%Y-%m-%d') == ['2015-02-02', '2015-02-03']
  97. def test_type_information_is_inherited():
  98. class MultiDates(Dates):
  99. __type__ = int
  100. MultiDates([datetime.date(2015, 2, 4), 5])
  101. with pytest.raises(TypeError):
  102. MultiDates([5.0])
  103. def test_invariants_are_inherited():
  104. class LimitNaturals(Naturals):
  105. __invariant__ = lambda value: (value < 10, 'Too big')
  106. try:
  107. LimitNaturals([10, -1])
  108. assert False
  109. except InvariantException as e:
  110. assert e.invariant_errors == ('Too big', 'Negative value')
  111. def test_invariant_must_be_callable():
  112. with pytest.raises(TypeError):
  113. class InvalidInvariant(CheckedPVector):
  114. __invariant__ = 1
  115. def test_type_spec_must_be_type():
  116. with pytest.raises(TypeError):
  117. class InvalidType(CheckedPVector):
  118. __type__ = 1
  119. def test_repr():
  120. x = Naturals([1, 2])
  121. assert str(x) == 'Naturals([1, 2])'
  122. def test_evolver_returns_same_instance_when_no_updates():
  123. x = Naturals([1, 2])
  124. assert x.evolver().persistent() is x
  125. def test_pickling():
  126. x = Naturals([1, 2])
  127. y = pickle.loads(pickle.dumps(x, -1))
  128. assert x == y
  129. assert isinstance(y, Naturals)
  130. def test_multiple_optional_types():
  131. class Numbers(CheckedPVector):
  132. __type__ = optional(int, float)
  133. numbers = Numbers([1, 2.5, None])
  134. assert numbers.serialize() == [1, 2.5, None]
  135. with pytest.raises(TypeError):
  136. numbers.append('foo')
  137. class NaturalsVectorStr(CheckedPVector):
  138. __type__ = '__tests__.checked_vector_test.Naturals'
  139. def test_check_with_string_specification():
  140. naturals_list = [Naturals([1, 2]), Naturals([3, 4])]
  141. nv = NaturalsVectorStr(naturals_list)
  142. assert nv == naturals_list
  143. def test_create_with_string_specification():
  144. naturals_list = [[1, 2], [3, 4]]
  145. nv = NaturalsVectorStr.create(naturals_list)
  146. assert nv == naturals_list
  147. def test_supports_weakref():
  148. import weakref
  149. weakref.ref(Naturals([]))
  150. def test_create_with_generator_iterator():
  151. # See issue #97
  152. class Numbers(CheckedPVector):
  153. __type__ = int
  154. n = Numbers(i for i in [1, 2, 3])
  155. assert n == Numbers([1, 2, 3])