interface.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import warnings
  2. import numpy as np
  3. import pytest
  4. from pandas.compat.numpy import np_version_gt2
  5. from pandas.core.dtypes.cast import construct_1d_object_array_from_listlike
  6. from pandas.core.dtypes.common import is_extension_array_dtype
  7. from pandas.core.dtypes.dtypes import ExtensionDtype
  8. import pandas as pd
  9. import pandas._testing as tm
  10. class BaseInterfaceTests:
  11. """Tests that the basic interface is satisfied."""
  12. # ------------------------------------------------------------------------
  13. # Interface
  14. # ------------------------------------------------------------------------
  15. def test_len(self, data):
  16. assert len(data) == 100
  17. def test_size(self, data):
  18. assert data.size == 100
  19. def test_ndim(self, data):
  20. assert data.ndim == 1
  21. def test_can_hold_na_valid(self, data):
  22. # GH-20761
  23. assert data._can_hold_na is True
  24. def test_contains(self, data, data_missing):
  25. # GH-37867
  26. # Tests for membership checks. Membership checks for nan-likes is tricky and
  27. # the settled on rule is: `nan_like in arr` is True if nan_like is
  28. # arr.dtype.na_value and arr.isna().any() is True. Else the check returns False.
  29. na_value = data.dtype.na_value
  30. # ensure data without missing values
  31. data = data[~data.isna()]
  32. # first elements are non-missing
  33. assert data[0] in data
  34. assert data_missing[0] in data_missing
  35. # check the presence of na_value
  36. assert na_value in data_missing
  37. assert na_value not in data
  38. # the data can never contain other nan-likes than na_value
  39. for na_value_obj in tm.NULL_OBJECTS:
  40. if na_value_obj is na_value or type(na_value_obj) == type(na_value):
  41. # type check for e.g. two instances of Decimal("NAN")
  42. continue
  43. assert na_value_obj not in data
  44. assert na_value_obj not in data_missing
  45. def test_memory_usage(self, data):
  46. s = pd.Series(data)
  47. result = s.memory_usage(index=False)
  48. assert result == s.nbytes
  49. def test_array_interface(self, data):
  50. result = np.array(data)
  51. assert result[0] == data[0]
  52. result = np.array(data, dtype=object)
  53. expected = np.array(list(data), dtype=object)
  54. if expected.ndim > 1:
  55. # nested data, explicitly construct as 1D
  56. expected = construct_1d_object_array_from_listlike(list(data))
  57. tm.assert_numpy_array_equal(result, expected)
  58. def test_array_interface_copy(self, data):
  59. result_copy1 = np.array(data, copy=True)
  60. result_copy2 = np.array(data, copy=True)
  61. assert not np.may_share_memory(result_copy1, result_copy2)
  62. if not np_version_gt2:
  63. # copy=False semantics are only supported in NumPy>=2.
  64. return
  65. warning_raised = False
  66. msg = "Starting with NumPy 2.0, the behavior of the 'copy' keyword has changed"
  67. with warnings.catch_warnings(record=True) as w:
  68. warnings.simplefilter("always")
  69. result_nocopy1 = np.array(data, copy=False)
  70. assert len(w) <= 1
  71. if len(w):
  72. warning_raised = True
  73. assert msg in str(w[0].message)
  74. with warnings.catch_warnings(record=True) as w:
  75. warnings.simplefilter("always")
  76. result_nocopy2 = np.array(data, copy=False)
  77. assert len(w) <= 1
  78. if len(w):
  79. warning_raised = True
  80. assert msg in str(w[0].message)
  81. if not warning_raised:
  82. # If copy=False was given and did not raise, these must share the same data
  83. assert np.may_share_memory(result_nocopy1, result_nocopy2)
  84. def test_is_extension_array_dtype(self, data):
  85. assert is_extension_array_dtype(data)
  86. assert is_extension_array_dtype(data.dtype)
  87. assert is_extension_array_dtype(pd.Series(data))
  88. assert isinstance(data.dtype, ExtensionDtype)
  89. def test_no_values_attribute(self, data):
  90. # GH-20735: EA's with .values attribute give problems with internal
  91. # code, disallowing this for now until solved
  92. assert not hasattr(data, "values")
  93. assert not hasattr(data, "_values")
  94. def test_is_numeric_honored(self, data):
  95. result = pd.Series(data)
  96. if hasattr(result._mgr, "blocks"):
  97. assert result._mgr.blocks[0].is_numeric is data.dtype._is_numeric
  98. def test_isna_extension_array(self, data_missing):
  99. # If your `isna` returns an ExtensionArray, you must also implement
  100. # _reduce. At the *very* least, you must implement any and all
  101. na = data_missing.isna()
  102. if is_extension_array_dtype(na):
  103. assert na._reduce("any")
  104. assert na.any()
  105. assert not na._reduce("all")
  106. assert not na.all()
  107. assert na.dtype._is_boolean
  108. def test_copy(self, data):
  109. # GH#27083 removing deep keyword from EA.copy
  110. assert data[0] != data[1]
  111. result = data.copy()
  112. if data.dtype._is_immutable:
  113. pytest.skip(f"test_copy assumes mutability and {data.dtype} is immutable")
  114. data[1] = data[0]
  115. assert result[1] != result[0]
  116. def test_view(self, data):
  117. # view with no dtype should return a shallow copy, *not* the same
  118. # object
  119. assert data[1] != data[0]
  120. result = data.view()
  121. assert result is not data
  122. assert type(result) == type(data)
  123. if data.dtype._is_immutable:
  124. pytest.skip(f"test_view assumes mutability and {data.dtype} is immutable")
  125. result[1] = result[0]
  126. assert data[1] == data[0]
  127. # check specifically that the `dtype` kwarg is accepted
  128. data.view(dtype=None)
  129. def test_tolist(self, data):
  130. result = data.tolist()
  131. expected = list(data)
  132. assert isinstance(result, list)
  133. assert result == expected