From ae69462463c9afe4c6c920391020a3f4cbbddd3f Mon Sep 17 00:00:00 2001 From: Phillip Cloud Date: Thu, 20 Feb 2014 23:57:59 -0500 Subject: [PATCH] BUG: correctly tokenize local variable references --- pandas/computation/expr.py | 8 +++++++- pandas/tests/test_frame.py | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pandas/computation/expr.py b/pandas/computation/expr.py index 454a28fd82362..0f2b3e643d83c 100644 --- a/pandas/computation/expr.py +++ b/pandas/computation/expr.py @@ -57,7 +57,13 @@ def _replace_booleans(source): def _replace_locals(source, local_symbol='@'): """Replace local variables with a syntactically valid name.""" - return source.replace(local_symbol, _LOCAL_TAG) + res = [] + for toknum, tokval, _, _, _ in tokenize_string(source): + if toknum == tokenize.OP and tokval == local_symbol: + res.append((tokenize.OP, _LOCAL_TAG)) + else: + res.append((toknum, tokval)) + return tokenize.untokenize(res) def _preparse(source): diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 88cf3179b33f2..8d15a06ad7baf 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -12774,6 +12774,14 @@ def test_local_variable_with_in(self): result = df.query('@b - 1 in a', engine=engine, parser=parser) tm.assert_frame_equal(expected, result) + def test_at_inside_string(self): + engine, parser = self.engine, self.parser + skip_if_no_pandas_parser(parser) + c = 1 + df = DataFrame({'a': ['a', 'a', 'b', 'b', '@c', '@c']}) + result = df.query('a == "@c"', engine=engine, parser=parser) + expected = df[df.a == "@c"] + tm.assert_frame_equal(result, expected) class TestDataFrameQueryNumExprPython(TestDataFrameQueryNumExprPandas):