From 3e8ff19d7dee5b96450805eb0e86ec97d258feea Mon Sep 17 00:00:00 2001 From: Stephen Voland Date: Sat, 10 Mar 2018 12:54:45 -0500 Subject: [PATCH 1/5] DOC: Improved the docstring of DataFrame.eval(). --- pandas/core/frame.py | 67 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index a66d00fff9714..15eea7a6d5de8 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2375,20 +2375,23 @@ def query(self, expr, inplace=False, **kwargs): return new_data def eval(self, expr, inplace=False, **kwargs): - """Evaluate an expression in the context of the calling DataFrame - instance. + """ + Evaluate expression in the context of the calling DataFrame instance. + + Evaluates a string describing operations on dataframe columns. This + allows `eval` to run arbitrary code, but remember to sanitize your + inputs. Parameters ---------- - expr : string + expr : str The expression string to evaluate. inplace : bool, default False If the expression contains an assignment, whether to perform the operation inplace and mutate the existing DataFrame. Otherwise, a new DataFrame is returned. - .. versionadded:: 0.18.0 - + .. versionadded:: 0.18.0. kwargs : dict See the documentation for :func:`~pandas.eval` for complete details on the keyword arguments accepted by @@ -2396,13 +2399,17 @@ def eval(self, expr, inplace=False, **kwargs): Returns ------- - ret : ndarray, scalar, or pandas object + ndarray, scalar, or pandas object + The result of the evaluation. See Also -------- - pandas.DataFrame.query - pandas.DataFrame.assign - pandas.eval + pandas.DataFrame.query : Evaluates a boolean expression to query the + columns of a frame. + pandas.DataFrame.assign : Can evaluate an expression or function to + create new values for a column. + pandas.eval : Evaluate a Python expression as a string using various + backends. Notes ----- @@ -2412,11 +2419,43 @@ def eval(self, expr, inplace=False, **kwargs): Examples -------- - >>> from numpy.random import randn - >>> from pandas import DataFrame - >>> df = pd.DataFrame(randn(10, 2), columns=list('ab')) - >>> df.eval('a + b') - >>> df.eval('c = a + b') + >>> df = pd.DataFrame({'A': range(1, 6), 'B': range(10, 0, -2)}) + >>> df + A B + 0 1 10 + 1 2 8 + 2 3 6 + 3 4 4 + 4 5 2 + >>> df.eval('A + B') + 0 11 + 1 10 + 2 9 + 3 8 + 4 7 + dtype: int64 + >>> df.eval('C = A + B') + A B C + 0 1 10 11 + 1 2 8 10 + 2 3 6 9 + 3 4 4 8 + 4 5 2 7 + >>> df + A B + 0 1 10 + 1 2 8 + 2 3 6 + 3 4 4 + 4 5 2 + >>> df.eval('C = A + B', inplace=True) + >>> df + A B C + 0 1 10 11 + 1 2 8 10 + 2 3 6 9 + 3 4 4 8 + 4 5 2 7 """ from pandas.core.computation.eval import eval as _eval From c86dc091b0af45dc213a1d539481ecf1b80dd284 Mon Sep 17 00:00:00 2001 From: Stephen Voland Date: Sat, 10 Mar 2018 14:02:27 -0500 Subject: [PATCH 2/5] DOC: update the DataFrame.eval() docstring --- pandas/core/frame.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 15eea7a6d5de8..3d1113182fc74 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2378,9 +2378,12 @@ def eval(self, expr, inplace=False, **kwargs): """ Evaluate expression in the context of the calling DataFrame instance. - Evaluates a string describing operations on dataframe columns. This - allows `eval` to run arbitrary code, but remember to sanitize your - inputs. + Evaluates a string describing operations on DataFrame columns (only, + not specific rows or elements). This allows `eval` to run arbitrary + code, but remember to sanitize your inputs. + + This function calls `pandas.eval()` and is likely to be slower than + it. Parameters ---------- @@ -2434,6 +2437,10 @@ def eval(self, expr, inplace=False, **kwargs): 3 8 4 7 dtype: int64 + + Assignment is allowed and by default the original DataFrame is not + modified. + >>> df.eval('C = A + B') A B C 0 1 10 11 @@ -2448,6 +2455,9 @@ def eval(self, expr, inplace=False, **kwargs): 2 3 6 3 4 4 4 5 2 + + Use inplace=True to modify the original DataFrame. + >>> df.eval('C = A + B', inplace=True) >>> df A B C From b67e76cabaf6d9e8864f8d99cd3446c65825c5f8 Mon Sep 17 00:00:00 2001 From: Stephen Voland Date: Sun, 11 Mar 2018 22:30:28 -0400 Subject: [PATCH 3/5] DOC: update the DataFrame.eval() docstring --- pandas/core/frame.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 3d1113182fc74..87017205b66b7 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2376,14 +2376,11 @@ def query(self, expr, inplace=False, **kwargs): def eval(self, expr, inplace=False, **kwargs): """ - Evaluate expression in the context of the calling DataFrame instance. + Evaluate a string describing operations on DataFrame columns. - Evaluates a string describing operations on DataFrame columns (only, - not specific rows or elements). This allows `eval` to run arbitrary - code, but remember to sanitize your inputs. - - This function calls `pandas.eval()` and is likely to be slower than - it. + Operates on columns only, not specific rows or elements. This allows + `eval` to run arbitrary code, which can make you vulnerable to code + injection if you pass user input to this function. Parameters ---------- @@ -2420,6 +2417,9 @@ def eval(self, expr, inplace=False, **kwargs): For detailed examples see :ref:`enhancing performance with eval `. + This function calls `pandas.eval()` and is likely to be slower than + it. + Examples -------- >>> df = pd.DataFrame({'A': range(1, 6), 'B': range(10, 0, -2)}) From f45aebe03a321fb1180ba727eb72eabaca986fbe Mon Sep 17 00:00:00 2001 From: Stephen Voland Date: Mon, 12 Mar 2018 17:45:10 -0400 Subject: [PATCH 4/5] DOC: update the eval docstring. --- pandas/core/frame.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 1e4417f290c61..3a9ed96ec063a 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2491,10 +2491,10 @@ def eval(self, expr, inplace=False, **kwargs): See Also -------- - pandas.DataFrame.query : Evaluates a boolean expression to query the - columns of a frame. - pandas.DataFrame.assign : Can evaluate an expression or function to - create new values for a column. + DataFrame.query : Evaluates a boolean expression to query the columns + of a frame. + DataFrame.assign : Can evaluate an expression or function to create new + values for a column. pandas.eval : Evaluate a Python expression as a string using various backends. @@ -2504,9 +2504,6 @@ def eval(self, expr, inplace=False, **kwargs): For detailed examples see :ref:`enhancing performance with eval `. - This function calls `pandas.eval()` and is likely to be slower than - it. - Examples -------- >>> df = pd.DataFrame({'A': range(1, 6), 'B': range(10, 0, -2)}) From b1301d8e47a5c7c7db291ded6aaa1dc79560a6c1 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 13 Mar 2018 09:26:07 -0500 Subject: [PATCH 5/5] Quote inplace --- pandas/core/frame.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 42bd66f73581e..c62ad1cbee5d7 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2550,7 +2550,7 @@ def eval(self, expr, inplace=False, **kwargs): 4 7 dtype: int64 - Assignment is allowed and by default the original DataFrame is not + Assignment is allowed though by default the original DataFrame is not modified. >>> df.eval('C = A + B') @@ -2568,7 +2568,7 @@ def eval(self, expr, inplace=False, **kwargs): 3 4 4 4 5 2 - Use inplace=True to modify the original DataFrame. + Use ``inplace=True`` to modify the original DataFrame. >>> df.eval('C = A + B', inplace=True) >>> df