diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 09e246c6ed971..84f9fd8906dbf 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -298,7 +298,6 @@ Bug Fixes ~~~~~~~~~ - Categorical ^^^^^^^^^^^ @@ -380,6 +379,7 @@ Indexing - Bug in which :meth:`DataFrame.append` produced an erroneous warning indicating that a ``KeyError`` will be thrown in the future when the data to be appended contains new columns (:issue:`22252`). - Bug in which :meth:`DataFrame.to_csv` caused a segfault for a reindexed data frame, when the indices were single-level :class:`MultiIndex` (:issue:`26303`). - Fixed bug where assigning a :class:`arrays.PandasArray` to a :class:`pandas.core.frame.DataFrame` would raise error (:issue:`26390`) +- Allow keyword arguments for callable local reference used in the :method:`DataFrame.query` string (:issue:`26426`) Missing diff --git a/pandas/core/computation/expr.py b/pandas/core/computation/expr.py index 628a2244d0a6f..32bd34c4db7d7 100644 --- a/pandas/core/computation/expr.py +++ b/pandas/core/computation/expr.py @@ -633,9 +633,7 @@ def visit_Call(self, node, side=None, **kwargs): "'{func}'".format(func=node.func.id)) if key.arg: - # TODO: bug? - kwargs.append(ast.keyword( - keyword.arg, self.visit(keyword.value))) # noqa + kwargs[key.arg] = self.visit(key.value).value return self.const_type(res(*new_args, **kwargs), self.env) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index 69c05ccfe9818..ca78e2e40ec74 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -1345,6 +1345,40 @@ def test_multi_line_expression_local_variable(self): assert_frame_equal(expected, df) assert ans is None + def test_multi_line_expression_callable_local_variable(self): + # 26426 + df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) + + def local_func(a, b): + return b + + expected = df.copy() + expected['c'] = expected['a'] * local_func(1, 7) + expected['d'] = expected['c'] + local_func(1, 7) + ans = df.eval(""" + c = a * @local_func(1, 7) + d = c + @local_func(1, 7) + """, inplace=True) + assert_frame_equal(expected, df) + assert ans is None + + def test_multi_line_expression_callable_local_variable_with_kwargs(self): + # 26426 + df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) + + def local_func(a, b): + return b + + expected = df.copy() + expected['c'] = expected['a'] * local_func(b=7, a=1) + expected['d'] = expected['c'] + local_func(b=7, a=1) + ans = df.eval(""" + c = a * @local_func(b=7, a=1) + d = c + @local_func(b=7, a=1) + """, inplace=True) + assert_frame_equal(expected, df) + assert ans is None + def test_assignment_in_query(self): # GH 8664 df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})