Repository: pandas-dev/pandas

Issue:
BUG: query with local strings gives KeyError
From SO question (http://stackoverflow.com/questions/23974664/unable-to-query-a-local-variable-in-pandas-0-14-0), referencing a local variable gives an error when this is a string (workaround seems to be to wrap it in a list):

```
In [39]: fills = pd.DataFrame({'Symbol':['BUD US', 'BUD US', 'IBM US', 'IBM US'], 'Price':[109.70, 109.72, 183.30, 183.35]})

In [40]: fills
Out[40]: 
    Price  Symbol
0  109.70  BUD US
1  109.72  BUD US
2  183.30  IBM US
3  183.35  IBM US

In [41]: my_symbol = ['BUD US']

In [42]: fills.query('Symbol==@my_symbol')
Out[42]: 
    Price  Symbol
0  109.70  BUD US
1  109.72  BUD US

In [43]: my_symbol = 'BUD US'

In [44]: fills.query('Symbol==@my_symbol')
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-44-c16846018a13> in <module>()
----> 1 fills.query('Symbol==@my_symbol')

...

/home/joris/scipy/pandas/pandas/computation/expr.pyc in _rewrite_membership_op(self, node, left, right)
    341             # of one string, kind of a hack
    342             if right_str:
--> 343                 self.env.remove_tmp(right.name)
    344                 name = self.env.add_tmp([right.value])
    345                 right = self.term_type(name, self.env)

/home/joris/scipy/pandas/pandas/computation/scope.pyc in remove_tmp(self, name)
    287             The name of a temporary to be removed
    288         """
--> 289         del self.temps[name]
    290 
    291     @property

KeyError: '__pd_eval_local_my_symbol'
> /home/joris/scipy/pandas/pandas/computation/scope.py(289)remove_tmp()
    288         """
--> 289         del self.temps[name]
    290 
```

@cpcloud 



Discussion:
Darn I totally thought that I had written a test for this. Guess not


Resolving patch:
diff --git a/pandas/computation/expr.py b/pandas/computation/expr.py
--- a/pandas/computation/expr.py
+++ b/pandas/computation/expr.py
@@ -340,12 +340,10 @@ def _rewrite_membership_op(self, node, left, right):
             # pop the string variable out of locals and replace it with a list
             # of one string, kind of a hack
             if right_str:
-                self.env.remove_tmp(right.name)
                 name = self.env.add_tmp([right.value])
                 right = self.term_type(name, self.env)
 
             if left_str:
-                self.env.remove_tmp(left.name)
                 name = self.env.add_tmp([left.value])
                 left = self.term_type(name, self.env)
 
diff --git a/pandas/computation/scope.py b/pandas/computation/scope.py
--- a/pandas/computation/scope.py
+++ b/pandas/computation/scope.py
@@ -278,16 +278,6 @@ def add_tmp(self, value):
         # only increment if the variable gets put in the scope
         return name
 
-    def remove_tmp(self, name):
-        """Remove a temporary variable from this scope
-
-        Parameters
-        ----------
-        name : str
-            The name of a temporary to be removed
-        """
-        del self.temps[name]
-
     @property
     def ntemps(self):
         """The number of temporary variables in this scope"""


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -13685,6 +13685,18 @@ def test_query_single_element_booleans(self):
         for parser, engine in product(PARSERS, ENGINES):
             yield self.check_query_single_element_booleans, parser, engine
 
+    def check_query_string_scalar_variable(self, parser, engine):
+        tm.skip_if_no_ne(engine)
+        df = pd.DataFrame({'Symbol': ['BUD US', 'BUD US', 'IBM US', 'IBM US'],
+                           'Price': [109.70, 109.72, 183.30, 183.35]})
+        e = df[df.Symbol == 'BUD US']
+        symb = 'BUD US'
+        r = df.query('Symbol == @symb', parser=parser, engine=engine)
+        tm.assert_frame_equal(e, r)
+
+    def test_query_string_scalar_variable(self):
+        for parser, engine in product(['pandas'], ENGINES):
+            yield self.check_query_string_scalar_variable, parser, engine
 
 class TestDataFrameEvalNumExprPandas(tm.TestCase):