From 607529700a371b3ed2f67a942ef3fb491e6346ea Mon Sep 17 00:00:00 2001
From: Marco Gorelli <m.e.gorelli@gmail.com>
Date: Mon, 2 Nov 2020 14:14:18 +0000
Subject: [PATCH] refactor core/computation

---
 pandas/core/computation/align.py    | 12 +++++++-----
 pandas/core/computation/eval.py     | 11 +++++------
 pandas/core/computation/expr.py     | 17 ++++++++---------
 pandas/core/computation/pytables.py | 16 ++++++++--------
 pandas/core/computation/scope.py    |  3 +--
 5 files changed, 29 insertions(+), 30 deletions(-)

diff --git a/pandas/core/computation/align.py b/pandas/core/computation/align.py
index 82867cf9dcd29..8a8b0d564ea49 100644
--- a/pandas/core/computation/align.py
+++ b/pandas/core/computation/align.py
@@ -38,8 +38,7 @@ def _align_core_single_unary_op(
 def _zip_axes_from_type(
     typ: Type[FrameOrSeries], new_axes: Sequence[int]
 ) -> Dict[str, int]:
-    axes = {name: new_axes[i] for i, name in enumerate(typ._AXIS_ORDERS)}
-    return axes
+    return {name: new_axes[i] for i, name in enumerate(typ._AXIS_ORDERS)}
 
 
 def _any_pandas_objects(terms) -> bool:
@@ -186,8 +185,11 @@ def reconstruct_object(typ, obj, axes, dtype):
         # The condition is to distinguish 0-dim array (returned in case of
         # scalar) and 1 element array
         # e.g. np.array(0) and np.array([0])
-        if len(obj.shape) == 1 and len(obj) == 1:
-            if not isinstance(ret_value, np.ndarray):
-                ret_value = np.array([ret_value]).astype(res_t)
+        if (
+            len(obj.shape) == 1
+            and len(obj) == 1
+            and not isinstance(ret_value, np.ndarray)
+        ):
+            ret_value = np.array([ret_value]).astype(res_t)
 
     return ret_value
diff --git a/pandas/core/computation/eval.py b/pandas/core/computation/eval.py
index b77204861f0a4..12f16343362e2 100644
--- a/pandas/core/computation/eval.py
+++ b/pandas/core/computation/eval.py
@@ -52,12 +52,11 @@ def _check_engine(engine: Optional[str]) -> str:
     # TODO: validate this in a more general way (thinking of future engines
     # that won't necessarily be import-able)
     # Could potentially be done on engine instantiation
-    if engine == "numexpr":
-        if not NUMEXPR_INSTALLED:
-            raise ImportError(
-                "'numexpr' is not installed or an unsupported version. Cannot use "
-                "engine='numexpr' for query/eval if 'numexpr' is not installed"
-            )
+    if engine == "numexpr" and not NUMEXPR_INSTALLED:
+        raise ImportError(
+            "'numexpr' is not installed or an unsupported version. Cannot use "
+            "engine='numexpr' for query/eval if 'numexpr' is not installed"
+        )
 
     return engine
 
diff --git a/pandas/core/computation/expr.py b/pandas/core/computation/expr.py
index 8c56f02c8d3cc..c971551a7f400 100644
--- a/pandas/core/computation/expr.py
+++ b/pandas/core/computation/expr.py
@@ -496,15 +496,14 @@ def _maybe_evaluate_binop(
                 f"'{lhs.type}' and '{rhs.type}'"
             )
 
-        if self.engine != "pytables":
-            if (
-                res.op in CMP_OPS_SYMS
-                and getattr(lhs, "is_datetime", False)
-                or getattr(rhs, "is_datetime", False)
-            ):
-                # all date ops must be done in python bc numexpr doesn't work
-                # well with NaT
-                return self._maybe_eval(res, self.binary_ops)
+        if self.engine != "pytables" and (
+            res.op in CMP_OPS_SYMS
+            and getattr(lhs, "is_datetime", False)
+            or getattr(rhs, "is_datetime", False)
+        ):
+            # all date ops must be done in python bc numexpr doesn't work
+            # well with NaT
+            return self._maybe_eval(res, self.binary_ops)
 
         if res.op in eval_in_python:
             # "in"/"not in" ops are always evaluated in python
diff --git a/pandas/core/computation/pytables.py b/pandas/core/computation/pytables.py
index dd622ed724e8f..6ec637a8b4845 100644
--- a/pandas/core/computation/pytables.py
+++ b/pandas/core/computation/pytables.py
@@ -378,14 +378,14 @@ def prune(self, klass):
         operand = self.operand
         operand = operand.prune(klass)
 
-        if operand is not None:
-            if issubclass(klass, ConditionBinOp):
-                if operand.condition is not None:
-                    return operand.invert()
-            elif issubclass(klass, FilterBinOp):
-                if operand.filter is not None:
-                    return operand.invert()
-
+        if operand is not None and (
+            issubclass(klass, ConditionBinOp)
+            and operand.condition is not None
+            or not issubclass(klass, ConditionBinOp)
+            and issubclass(klass, FilterBinOp)
+            and operand.filter is not None
+        ):
+            return operand.invert()
         return None
 
 
diff --git a/pandas/core/computation/scope.py b/pandas/core/computation/scope.py
index 2925f583bfc56..7a9b8caa985e3 100644
--- a/pandas/core/computation/scope.py
+++ b/pandas/core/computation/scope.py
@@ -144,8 +144,7 @@ def __init__(
     def __repr__(self) -> str:
         scope_keys = _get_pretty_string(list(self.scope.keys()))
         res_keys = _get_pretty_string(list(self.resolvers.keys()))
-        unicode_str = f"{type(self).__name__}(scope={scope_keys}, resolvers={res_keys})"
-        return unicode_str
+        return f"{type(self).__name__}(scope={scope_keys}, resolvers={res_keys})"
 
     @property
     def has_resolvers(self) -> bool: