Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/pandas/compat/numpy/function.py: 47%
184 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2For compatibility with numpy libraries, pandas functions or methods have to
3accept '*args' and '**kwargs' parameters to accommodate numpy arguments that
4are not actually used or respected in the pandas implementation.
6To ensure that users do not abuse these parameters, validation is performed in
7'validators.py' to make sure that any extra parameters passed correspond ONLY
8to those in the numpy signature. Part of that validation includes whether or
9not the user attempted to pass in non-default values for these extraneous
10parameters. As we want to discourage users from relying on these parameters
11when calling the pandas implementation, we want them only to pass in the
12default values for these parameters.
14This module provides a set of commonly used default arguments for functions and
15methods that are spread throughout the codebase. This module will make it
16easier to adjust to future upstream changes in the analogous numpy signatures.
17"""
18from __future__ import annotations
20from typing import (
21 Any,
22 TypeVar,
23 overload,
24)
26from numpy import ndarray
28from pandas._libs.lib import (
29 is_bool,
30 is_integer,
31)
32from pandas._typing import Axis
33from pandas.errors import UnsupportedFunctionCall
34from pandas.util._validators import (
35 validate_args,
36 validate_args_and_kwargs,
37 validate_kwargs,
38)
40AxisNoneT = TypeVar("AxisNoneT", Axis, None)
43class CompatValidator:
44 def __init__(
45 self,
46 defaults,
47 fname=None,
48 method: str | None = None,
49 max_fname_arg_count=None,
50 ) -> None:
51 self.fname = fname
52 self.method = method
53 self.defaults = defaults
54 self.max_fname_arg_count = max_fname_arg_count
56 def __call__(
57 self,
58 args,
59 kwargs,
60 fname=None,
61 max_fname_arg_count=None,
62 method: str | None = None,
63 ) -> None:
64 if args or kwargs:
65 fname = self.fname if fname is None else fname
66 max_fname_arg_count = (
67 self.max_fname_arg_count
68 if max_fname_arg_count is None
69 else max_fname_arg_count
70 )
71 method = self.method if method is None else method
73 if method == "args":
74 validate_args(fname, args, max_fname_arg_count, self.defaults)
75 elif method == "kwargs":
76 validate_kwargs(fname, kwargs, self.defaults)
77 elif method == "both":
78 validate_args_and_kwargs(
79 fname, args, kwargs, max_fname_arg_count, self.defaults
80 )
81 else:
82 raise ValueError(f"invalid validation method '{method}'")
85ARGMINMAX_DEFAULTS = {"out": None}
86validate_argmin = CompatValidator(
87 ARGMINMAX_DEFAULTS, fname="argmin", method="both", max_fname_arg_count=1
88)
89validate_argmax = CompatValidator(
90 ARGMINMAX_DEFAULTS, fname="argmax", method="both", max_fname_arg_count=1
91)
94def process_skipna(skipna: bool | ndarray | None, args) -> tuple[bool, Any]:
95 if isinstance(skipna, ndarray) or skipna is None:
96 args = (skipna,) + args
97 skipna = True
99 return skipna, args
102def validate_argmin_with_skipna(skipna: bool | ndarray | None, args, kwargs) -> bool:
103 """
104 If 'Series.argmin' is called via the 'numpy' library, the third parameter
105 in its signature is 'out', which takes either an ndarray or 'None', so
106 check if the 'skipna' parameter is either an instance of ndarray or is
107 None, since 'skipna' itself should be a boolean
108 """
109 skipna, args = process_skipna(skipna, args)
110 validate_argmin(args, kwargs)
111 return skipna
114def validate_argmax_with_skipna(skipna: bool | ndarray | None, args, kwargs) -> bool:
115 """
116 If 'Series.argmax' is called via the 'numpy' library, the third parameter
117 in its signature is 'out', which takes either an ndarray or 'None', so
118 check if the 'skipna' parameter is either an instance of ndarray or is
119 None, since 'skipna' itself should be a boolean
120 """
121 skipna, args = process_skipna(skipna, args)
122 validate_argmax(args, kwargs)
123 return skipna
126ARGSORT_DEFAULTS: dict[str, int | str | None] = {}
127ARGSORT_DEFAULTS["axis"] = -1
128ARGSORT_DEFAULTS["kind"] = "quicksort"
129ARGSORT_DEFAULTS["order"] = None
130ARGSORT_DEFAULTS["kind"] = None
133validate_argsort = CompatValidator(
134 ARGSORT_DEFAULTS, fname="argsort", max_fname_arg_count=0, method="both"
135)
137# two different signatures of argsort, this second validation for when the
138# `kind` param is supported
139ARGSORT_DEFAULTS_KIND: dict[str, int | None] = {}
140ARGSORT_DEFAULTS_KIND["axis"] = -1
141ARGSORT_DEFAULTS_KIND["order"] = None
142validate_argsort_kind = CompatValidator(
143 ARGSORT_DEFAULTS_KIND, fname="argsort", max_fname_arg_count=0, method="both"
144)
147def validate_argsort_with_ascending(ascending: bool | int | None, args, kwargs) -> bool:
148 """
149 If 'Categorical.argsort' is called via the 'numpy' library, the first
150 parameter in its signature is 'axis', which takes either an integer or
151 'None', so check if the 'ascending' parameter has either integer type or is
152 None, since 'ascending' itself should be a boolean
153 """
154 if is_integer(ascending) or ascending is None:
155 args = (ascending,) + args
156 ascending = True
158 validate_argsort_kind(args, kwargs, max_fname_arg_count=3)
159 # error: Incompatible return value type (got "int", expected "bool")
160 return ascending # type: ignore[return-value]
163CLIP_DEFAULTS: dict[str, Any] = {"out": None}
164validate_clip = CompatValidator(
165 CLIP_DEFAULTS, fname="clip", method="both", max_fname_arg_count=3
166)
169@overload
170def validate_clip_with_axis(axis: ndarray, args, kwargs) -> None:
171 ...
174@overload
175def validate_clip_with_axis(axis: AxisNoneT, args, kwargs) -> AxisNoneT:
176 ...
179def validate_clip_with_axis(
180 axis: ndarray | AxisNoneT, args, kwargs
181) -> AxisNoneT | None:
182 """
183 If 'NDFrame.clip' is called via the numpy library, the third parameter in
184 its signature is 'out', which can takes an ndarray, so check if the 'axis'
185 parameter is an instance of ndarray, since 'axis' itself should either be
186 an integer or None
187 """
188 if isinstance(axis, ndarray):
189 args = (axis,) + args
190 # error: Incompatible types in assignment (expression has type "None",
191 # variable has type "Union[ndarray[Any, Any], str, int]")
192 axis = None # type: ignore[assignment]
194 validate_clip(args, kwargs)
195 # error: Incompatible return value type (got "Union[ndarray[Any, Any],
196 # str, int]", expected "Union[str, int, None]")
197 return axis # type: ignore[return-value]
200CUM_FUNC_DEFAULTS: dict[str, Any] = {}
201CUM_FUNC_DEFAULTS["dtype"] = None
202CUM_FUNC_DEFAULTS["out"] = None
203validate_cum_func = CompatValidator(
204 CUM_FUNC_DEFAULTS, method="both", max_fname_arg_count=1
205)
206validate_cumsum = CompatValidator(
207 CUM_FUNC_DEFAULTS, fname="cumsum", method="both", max_fname_arg_count=1
208)
211def validate_cum_func_with_skipna(skipna, args, kwargs, name) -> bool:
212 """
213 If this function is called via the 'numpy' library, the third parameter in
214 its signature is 'dtype', which takes either a 'numpy' dtype or 'None', so
215 check if the 'skipna' parameter is a boolean or not
216 """
217 if not is_bool(skipna):
218 args = (skipna,) + args
219 skipna = True
221 validate_cum_func(args, kwargs, fname=name)
222 return skipna
225ALLANY_DEFAULTS: dict[str, bool | None] = {}
226ALLANY_DEFAULTS["dtype"] = None
227ALLANY_DEFAULTS["out"] = None
228ALLANY_DEFAULTS["keepdims"] = False
229ALLANY_DEFAULTS["axis"] = None
230validate_all = CompatValidator(
231 ALLANY_DEFAULTS, fname="all", method="both", max_fname_arg_count=1
232)
233validate_any = CompatValidator(
234 ALLANY_DEFAULTS, fname="any", method="both", max_fname_arg_count=1
235)
237LOGICAL_FUNC_DEFAULTS = {"out": None, "keepdims": False}
238validate_logical_func = CompatValidator(LOGICAL_FUNC_DEFAULTS, method="kwargs")
240MINMAX_DEFAULTS = {"axis": None, "out": None, "keepdims": False}
241validate_min = CompatValidator(
242 MINMAX_DEFAULTS, fname="min", method="both", max_fname_arg_count=1
243)
244validate_max = CompatValidator(
245 MINMAX_DEFAULTS, fname="max", method="both", max_fname_arg_count=1
246)
248RESHAPE_DEFAULTS: dict[str, str] = {"order": "C"}
249validate_reshape = CompatValidator(
250 RESHAPE_DEFAULTS, fname="reshape", method="both", max_fname_arg_count=1
251)
253REPEAT_DEFAULTS: dict[str, Any] = {"axis": None}
254validate_repeat = CompatValidator(
255 REPEAT_DEFAULTS, fname="repeat", method="both", max_fname_arg_count=1
256)
258ROUND_DEFAULTS: dict[str, Any] = {"out": None}
259validate_round = CompatValidator(
260 ROUND_DEFAULTS, fname="round", method="both", max_fname_arg_count=1
261)
263SORT_DEFAULTS: dict[str, int | str | None] = {}
264SORT_DEFAULTS["axis"] = -1
265SORT_DEFAULTS["kind"] = "quicksort"
266SORT_DEFAULTS["order"] = None
267validate_sort = CompatValidator(SORT_DEFAULTS, fname="sort", method="kwargs")
269STAT_FUNC_DEFAULTS: dict[str, Any | None] = {}
270STAT_FUNC_DEFAULTS["dtype"] = None
271STAT_FUNC_DEFAULTS["out"] = None
273SUM_DEFAULTS = STAT_FUNC_DEFAULTS.copy()
274SUM_DEFAULTS["axis"] = None
275SUM_DEFAULTS["keepdims"] = False
276SUM_DEFAULTS["initial"] = None
278PROD_DEFAULTS = STAT_FUNC_DEFAULTS.copy()
279PROD_DEFAULTS["axis"] = None
280PROD_DEFAULTS["keepdims"] = False
281PROD_DEFAULTS["initial"] = None
283MEDIAN_DEFAULTS = STAT_FUNC_DEFAULTS.copy()
284MEDIAN_DEFAULTS["overwrite_input"] = False
285MEDIAN_DEFAULTS["keepdims"] = False
287STAT_FUNC_DEFAULTS["keepdims"] = False
289validate_stat_func = CompatValidator(STAT_FUNC_DEFAULTS, method="kwargs")
290validate_sum = CompatValidator(
291 SUM_DEFAULTS, fname="sum", method="both", max_fname_arg_count=1
292)
293validate_prod = CompatValidator(
294 PROD_DEFAULTS, fname="prod", method="both", max_fname_arg_count=1
295)
296validate_mean = CompatValidator(
297 STAT_FUNC_DEFAULTS, fname="mean", method="both", max_fname_arg_count=1
298)
299validate_median = CompatValidator(
300 MEDIAN_DEFAULTS, fname="median", method="both", max_fname_arg_count=1
301)
303STAT_DDOF_FUNC_DEFAULTS: dict[str, bool | None] = {}
304STAT_DDOF_FUNC_DEFAULTS["dtype"] = None
305STAT_DDOF_FUNC_DEFAULTS["out"] = None
306STAT_DDOF_FUNC_DEFAULTS["keepdims"] = False
307validate_stat_ddof_func = CompatValidator(STAT_DDOF_FUNC_DEFAULTS, method="kwargs")
309TAKE_DEFAULTS: dict[str, str | None] = {}
310TAKE_DEFAULTS["out"] = None
311TAKE_DEFAULTS["mode"] = "raise"
312validate_take = CompatValidator(TAKE_DEFAULTS, fname="take", method="kwargs")
315def validate_take_with_convert(convert: ndarray | bool | None, args, kwargs) -> bool:
316 """
317 If this function is called via the 'numpy' library, the third parameter in
318 its signature is 'axis', which takes either an ndarray or 'None', so check
319 if the 'convert' parameter is either an instance of ndarray or is None
320 """
321 if isinstance(convert, ndarray) or convert is None:
322 args = (convert,) + args
323 convert = True
325 validate_take(args, kwargs, max_fname_arg_count=3, method="both")
326 return convert
329TRANSPOSE_DEFAULTS = {"axes": None}
330validate_transpose = CompatValidator(
331 TRANSPOSE_DEFAULTS, fname="transpose", method="both", max_fname_arg_count=0
332)
335def validate_window_func(name, args, kwargs) -> None:
336 numpy_args = ("axis", "dtype", "out")
337 msg = (
338 f"numpy operations are not valid with window objects. "
339 f"Use .{name}() directly instead "
340 )
342 if len(args) > 0:
343 raise UnsupportedFunctionCall(msg)
345 for arg in numpy_args:
346 if arg in kwargs:
347 raise UnsupportedFunctionCall(msg)
350def validate_rolling_func(name, args, kwargs) -> None:
351 numpy_args = ("axis", "dtype", "out")
352 msg = (
353 f"numpy operations are not valid with window objects. "
354 f"Use .rolling(...).{name}() instead "
355 )
357 if len(args) > 0:
358 raise UnsupportedFunctionCall(msg)
360 for arg in numpy_args:
361 if arg in kwargs:
362 raise UnsupportedFunctionCall(msg)
365def validate_expanding_func(name, args, kwargs) -> None:
366 numpy_args = ("axis", "dtype", "out")
367 msg = (
368 f"numpy operations are not valid with window objects. "
369 f"Use .expanding(...).{name}() instead "
370 )
372 if len(args) > 0:
373 raise UnsupportedFunctionCall(msg)
375 for arg in numpy_args:
376 if arg in kwargs:
377 raise UnsupportedFunctionCall(msg)
380def validate_groupby_func(name, args, kwargs, allowed=None) -> None:
381 """
382 'args' and 'kwargs' should be empty, except for allowed kwargs because all
383 of their necessary parameters are explicitly listed in the function
384 signature
385 """
386 if allowed is None:
387 allowed = []
389 kwargs = set(kwargs) - set(allowed)
391 if len(args) + len(kwargs) > 0:
392 raise UnsupportedFunctionCall(
393 "numpy operations are not valid with groupby. "
394 f"Use .groupby(...).{name}() instead"
395 )
398RESAMPLER_NUMPY_OPS = ("min", "max", "sum", "prod", "mean", "std", "var")
401def validate_resampler_func(method: str, args, kwargs) -> None:
402 """
403 'args' and 'kwargs' should be empty because all of their necessary
404 parameters are explicitly listed in the function signature
405 """
406 if len(args) + len(kwargs) > 0:
407 if method in RESAMPLER_NUMPY_OPS:
408 raise UnsupportedFunctionCall(
409 "numpy operations are not valid with resample. "
410 f"Use .resample(...).{method}() instead"
411 )
412 else:
413 raise TypeError("too many arguments passed in")
416def validate_minmax_axis(axis: int | None, ndim: int = 1) -> None:
417 """
418 Ensure that the axis argument passed to min, max, argmin, or argmax is zero
419 or None, as otherwise it will be incorrectly ignored.
421 Parameters
422 ----------
423 axis : int or None
424 ndim : int, default 1
426 Raises
427 ------
428 ValueError
429 """
430 if axis is None:
431 return
432 if axis >= ndim or (axis < 0 and ndim + axis < 0):
433 raise ValueError(f"`axis` must be fewer than the number of dimensions ({ndim})")