Skip to content

Commit 3c9fec3

Browse files
stephenrauchjreback
authored andcommitted
BUG: Multiline Eval broken for local variables after first line
Also fixes the code which attempted to ignore any blank lines in the multiline expression. closes pandas-dev#15342 Author: Stephen Rauch <[email protected]> Closes pandas-dev#15343 from stephenrauch/multi-line-eval-with-local and squashes the following commits: fe67ede [Stephen Rauch] BUG: GH15342 - Multiline Eval broken for local variables after first line
1 parent c1bd201 commit 3c9fec3

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -517,3 +517,4 @@ Bug Fixes
517517

518518
- Bug in ``DataFrame.boxplot`` where ``fontsize`` was not applied to the tick labels on both axes (:issue:`15108`)
519519
- Bug in ``Series.replace`` and ``DataFrame.replace`` which failed on empty replacement dicts (:issue:`15289`)
520+
- Bug in ``.eval()`` which caused multiline evals to fail with local variables not on the first line (:issue:`15342`)

pandas/computation/eval.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ def eval(expr, parser='pandas', engine=None, truediv=True,
236236
first_expr = True
237237
if isinstance(expr, string_types):
238238
_check_expression(expr)
239-
exprs = [e for e in expr.splitlines() if e != '']
239+
exprs = [e.strip() for e in expr.splitlines() if e.strip() != '']
240240
else:
241241
exprs = [expr]
242242
multi_line = len(exprs) > 1
@@ -254,8 +254,7 @@ def eval(expr, parser='pandas', engine=None, truediv=True,
254254
_check_for_locals(expr, level, parser)
255255

256256
# get our (possibly passed-in) scope
257-
level += 1
258-
env = _ensure_scope(level, global_dict=global_dict,
257+
env = _ensure_scope(level + 1, global_dict=global_dict,
259258
local_dict=local_dict, resolvers=resolvers,
260259
target=target)
261260

pandas/computation/tests/test_eval.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -1274,7 +1274,6 @@ def test_assignment_fails(self):
12741274
local_dict={'df': df, 'df2': df2})
12751275

12761276
def test_assignment_column(self):
1277-
tm.skip_if_no_ne('numexpr')
12781277
df = DataFrame(np.random.randn(5, 2), columns=list('ab'))
12791278
orig_df = df.copy()
12801279

@@ -1346,7 +1345,6 @@ def test_column_in(self):
13461345

13471346
def assignment_not_inplace(self):
13481347
# GH 9297
1349-
tm.skip_if_no_ne('numexpr')
13501348
df = DataFrame(np.random.randn(5, 2), columns=list('ab'))
13511349

13521350
actual = df.eval('c = a + b', inplace=False)
@@ -1365,7 +1363,6 @@ def assignment_not_inplace(self):
13651363

13661364
def test_multi_line_expression(self):
13671365
# GH 11149
1368-
tm.skip_if_no_ne('numexpr')
13691366
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
13701367
expected = df.copy()
13711368

@@ -1393,7 +1390,6 @@ def test_multi_line_expression(self):
13931390

13941391
def test_multi_line_expression_not_inplace(self):
13951392
# GH 11149
1396-
tm.skip_if_no_ne('numexpr')
13971393
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
13981394
expected = df.copy()
13991395

@@ -1411,6 +1407,21 @@ def test_multi_line_expression_not_inplace(self):
14111407
e = a + 2""", inplace=False)
14121408
assert_frame_equal(expected, df)
14131409

1410+
def test_multi_line_expression_local_variable(self):
1411+
# GH 15342
1412+
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
1413+
expected = df.copy()
1414+
1415+
local_var = 7
1416+
expected['c'] = expected['a'] * local_var
1417+
expected['d'] = expected['c'] + local_var
1418+
ans = df.eval("""
1419+
c = a * @local_var
1420+
d = c + @local_var
1421+
""", inplace=True)
1422+
assert_frame_equal(expected, df)
1423+
self.assertIsNone(ans)
1424+
14141425
def test_assignment_in_query(self):
14151426
# GH 8664
14161427
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})

0 commit comments

Comments
 (0)