diff --git a/doc/source/whatsnew/v1.5.2.rst b/doc/source/whatsnew/v1.5.2.rst index 6397016d827f2..23f8fc593c700 100644 --- a/doc/source/whatsnew/v1.5.2.rst +++ b/doc/source/whatsnew/v1.5.2.rst @@ -13,6 +13,7 @@ including other versions of pandas. Fixed regressions ~~~~~~~~~~~~~~~~~ +- Fixed regression in :meth:`DataFrame.query` raising ``UndefinedVariableError`` when calling it with class as a name (:issue:`48694`) - Fixed regression in :meth:`MultiIndex.join` for extension array dtypes (:issue:`49277`) - Fixed regression in :meth:`Series.replace` raising ``RecursionError`` with numeric dtype and when specifying ``value=None`` (:issue:`45725`) - Fixed regression in arithmetic operations for :class:`DataFrame` with :class:`MultiIndex` columns with different dtypes (:issue:`49769`) diff --git a/pandas/core/computation/ops.py b/pandas/core/computation/ops.py index f629538281d65..96e3b1e8f20b1 100644 --- a/pandas/core/computation/ops.py +++ b/pandas/core/computation/ops.py @@ -29,6 +29,7 @@ result_type_many, ) from pandas.core.computation.scope import DEFAULT_GLOBALS +from pandas.core.series import Series from pandas.io.formats.printing import ( pprint_thing, @@ -102,10 +103,9 @@ def evaluate(self, *args, **kwargs) -> Term: def _resolve_name(self): local_name = str(self.local_name) is_local = self.is_local - if local_name in self.env.scope and isinstance( - self.env.scope[local_name], type - ): - is_local = False + check = self.env.scope.get("column") == local_name + if not isinstance(check, Series) and check: + is_local = not is_local res = self.env.resolve(local_name, is_local=is_local) self.update(res) diff --git a/pandas/core/computation/pytables.py b/pandas/core/computation/pytables.py index 4055be3f943fa..43dcb931e5225 100644 --- a/pandas/core/computation/pytables.py +++ b/pandas/core/computation/pytables.py @@ -609,20 +609,21 @@ def __repr__(self) -> str: def evaluate(self): """create and return the numexpr condition and filter""" - try: - self.condition = self.terms.prune(ConditionBinOp) - except AttributeError as err: - raise ValueError( - f"cannot process expression [{self.expr}], [{self}] " - "is not a valid condition" - ) from err - try: - self.filter = self.terms.prune(FilterBinOp) - except AttributeError as err: - raise ValueError( - f"cannot process expression [{self.expr}], [{self}] " - "is not a valid filter" - ) from err + if self.terms is not None: + try: + self.condition = self.terms.prune(ConditionBinOp) + except AttributeError as err: + raise ValueError( + f"cannot process expression [{self.expr}], [{self}] " + "is not a valid condition" + ) from err + try: + self.filter = self.terms.prune(FilterBinOp) + except AttributeError as err: + raise ValueError( + f"cannot process expression [{self.expr}], [{self}] " + "is not a valid filter" + ) from err return self.condition, self.filter diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index 571bf92870ab7..127586993d6da 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -1846,7 +1846,7 @@ def test_negate_lt_eq_le(engine, parser): ) def test_eval_no_support_column_name(request, column): # GH 44603 - if column in ["True", "False", "inf", "Inf"]: + if column in ["True", "False"]: request.node.add_marker( pytest.mark.xfail( raises=KeyError, @@ -1861,6 +1861,17 @@ def test_eval_no_support_column_name(request, column): tm.assert_frame_equal(result, expected) +def test_classname_frame_query(): + # GH 48694 + class A: + a = 1 + + df1 = DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]}) + df_test = DataFrame({"x": [1], "y": [4]}) + tm.assert_frame_equal(df_test, df1.query(f"x=={A.a}")) + tm.assert_frame_equal(df_test, df1.query("x==@A.a")) + + @td.skip_array_manager_not_yet_implemented def test_set_inplace(using_copy_on_write): # https://github.com/pandas-dev/pandas/issues/47449