test_na_scalar.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. from datetime import (
  2. date,
  3. time,
  4. timedelta,
  5. )
  6. import pickle
  7. import numpy as np
  8. import pytest
  9. from pandas._libs.missing import NA
  10. from pandas.core.dtypes.common import is_scalar
  11. import pandas as pd
  12. import pandas._testing as tm
  13. def test_singleton():
  14. assert NA is NA
  15. new_NA = type(NA)()
  16. assert new_NA is NA
  17. def test_repr():
  18. assert repr(NA) == "<NA>"
  19. assert str(NA) == "<NA>"
  20. def test_format():
  21. # GH-34740
  22. assert format(NA) == "<NA>"
  23. assert format(NA, ">10") == " <NA>"
  24. assert format(NA, "xxx") == "<NA>" # NA is flexible, accept any format spec
  25. assert f"{NA}" == "<NA>"
  26. assert f"{NA:>10}" == " <NA>"
  27. assert f"{NA:xxx}" == "<NA>"
  28. def test_truthiness():
  29. msg = "boolean value of NA is ambiguous"
  30. with pytest.raises(TypeError, match=msg):
  31. bool(NA)
  32. with pytest.raises(TypeError, match=msg):
  33. not NA
  34. def test_hashable():
  35. assert hash(NA) == hash(NA)
  36. d = {NA: "test"}
  37. assert d[NA] == "test"
  38. @pytest.mark.parametrize(
  39. "other", [NA, 1, 1.0, "a", b"a", np.int64(1), np.nan], ids=repr
  40. )
  41. def test_arithmetic_ops(all_arithmetic_functions, other):
  42. op = all_arithmetic_functions
  43. if op.__name__ in ("pow", "rpow", "rmod") and isinstance(other, (str, bytes)):
  44. pytest.skip(reason=f"{op.__name__} with NA and {other} not defined.")
  45. if op.__name__ in ("divmod", "rdivmod"):
  46. assert op(NA, other) is (NA, NA)
  47. else:
  48. if op.__name__ == "rpow":
  49. # avoid special case
  50. other += 1
  51. assert op(NA, other) is NA
  52. @pytest.mark.parametrize(
  53. "other",
  54. [
  55. NA,
  56. 1,
  57. 1.0,
  58. "a",
  59. b"a",
  60. np.int64(1),
  61. np.nan,
  62. np.bool_(True),
  63. time(0),
  64. date(1, 2, 3),
  65. timedelta(1),
  66. pd.NaT,
  67. ],
  68. )
  69. def test_comparison_ops(comparison_op, other):
  70. assert comparison_op(NA, other) is NA
  71. assert comparison_op(other, NA) is NA
  72. @pytest.mark.parametrize(
  73. "value",
  74. [
  75. 0,
  76. 0.0,
  77. -0,
  78. -0.0,
  79. False,
  80. np.bool_(False),
  81. np.int_(0),
  82. np.float_(0),
  83. np.int_(-0),
  84. np.float_(-0),
  85. ],
  86. )
  87. @pytest.mark.parametrize("asarray", [True, False])
  88. def test_pow_special(value, asarray):
  89. if asarray:
  90. value = np.array([value])
  91. result = NA**value
  92. if asarray:
  93. result = result[0]
  94. else:
  95. # this assertion isn't possible for ndarray.
  96. assert isinstance(result, type(value))
  97. assert result == 1
  98. @pytest.mark.parametrize(
  99. "value", [1, 1.0, True, np.bool_(True), np.int_(1), np.float_(1)]
  100. )
  101. @pytest.mark.parametrize("asarray", [True, False])
  102. def test_rpow_special(value, asarray):
  103. if asarray:
  104. value = np.array([value])
  105. result = value**NA
  106. if asarray:
  107. result = result[0]
  108. elif not isinstance(value, (np.float_, np.bool_, np.int_)):
  109. # this assertion isn't possible with asarray=True
  110. assert isinstance(result, type(value))
  111. assert result == value
  112. @pytest.mark.parametrize("value", [-1, -1.0, np.int_(-1), np.float_(-1)])
  113. @pytest.mark.parametrize("asarray", [True, False])
  114. def test_rpow_minus_one(value, asarray):
  115. if asarray:
  116. value = np.array([value])
  117. result = value**NA
  118. if asarray:
  119. result = result[0]
  120. assert pd.isna(result)
  121. def test_unary_ops():
  122. assert +NA is NA
  123. assert -NA is NA
  124. assert abs(NA) is NA
  125. assert ~NA is NA
  126. def test_logical_and():
  127. assert NA & True is NA
  128. assert True & NA is NA
  129. assert NA & False is False
  130. assert False & NA is False
  131. assert NA & NA is NA
  132. msg = "unsupported operand type"
  133. with pytest.raises(TypeError, match=msg):
  134. NA & 5
  135. def test_logical_or():
  136. assert NA | True is True
  137. assert True | NA is True
  138. assert NA | False is NA
  139. assert False | NA is NA
  140. assert NA | NA is NA
  141. msg = "unsupported operand type"
  142. with pytest.raises(TypeError, match=msg):
  143. NA | 5
  144. def test_logical_xor():
  145. assert NA ^ True is NA
  146. assert True ^ NA is NA
  147. assert NA ^ False is NA
  148. assert False ^ NA is NA
  149. assert NA ^ NA is NA
  150. msg = "unsupported operand type"
  151. with pytest.raises(TypeError, match=msg):
  152. NA ^ 5
  153. def test_logical_not():
  154. assert ~NA is NA
  155. @pytest.mark.parametrize("shape", [(3,), (3, 3), (1, 2, 3)])
  156. def test_arithmetic_ndarray(shape, all_arithmetic_functions):
  157. op = all_arithmetic_functions
  158. a = np.zeros(shape)
  159. if op.__name__ == "pow":
  160. a += 5
  161. result = op(NA, a)
  162. expected = np.full(a.shape, NA, dtype=object)
  163. tm.assert_numpy_array_equal(result, expected)
  164. def test_is_scalar():
  165. assert is_scalar(NA) is True
  166. def test_isna():
  167. assert pd.isna(NA) is True
  168. assert pd.notna(NA) is False
  169. def test_series_isna():
  170. s = pd.Series([1, NA], dtype=object)
  171. expected = pd.Series([False, True])
  172. tm.assert_series_equal(s.isna(), expected)
  173. def test_ufunc():
  174. assert np.log(NA) is NA
  175. assert np.add(NA, 1) is NA
  176. result = np.divmod(NA, 1)
  177. assert result[0] is NA and result[1] is NA
  178. result = np.frexp(NA)
  179. assert result[0] is NA and result[1] is NA
  180. def test_ufunc_raises():
  181. msg = "ufunc method 'at'"
  182. with pytest.raises(ValueError, match=msg):
  183. np.log.at(NA, 0)
  184. def test_binary_input_not_dunder():
  185. a = np.array([1, 2, 3])
  186. expected = np.array([NA, NA, NA], dtype=object)
  187. result = np.logaddexp(a, NA)
  188. tm.assert_numpy_array_equal(result, expected)
  189. result = np.logaddexp(NA, a)
  190. tm.assert_numpy_array_equal(result, expected)
  191. # all NA, multiple inputs
  192. assert np.logaddexp(NA, NA) is NA
  193. result = np.modf(NA, NA)
  194. assert len(result) == 2
  195. assert all(x is NA for x in result)
  196. def test_divmod_ufunc():
  197. # binary in, binary out.
  198. a = np.array([1, 2, 3])
  199. expected = np.array([NA, NA, NA], dtype=object)
  200. result = np.divmod(a, NA)
  201. assert isinstance(result, tuple)
  202. for arr in result:
  203. tm.assert_numpy_array_equal(arr, expected)
  204. tm.assert_numpy_array_equal(arr, expected)
  205. result = np.divmod(NA, a)
  206. for arr in result:
  207. tm.assert_numpy_array_equal(arr, expected)
  208. tm.assert_numpy_array_equal(arr, expected)
  209. def test_integer_hash_collision_dict():
  210. # GH 30013
  211. result = {NA: "foo", hash(NA): "bar"}
  212. assert result[NA] == "foo"
  213. assert result[hash(NA)] == "bar"
  214. def test_integer_hash_collision_set():
  215. # GH 30013
  216. result = {NA, hash(NA)}
  217. assert len(result) == 2
  218. assert NA in result
  219. assert hash(NA) in result
  220. def test_pickle_roundtrip():
  221. # https://github.com/pandas-dev/pandas/issues/31847
  222. result = pickle.loads(pickle.dumps(NA))
  223. assert result is NA
  224. def test_pickle_roundtrip_pandas():
  225. result = tm.round_trip_pickle(NA)
  226. assert result is NA
  227. @pytest.mark.parametrize(
  228. "values, dtype", [([1, 2, NA], "Int64"), (["A", "B", NA], "string")]
  229. )
  230. @pytest.mark.parametrize("as_frame", [True, False])
  231. def test_pickle_roundtrip_containers(as_frame, values, dtype):
  232. s = pd.Series(pd.array(values, dtype=dtype))
  233. if as_frame:
  234. s = s.to_frame(name="A")
  235. result = tm.round_trip_pickle(s)
  236. tm.assert_equal(result, s)