test_numpy.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. """
  2. Additional tests for PandasArray that aren't covered by
  3. the interface tests.
  4. """
  5. import numpy as np
  6. import pytest
  7. import pandas as pd
  8. import pandas._testing as tm
  9. from pandas.arrays import PandasArray
  10. from pandas.core.arrays.numpy_ import PandasDtype
  11. @pytest.fixture(
  12. params=[
  13. np.array(["a", "b"], dtype=object),
  14. np.array([0, 1], dtype=float),
  15. np.array([0, 1], dtype=int),
  16. np.array([0, 1 + 2j], dtype=complex),
  17. np.array([True, False], dtype=bool),
  18. np.array([0, 1], dtype="datetime64[ns]"),
  19. np.array([0, 1], dtype="timedelta64[ns]"),
  20. ]
  21. )
  22. def any_numpy_array(request):
  23. """
  24. Parametrized fixture for NumPy arrays with different dtypes.
  25. This excludes string and bytes.
  26. """
  27. return request.param
  28. # ----------------------------------------------------------------------------
  29. # PandasDtype
  30. @pytest.mark.parametrize(
  31. "dtype, expected",
  32. [
  33. ("bool", True),
  34. ("int", True),
  35. ("uint", True),
  36. ("float", True),
  37. ("complex", True),
  38. ("str", False),
  39. ("bytes", False),
  40. ("datetime64[ns]", False),
  41. ("object", False),
  42. ("void", False),
  43. ],
  44. )
  45. def test_is_numeric(dtype, expected):
  46. dtype = PandasDtype(dtype)
  47. assert dtype._is_numeric is expected
  48. @pytest.mark.parametrize(
  49. "dtype, expected",
  50. [
  51. ("bool", True),
  52. ("int", False),
  53. ("uint", False),
  54. ("float", False),
  55. ("complex", False),
  56. ("str", False),
  57. ("bytes", False),
  58. ("datetime64[ns]", False),
  59. ("object", False),
  60. ("void", False),
  61. ],
  62. )
  63. def test_is_boolean(dtype, expected):
  64. dtype = PandasDtype(dtype)
  65. assert dtype._is_boolean is expected
  66. def test_repr():
  67. dtype = PandasDtype(np.dtype("int64"))
  68. assert repr(dtype) == "PandasDtype('int64')"
  69. def test_constructor_from_string():
  70. result = PandasDtype.construct_from_string("int64")
  71. expected = PandasDtype(np.dtype("int64"))
  72. assert result == expected
  73. # ----------------------------------------------------------------------------
  74. # Construction
  75. def test_constructor_no_coercion():
  76. with pytest.raises(ValueError, match="NumPy array"):
  77. PandasArray([1, 2, 3])
  78. def test_series_constructor_with_copy():
  79. ndarray = np.array([1, 2, 3])
  80. ser = pd.Series(PandasArray(ndarray), copy=True)
  81. assert ser.values is not ndarray
  82. def test_series_constructor_with_astype():
  83. ndarray = np.array([1, 2, 3])
  84. result = pd.Series(PandasArray(ndarray), dtype="float64")
  85. expected = pd.Series([1.0, 2.0, 3.0], dtype="float64")
  86. tm.assert_series_equal(result, expected)
  87. def test_from_sequence_dtype():
  88. arr = np.array([1, 2, 3], dtype="int64")
  89. result = PandasArray._from_sequence(arr, dtype="uint64")
  90. expected = PandasArray(np.array([1, 2, 3], dtype="uint64"))
  91. tm.assert_extension_array_equal(result, expected)
  92. def test_constructor_copy():
  93. arr = np.array([0, 1])
  94. result = PandasArray(arr, copy=True)
  95. assert np.shares_memory(result._ndarray, arr) is False
  96. def test_constructor_with_data(any_numpy_array):
  97. nparr = any_numpy_array
  98. arr = PandasArray(nparr)
  99. assert arr.dtype.numpy_dtype == nparr.dtype
  100. # ----------------------------------------------------------------------------
  101. # Conversion
  102. def test_to_numpy():
  103. arr = PandasArray(np.array([1, 2, 3]))
  104. result = arr.to_numpy()
  105. assert result is arr._ndarray
  106. result = arr.to_numpy(copy=True)
  107. assert result is not arr._ndarray
  108. result = arr.to_numpy(dtype="f8")
  109. expected = np.array([1, 2, 3], dtype="f8")
  110. tm.assert_numpy_array_equal(result, expected)
  111. # ----------------------------------------------------------------------------
  112. # Setitem
  113. def test_setitem_series():
  114. ser = pd.Series([1, 2, 3])
  115. ser.array[0] = 10
  116. expected = pd.Series([10, 2, 3])
  117. tm.assert_series_equal(ser, expected)
  118. def test_setitem(any_numpy_array):
  119. nparr = any_numpy_array
  120. arr = PandasArray(nparr, copy=True)
  121. arr[0] = arr[1]
  122. nparr[0] = nparr[1]
  123. tm.assert_numpy_array_equal(arr.to_numpy(), nparr)
  124. # ----------------------------------------------------------------------------
  125. # Reductions
  126. def test_bad_reduce_raises():
  127. arr = np.array([1, 2, 3], dtype="int64")
  128. arr = PandasArray(arr)
  129. msg = "cannot perform not_a_method with type int"
  130. with pytest.raises(TypeError, match=msg):
  131. arr._reduce(msg)
  132. def test_validate_reduction_keyword_args():
  133. arr = PandasArray(np.array([1, 2, 3]))
  134. msg = "the 'keepdims' parameter is not supported .*all"
  135. with pytest.raises(ValueError, match=msg):
  136. arr.all(keepdims=True)
  137. # ----------------------------------------------------------------------------
  138. # Ops
  139. def test_ufunc():
  140. arr = PandasArray(np.array([-1.0, 0.0, 1.0]))
  141. result = np.abs(arr)
  142. expected = PandasArray(np.abs(arr._ndarray))
  143. tm.assert_extension_array_equal(result, expected)
  144. r1, r2 = np.divmod(arr, np.add(arr, 2))
  145. e1, e2 = np.divmod(arr._ndarray, np.add(arr._ndarray, 2))
  146. e1 = PandasArray(e1)
  147. e2 = PandasArray(e2)
  148. tm.assert_extension_array_equal(r1, e1)
  149. tm.assert_extension_array_equal(r2, e2)
  150. def test_basic_binop():
  151. # Just a basic smoke test. The EA interface tests exercise this
  152. # more thoroughly.
  153. x = PandasArray(np.array([1, 2, 3]))
  154. result = x + x
  155. expected = PandasArray(np.array([2, 4, 6]))
  156. tm.assert_extension_array_equal(result, expected)
  157. @pytest.mark.parametrize("dtype", [None, object])
  158. def test_setitem_object_typecode(dtype):
  159. arr = PandasArray(np.array(["a", "b", "c"], dtype=dtype))
  160. arr[0] = "t"
  161. expected = PandasArray(np.array(["t", "b", "c"], dtype=dtype))
  162. tm.assert_extension_array_equal(arr, expected)
  163. def test_setitem_no_coercion():
  164. # https://github.com/pandas-dev/pandas/issues/28150
  165. arr = PandasArray(np.array([1, 2, 3]))
  166. with pytest.raises(ValueError, match="int"):
  167. arr[0] = "a"
  168. # With a value that we do coerce, check that we coerce the value
  169. # and not the underlying array.
  170. arr[0] = 2.5
  171. assert isinstance(arr[0], (int, np.integer)), type(arr[0])
  172. def test_setitem_preserves_views():
  173. # GH#28150, see also extension test of the same name
  174. arr = PandasArray(np.array([1, 2, 3]))
  175. view1 = arr.view()
  176. view2 = arr[:]
  177. view3 = np.asarray(arr)
  178. arr[0] = 9
  179. assert view1[0] == 9
  180. assert view2[0] == 9
  181. assert view3[0] == 9
  182. arr[-1] = 2.5
  183. view1[-1] = 5
  184. assert arr[-1] == 5