Closed
Description
Describe the bug
- I have checked that this issue has not already been reported.
- I have confirmed this bug exists on the latest version of pandera.
- (optional) I have confirmed this bug exists on the main branch of pandera.
Bug introduced in check_input
in 0.22.0 when both positional and keyword arguments are passed to the decorated function.
Code Sample, a copy-pastable example
import pandas as pd
import pandera as pa
from pandera.typing import DataFrame
class Iris(pa.DataFrameModel):
sepal_length: float
sepal_width: float
petal_length: float
petal_width: float
species: str
@pa.check_input(
Iris.to_schema()
)
def do_something(
data: DataFrame[Iris],
*,
progress: bool = False
):
return ...
if __name__ == "__main__":
do_something(
pd.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/refs/heads/master/iris.csv"),
progress=False,
)
In 0.21.1
, the code works as expected. In 0.22.0
the following exception gets raised:
Traceback (most recent call last):
File "/tmp/tmp.qLV4KDw4CH/test.py", line 26, in <module>
do_something(
~~~~~~~~~~~~^
pd.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/refs/heads/master/iris.csv"),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
progress=False,
^^^^^^^^^^^^^^^
)
^
File "/home/ashpy/lib/unionai-oss/pandera/pandera/decorators.py", line 268, in _wrapper
kwargs[args_names[0]], *validate_args
~~~~~~^^^^^^^^^^^^^^^
KeyError: 'data'
Expected behavior
The code works just as well in 0.22.0
as it did in 0.21.1
.
Additional context
I tracked the issue down to this commit: e117d2e.
My guess is that the two conditionals should be inverted: first check if there are positional arguments, then check if there are keyword args, not the other way around:
diff --git a/pandera/decorators.py b/pandera/decorators.py
index f4afee8..d166a53 100644
--- a/pandera/decorators.py
+++ b/pandera/decorators.py
@@ -258,23 +258,6 @@ def check_input(
pos_args[obj_getter], *validate_args
)
args = list(pos_args.values())
- elif obj_getter is None and kwargs:
- # get the first key in the same order specified in the
- # function argument.
- args_names = _get_fn_argnames(wrapped)
-
- try:
- kwargs[args_names[0]] = schema.validate(
- kwargs[args_names[0]], *validate_args
- )
- except errors.SchemaError as e:
- _handle_schema_error(
- "check_input",
- wrapped,
- schema,
- kwargs[args_names[0]],
- e,
- )
elif obj_getter is None and args:
try:
_fn = (
@@ -294,6 +277,23 @@ def check_input(
_handle_schema_error(
"check_input", wrapped, schema, args[0], e
)
+ elif obj_getter is None and kwargs:
+ # get the first key in the same order specified in the
+ # function argument.
+ args_names = _get_fn_argnames(wrapped)
+
+ try:
+ kwargs[args_names[0]] = schema.validate(
+ kwargs[args_names[0]], *validate_args
+ )
+ except errors.SchemaError as e:
+ _handle_schema_error(
+ "check_input",
+ wrapped,
+ schema,
+ kwargs[args_names[0]],
+ e,
+ )
else:
raise TypeError(
f"obj_getter is unrecognized type: {type(obj_getter)}"