test_invalid_arg.py 11 KB

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