test_bunch.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import pytest
  2. import pickle
  3. from numpy.testing import assert_equal
  4. from scipy._lib._bunch import _make_tuple_bunch
  5. # `Result` is defined at the top level of the module so it can be
  6. # used to test pickling.
  7. Result = _make_tuple_bunch('Result', ['x', 'y', 'z'], ['w', 'beta'])
  8. class TestMakeTupleBunch:
  9. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  10. # Tests with Result
  11. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  12. def setup_method(self):
  13. # Set up an instance of Result.
  14. self.result = Result(x=1, y=2, z=3, w=99, beta=0.5)
  15. def test_attribute_access(self):
  16. assert_equal(self.result.x, 1)
  17. assert_equal(self.result.y, 2)
  18. assert_equal(self.result.z, 3)
  19. assert_equal(self.result.w, 99)
  20. assert_equal(self.result.beta, 0.5)
  21. def test_indexing(self):
  22. assert_equal(self.result[0], 1)
  23. assert_equal(self.result[1], 2)
  24. assert_equal(self.result[2], 3)
  25. assert_equal(self.result[-1], 3)
  26. with pytest.raises(IndexError, match='index out of range'):
  27. self.result[3]
  28. def test_unpacking(self):
  29. x0, y0, z0 = self.result
  30. assert_equal((x0, y0, z0), (1, 2, 3))
  31. assert_equal(self.result, (1, 2, 3))
  32. def test_slice(self):
  33. assert_equal(self.result[1:], (2, 3))
  34. assert_equal(self.result[::2], (1, 3))
  35. assert_equal(self.result[::-1], (3, 2, 1))
  36. def test_len(self):
  37. assert_equal(len(self.result), 3)
  38. def test_repr(self):
  39. s = repr(self.result)
  40. assert_equal(s, 'Result(x=1, y=2, z=3, w=99, beta=0.5)')
  41. def test_hash(self):
  42. assert_equal(hash(self.result), hash((1, 2, 3)))
  43. def test_pickle(self):
  44. s = pickle.dumps(self.result)
  45. obj = pickle.loads(s)
  46. assert isinstance(obj, Result)
  47. assert_equal(obj.x, self.result.x)
  48. assert_equal(obj.y, self.result.y)
  49. assert_equal(obj.z, self.result.z)
  50. assert_equal(obj.w, self.result.w)
  51. assert_equal(obj.beta, self.result.beta)
  52. def test_read_only_existing(self):
  53. with pytest.raises(AttributeError, match="can't set attribute"):
  54. self.result.x = -1
  55. def test_read_only_new(self):
  56. self.result.plate_of_shrimp = "lattice of coincidence"
  57. assert self.result.plate_of_shrimp == "lattice of coincidence"
  58. def test_constructor_missing_parameter(self):
  59. with pytest.raises(TypeError, match='missing'):
  60. # `w` is missing.
  61. Result(x=1, y=2, z=3, beta=0.75)
  62. def test_constructor_incorrect_parameter(self):
  63. with pytest.raises(TypeError, match='unexpected'):
  64. # `foo` is not an existing field.
  65. Result(x=1, y=2, z=3, w=123, beta=0.75, foo=999)
  66. def test_module(self):
  67. m = 'scipy._lib.tests.test_bunch'
  68. assert_equal(Result.__module__, m)
  69. assert_equal(self.result.__module__, m)
  70. def test_extra_fields_per_instance(self):
  71. # This test exists to ensure that instances of the same class
  72. # store their own values for the extra fields. That is, the values
  73. # are stored per instance and not in the class.
  74. result1 = Result(x=1, y=2, z=3, w=-1, beta=0.0)
  75. result2 = Result(x=4, y=5, z=6, w=99, beta=1.0)
  76. assert_equal(result1.w, -1)
  77. assert_equal(result1.beta, 0.0)
  78. # The rest of these checks aren't essential, but let's check
  79. # them anyway.
  80. assert_equal(result1[:], (1, 2, 3))
  81. assert_equal(result2.w, 99)
  82. assert_equal(result2.beta, 1.0)
  83. assert_equal(result2[:], (4, 5, 6))
  84. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  85. # Other tests
  86. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  87. def test_extra_field_names_is_optional(self):
  88. Square = _make_tuple_bunch('Square', ['width', 'height'])
  89. sq = Square(width=1, height=2)
  90. assert_equal(sq.width, 1)
  91. assert_equal(sq.height, 2)
  92. s = repr(sq)
  93. assert_equal(s, 'Square(width=1, height=2)')
  94. def test_tuple_like(self):
  95. Tup = _make_tuple_bunch('Tup', ['a', 'b'])
  96. tu = Tup(a=1, b=2)
  97. assert isinstance(tu, tuple)
  98. assert isinstance(tu + (1,), tuple)
  99. def test_explicit_module(self):
  100. m = 'some.module.name'
  101. Foo = _make_tuple_bunch('Foo', ['x'], ['a', 'b'], module=m)
  102. foo = Foo(x=1, a=355, b=113)
  103. assert_equal(Foo.__module__, m)
  104. assert_equal(foo.__module__, m)
  105. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  106. # Argument validation
  107. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  108. @pytest.mark.parametrize('args', [('123', ['a'], ['b']),
  109. ('Foo', ['-3'], ['x']),
  110. ('Foo', ['a'], ['+-*/'])])
  111. def test_identifiers_not_allowed(self, args):
  112. with pytest.raises(ValueError, match='identifiers'):
  113. _make_tuple_bunch(*args)
  114. @pytest.mark.parametrize('args', [('Foo', ['a', 'b', 'a'], ['x']),
  115. ('Foo', ['a', 'b'], ['b', 'x'])])
  116. def test_repeated_field_names(self, args):
  117. with pytest.raises(ValueError, match='Duplicate'):
  118. _make_tuple_bunch(*args)
  119. @pytest.mark.parametrize('args', [('Foo', ['_a'], ['x']),
  120. ('Foo', ['a'], ['_x'])])
  121. def test_leading_underscore_not_allowed(self, args):
  122. with pytest.raises(ValueError, match='underscore'):
  123. _make_tuple_bunch(*args)
  124. @pytest.mark.parametrize('args', [('Foo', ['def'], ['x']),
  125. ('Foo', ['a'], ['or']),
  126. ('and', ['a'], ['x'])])
  127. def test_keyword_not_allowed_in_fields(self, args):
  128. with pytest.raises(ValueError, match='keyword'):
  129. _make_tuple_bunch(*args)
  130. def test_at_least_one_field_name_required(self):
  131. with pytest.raises(ValueError, match='at least one name'):
  132. _make_tuple_bunch('Qwerty', [], ['a', 'b'])