test_invalid_arg.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. # Tests specifically aimed at detecting bad arguments.
  2. # This file is organized by reason for exception.
  3. # 1. always invalid argument values
  4. # 2. missing column(s)
  5. # 3. incompatible ops/dtype/args/kwargs
  6. # 4. invalid result shape/type
  7. # If your test does not fit into one of these categories, add to this list.
  8. from itertools import chain
  9. import re
  10. import numpy as np
  11. import pytest
  12. from pandas.errors import SpecificationError
  13. from pandas import (
  14. Categorical,
  15. DataFrame,
  16. Series,
  17. date_range,
  18. notna,
  19. )
  20. import pandas._testing as tm
  21. @pytest.mark.parametrize("result_type", ["foo", 1])
  22. def test_result_type_error(result_type, int_frame_const_col):
  23. # allowed result_type
  24. df = int_frame_const_col
  25. msg = (
  26. "invalid value for result_type, must be one of "
  27. "{None, 'reduce', 'broadcast', 'expand'}"
  28. )
  29. with pytest.raises(ValueError, match=msg):
  30. df.apply(lambda x: [1, 2, 3], axis=1, result_type=result_type)
  31. def test_apply_invalid_axis_value():
  32. df = DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=["a", "a", "c"])
  33. msg = "No axis named 2 for object type DataFrame"
  34. with pytest.raises(ValueError, match=msg):
  35. df.apply(lambda x: x, 2)
  36. def test_applymap_invalid_na_action(float_frame):
  37. # GH 23803
  38. with pytest.raises(ValueError, match="na_action must be .*Got 'abc'"):
  39. float_frame.applymap(lambda x: len(str(x)), na_action="abc")
  40. def test_agg_raises():
  41. # GH 26513
  42. df = DataFrame({"A": [0, 1], "B": [1, 2]})
  43. msg = "Must provide"
  44. with pytest.raises(TypeError, match=msg):
  45. df.agg()
  46. def test_map_with_invalid_na_action_raises():
  47. # https://github.com/pandas-dev/pandas/issues/32815
  48. s = Series([1, 2, 3])
  49. msg = "na_action must either be 'ignore' or None"
  50. with pytest.raises(ValueError, match=msg):
  51. s.map(lambda x: x, na_action="____")
  52. @pytest.mark.parametrize("input_na_action", ["____", True])
  53. def test_map_arg_is_dict_with_invalid_na_action_raises(input_na_action):
  54. # https://github.com/pandas-dev/pandas/issues/46588
  55. s = Series([1, 2, 3])
  56. msg = f"na_action must either be 'ignore' or None, {input_na_action} was passed"
  57. with pytest.raises(ValueError, match=msg):
  58. s.map({1: 2}, na_action=input_na_action)
  59. def test_map_categorical_na_action():
  60. values = Categorical(list("ABBABCD"), categories=list("DCBA"), ordered=True)
  61. s = Series(values, name="XX", index=list("abcdefg"))
  62. with pytest.raises(NotImplementedError, match=tm.EMPTY_STRING_PATTERN):
  63. s.map(lambda x: x, na_action="ignore")
  64. def test_map_datetimetz_na_action():
  65. values = date_range("2011-01-01", "2011-01-02", freq="H").tz_localize("Asia/Tokyo")
  66. s = Series(values, name="XX")
  67. with pytest.raises(NotImplementedError, match=tm.EMPTY_STRING_PATTERN):
  68. s.map(lambda x: x, na_action="ignore")
  69. @pytest.mark.parametrize("method", ["apply", "agg", "transform"])
  70. @pytest.mark.parametrize("func", [{"A": {"B": "sum"}}, {"A": {"B": ["sum"]}}])
  71. def test_nested_renamer(frame_or_series, method, func):
  72. # GH 35964
  73. obj = frame_or_series({"A": [1]})
  74. match = "nested renamer is not supported"
  75. with pytest.raises(SpecificationError, match=match):
  76. getattr(obj, method)(func)
  77. @pytest.mark.parametrize(
  78. "renamer",
  79. [{"foo": ["min", "max"]}, {"foo": ["min", "max"], "bar": ["sum", "mean"]}],
  80. )
  81. def test_series_nested_renamer(renamer):
  82. s = Series(range(6), dtype="int64", name="series")
  83. msg = "nested renamer is not supported"
  84. with pytest.raises(SpecificationError, match=msg):
  85. s.agg(renamer)
  86. def test_apply_dict_depr():
  87. tsdf = DataFrame(
  88. np.random.randn(10, 3),
  89. columns=["A", "B", "C"],
  90. index=date_range("1/1/2000", periods=10),
  91. )
  92. msg = "nested renamer is not supported"
  93. with pytest.raises(SpecificationError, match=msg):
  94. tsdf.A.agg({"foo": ["sum", "mean"]})
  95. @pytest.mark.parametrize("method", ["agg", "transform"])
  96. def test_dict_nested_renaming_depr(method):
  97. df = DataFrame({"A": range(5), "B": 5})
  98. # nested renaming
  99. msg = r"nested renamer is not supported"
  100. with pytest.raises(SpecificationError, match=msg):
  101. getattr(df, method)({"A": {"foo": "min"}, "B": {"bar": "max"}})
  102. @pytest.mark.parametrize("method", ["apply", "agg", "transform"])
  103. @pytest.mark.parametrize("func", [{"B": "sum"}, {"B": ["sum"]}])
  104. def test_missing_column(method, func):
  105. # GH 40004
  106. obj = DataFrame({"A": [1]})
  107. match = re.escape("Column(s) ['B'] do not exist")
  108. with pytest.raises(KeyError, match=match):
  109. getattr(obj, method)(func)
  110. def test_transform_mixed_column_name_dtypes():
  111. # GH39025
  112. df = DataFrame({"a": ["1"]})
  113. msg = r"Column\(s\) \[1, 'b'\] do not exist"
  114. with pytest.raises(KeyError, match=msg):
  115. df.transform({"a": int, 1: str, "b": int})
  116. @pytest.mark.parametrize(
  117. "how, args", [("pct_change", ()), ("nsmallest", (1, ["a", "b"])), ("tail", 1)]
  118. )
  119. def test_apply_str_axis_1_raises(how, args):
  120. # GH 39211 - some ops don't support axis=1
  121. df = DataFrame({"a": [1, 2], "b": [3, 4]})
  122. msg = f"Operation {how} does not support axis=1"
  123. with pytest.raises(ValueError, match=msg):
  124. df.apply(how, axis=1, args=args)
  125. def test_transform_axis_1_raises():
  126. # GH 35964
  127. msg = "No axis named 1 for object type Series"
  128. with pytest.raises(ValueError, match=msg):
  129. Series([1]).transform("sum", axis=1)
  130. def test_apply_modify_traceback():
  131. data = DataFrame(
  132. {
  133. "A": [
  134. "foo",
  135. "foo",
  136. "foo",
  137. "foo",
  138. "bar",
  139. "bar",
  140. "bar",
  141. "bar",
  142. "foo",
  143. "foo",
  144. "foo",
  145. ],
  146. "B": [
  147. "one",
  148. "one",
  149. "one",
  150. "two",
  151. "one",
  152. "one",
  153. "one",
  154. "two",
  155. "two",
  156. "two",
  157. "one",
  158. ],
  159. "C": [
  160. "dull",
  161. "dull",
  162. "shiny",
  163. "dull",
  164. "dull",
  165. "shiny",
  166. "shiny",
  167. "dull",
  168. "shiny",
  169. "shiny",
  170. "shiny",
  171. ],
  172. "D": np.random.randn(11),
  173. "E": np.random.randn(11),
  174. "F": np.random.randn(11),
  175. }
  176. )
  177. data.loc[4, "C"] = np.nan
  178. def transform(row):
  179. if row["C"].startswith("shin") and row["A"] == "foo":
  180. row["D"] = 7
  181. return row
  182. def transform2(row):
  183. if notna(row["C"]) and row["C"].startswith("shin") and row["A"] == "foo":
  184. row["D"] = 7
  185. return row
  186. msg = "'float' object has no attribute 'startswith'"
  187. with pytest.raises(AttributeError, match=msg):
  188. data.apply(transform, axis=1)
  189. @pytest.mark.parametrize(
  190. "df, func, expected",
  191. tm.get_cython_table_params(
  192. DataFrame([["a", "b"], ["b", "a"]]), [["cumprod", TypeError]]
  193. ),
  194. )
  195. def test_agg_cython_table_raises_frame(df, func, expected, axis):
  196. # GH 21224
  197. msg = "can't multiply sequence by non-int of type 'str'"
  198. with pytest.raises(expected, match=msg):
  199. df.agg(func, axis=axis)
  200. @pytest.mark.parametrize(
  201. "series, func, expected",
  202. chain(
  203. tm.get_cython_table_params(
  204. Series("a b c".split()),
  205. [
  206. ("mean", TypeError), # mean raises TypeError
  207. ("prod", TypeError),
  208. ("std", TypeError),
  209. ("var", TypeError),
  210. ("median", TypeError),
  211. ("cumprod", TypeError),
  212. ],
  213. )
  214. ),
  215. )
  216. def test_agg_cython_table_raises_series(series, func, expected):
  217. # GH21224
  218. msg = r"[Cc]ould not convert|can't multiply sequence by non-int of type"
  219. with pytest.raises(expected, match=msg):
  220. # e.g. Series('a b'.split()).cumprod() will raise
  221. series.agg(func)
  222. def test_agg_none_to_type():
  223. # GH 40543
  224. df = DataFrame({"a": [None]})
  225. msg = re.escape("int() argument must be a string")
  226. with pytest.raises(TypeError, match=msg):
  227. df.agg({"a": lambda x: int(x.iloc[0])})
  228. def test_transform_none_to_type():
  229. # GH#34377
  230. df = DataFrame({"a": [None]})
  231. msg = "argument must be a"
  232. with pytest.raises(TypeError, match=msg):
  233. df.transform({"a": lambda x: int(x.iloc[0])})
  234. @pytest.mark.parametrize(
  235. "func",
  236. [
  237. lambda x: np.array([1, 2]).reshape(-1, 2),
  238. lambda x: [1, 2],
  239. lambda x: Series([1, 2]),
  240. ],
  241. )
  242. def test_apply_broadcast_error(int_frame_const_col, func):
  243. df = int_frame_const_col
  244. # > 1 ndim
  245. msg = "too many dims to broadcast|cannot broadcast result"
  246. with pytest.raises(ValueError, match=msg):
  247. df.apply(func, axis=1, result_type="broadcast")
  248. def test_transform_and_agg_err_agg(axis, float_frame):
  249. # cannot both transform and agg
  250. msg = "cannot combine transform and aggregation operations"
  251. with pytest.raises(ValueError, match=msg):
  252. with np.errstate(all="ignore"):
  253. float_frame.agg(["max", "sqrt"], axis=axis)
  254. @pytest.mark.parametrize(
  255. "func, msg",
  256. [
  257. (["sqrt", "max"], "cannot combine transform and aggregation"),
  258. (
  259. {"foo": np.sqrt, "bar": "sum"},
  260. "cannot perform both aggregation and transformation",
  261. ),
  262. ],
  263. )
  264. def test_transform_and_agg_err_series(string_series, func, msg):
  265. # we are trying to transform with an aggregator
  266. with pytest.raises(ValueError, match=msg):
  267. with np.errstate(all="ignore"):
  268. string_series.agg(func)
  269. @pytest.mark.parametrize("func", [["max", "min"], ["max", "sqrt"]])
  270. def test_transform_wont_agg_frame(axis, float_frame, func):
  271. # GH 35964
  272. # cannot both transform and agg
  273. msg = "Function did not transform"
  274. with pytest.raises(ValueError, match=msg):
  275. float_frame.transform(func, axis=axis)
  276. @pytest.mark.parametrize("func", [["min", "max"], ["sqrt", "max"]])
  277. def test_transform_wont_agg_series(string_series, func):
  278. # GH 35964
  279. # we are trying to transform with an aggregator
  280. msg = "Function did not transform"
  281. warn = RuntimeWarning if func[0] == "sqrt" else None
  282. warn_msg = "invalid value encountered in sqrt"
  283. with pytest.raises(ValueError, match=msg):
  284. with tm.assert_produces_warning(warn, match=warn_msg, check_stacklevel=False):
  285. string_series.transform(func)
  286. @pytest.mark.parametrize(
  287. "op_wrapper", [lambda x: x, lambda x: [x], lambda x: {"A": x}, lambda x: {"A": [x]}]
  288. )
  289. def test_transform_reducer_raises(all_reductions, frame_or_series, op_wrapper):
  290. # GH 35964
  291. op = op_wrapper(all_reductions)
  292. obj = DataFrame({"A": [1, 2, 3]})
  293. obj = tm.get_obj(obj, frame_or_series)
  294. msg = "Function did not transform"
  295. with pytest.raises(ValueError, match=msg):
  296. obj.transform(op)