From 00b6ade8e3e2aafdccde139a14b32976d081698c Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Thu, 5 Mar 2020 14:04:17 +0200 Subject: [PATCH 1/7] Disallow .__call__() as workaround for non-named functions --- pandas/core/computation/expr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/computation/expr.py b/pandas/core/computation/expr.py index 6cd9a15b70d39..fcccc24ed7615 100644 --- a/pandas/core/computation/expr.py +++ b/pandas/core/computation/expr.py @@ -641,7 +641,7 @@ def visit_Attribute(self, node, **kwargs): def visit_Call(self, node, side=None, **kwargs): - if isinstance(node.func, ast.Attribute): + if isinstance(node.func, ast.Attribute) and node.func.attr != "__call__": res = self.visit_Attribute(node.func) elif not isinstance(node.func, ast.Name): raise TypeError("Only named functions are supported") From 0a12b491e20b0461ee02ce41799f732777715ba6 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 15 Mar 2020 10:11:06 +0200 Subject: [PATCH 2/7] Add test_call_non_named_expression --- pandas/tests/frame/test_query_eval.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pandas/tests/frame/test_query_eval.py b/pandas/tests/frame/test_query_eval.py index 1a07780462ea3..c970ee658407e 100644 --- a/pandas/tests/frame/test_query_eval.py +++ b/pandas/tests/frame/test_query_eval.py @@ -1181,3 +1181,17 @@ def test_failing_character_outside_range(self, df): def test_failing_hashtag(self, df): with pytest.raises(SyntaxError): df.query("`foo#bar` > 4") + + def test_call_non_named_expression(self, df): + def func(*_): + return 1 + + funcs = [func] + + df.eval("@func()") + + with pytest.raises(TypeError): + df.eval("@funcs[0]()") + + with pytest.raises(TypeError): + df.eval("@funcs[0].__call__()") From 19a08894207be3cfcb145e51d64db10d9383e37d Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 15 Mar 2020 10:36:44 +0200 Subject: [PATCH 3/7] No linting for unused variable funcs --- pandas/tests/frame/test_query_eval.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/frame/test_query_eval.py b/pandas/tests/frame/test_query_eval.py index c970ee658407e..9654653b975ca 100644 --- a/pandas/tests/frame/test_query_eval.py +++ b/pandas/tests/frame/test_query_eval.py @@ -1186,7 +1186,7 @@ def test_call_non_named_expression(self, df): def func(*_): return 1 - funcs = [func] + funcs = [func] # noqa df.eval("@func()") From 432fe6b4d6ce249f0ade1185ebc34325699195f6 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 10 May 2020 13:25:48 +0200 Subject: [PATCH 4/7] Assert exception message 'Only named functions are supported' --- pandas/tests/frame/test_query_eval.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/frame/test_query_eval.py b/pandas/tests/frame/test_query_eval.py index 9654653b975ca..b54104f32ce7f 100644 --- a/pandas/tests/frame/test_query_eval.py +++ b/pandas/tests/frame/test_query_eval.py @@ -1190,8 +1190,8 @@ def func(*_): df.eval("@func()") - with pytest.raises(TypeError): + with pytest.raises(TypeError, match="Only named functions are supported"): df.eval("@funcs[0]()") - with pytest.raises(TypeError): + with pytest.raises(TypeError, match="Only named functions are supported"): df.eval("@funcs[0].__call__()") From 3eabbe9dbf478504fc6a5c5e2a646c26758a90dc Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 10 May 2020 13:30:08 +0200 Subject: [PATCH 5/7] Add whatsnew note: Ensure only named functions can be used in eval() --- doc/source/whatsnew/v1.1.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 84ad478226175..58aab96aa95eb 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -784,6 +784,7 @@ Reshaping - Bug in :func:`concat` was not allowing for concatenation of ``DataFrame`` and ``Series`` with duplicate keys (:issue:`33654`) - Bug in :func:`cut` raised an error when non-unique labels (:issue:`33141`) - Bug in :meth:`DataFrame.replace` casts columns to ``object`` dtype if items in ``to_replace`` not in values (:issue:`32988`) +- Ensure only named functions can be used in :func:`eval()` (:issue:`32460`) Sparse From 2f7c3a12aae2c722cf4485bde9675bee2b874905 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 10 May 2020 19:51:16 +0200 Subject: [PATCH 6/7] Add explanation and issue link to test_call_non_named_expression --- pandas/tests/frame/test_query_eval.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pandas/tests/frame/test_query_eval.py b/pandas/tests/frame/test_query_eval.py index b54104f32ce7f..a130d87989372 100644 --- a/pandas/tests/frame/test_query_eval.py +++ b/pandas/tests/frame/test_query_eval.py @@ -1183,6 +1183,12 @@ def test_failing_hashtag(self, df): df.query("`foo#bar` > 4") def test_call_non_named_expression(self, df): + """ + Only attributes and variables ('named functions') can be called. + .__call__() is not an allowed attribute because that would allow calling anything. + https://github.com/pandas-dev/pandas/pull/32460 + """ + def func(*_): return 1 From b41c3971f56fe640b9946045a743e863c7273639 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Sun, 10 May 2020 19:52:08 +0200 Subject: [PATCH 7/7] Fix line length --- pandas/tests/frame/test_query_eval.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/frame/test_query_eval.py b/pandas/tests/frame/test_query_eval.py index a130d87989372..8612c05e6a996 100644 --- a/pandas/tests/frame/test_query_eval.py +++ b/pandas/tests/frame/test_query_eval.py @@ -1185,7 +1185,8 @@ def test_failing_hashtag(self, df): def test_call_non_named_expression(self, df): """ Only attributes and variables ('named functions') can be called. - .__call__() is not an allowed attribute because that would allow calling anything. + .__call__() is not an allowed attribute because that would allow + calling anything. https://github.com/pandas-dev/pandas/pull/32460 """