Skip to content

CLN: typing and renaming in computation.pytables #29778

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 29 additions & 23 deletions pandas/core/computation/pytables.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from pandas.io.formats.printing import pprint_thing, pprint_thing_encoded


class Scope(_scope.Scope):
class PyTablesScope(_scope.Scope):
__slots__ = ("queryables",)

queryables: Dict[str, Any]
Expand All @@ -38,13 +38,13 @@ def __init__(


class Term(ops.Term):
env: Scope
env: PyTablesScope

def __new__(cls, name, env, side=None, encoding=None):
klass = Constant if not isinstance(name, str) else cls
return object.__new__(klass)

def __init__(self, name, env: Scope, side=None, encoding=None):
def __init__(self, name, env: PyTablesScope, side=None, encoding=None):
super().__init__(name, env, side=side, encoding=encoding)

def _resolve_name(self):
Expand All @@ -68,7 +68,8 @@ def value(self):


class Constant(Term):
def __init__(self, value, env, side=None, encoding=None):
def __init__(self, value, env: PyTablesScope, side=None, encoding=None):
assert isinstance(env, PyTablesScope), type(env)
super().__init__(value, env, side=side, encoding=encoding)

def _resolve_name(self):
Expand Down Expand Up @@ -270,7 +271,7 @@ def evaluate(self):
raise ValueError("query term is not valid [{slf}]".format(slf=self))

rhs = self.conform(self.rhs)
values = [TermValue(v, v, self.kind).value for v in rhs]
values = list(rhs)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the most non-trivial change. It allows us to type the kind arg to TermValue as str, and in turn simplify some other parts of TermValue


if self.is_in_table:

Expand Down Expand Up @@ -386,7 +387,7 @@ def prune(self, klass):
return None


class ExprVisitor(BaseExprVisitor):
class PyTablesExprVisitor(BaseExprVisitor):
const_type = Constant
term_type = Term

Expand Down Expand Up @@ -486,25 +487,29 @@ def _validate_where(w):
TypeError : An invalid data type was passed in for w (e.g. dict).
"""

if not (isinstance(w, (Expr, str)) or is_list_like(w)):
raise TypeError("where must be passed as a string, Expr, or list-like of Exprs")
if not (isinstance(w, (PyTablesExpr, str)) or is_list_like(w)):
raise TypeError(
"where must be passed as a string, PyTablesExpr, "
"or list-like of PyTablesExpr"
)

return w


class Expr(expr.Expr):
""" hold a pytables like expression, comprised of possibly multiple 'terms'
class PyTablesExpr(expr.Expr):
"""
Hold a pytables-like expression, comprised of possibly multiple 'terms'.

Parameters
----------
where : string term expression, Expr, or list-like of Exprs
where : string term expression, PyTablesExpr, or list-like of PyTablesExprs
queryables : a "kinds" map (dict of column name -> kind), or None if column
is non-indexable
encoding : an encoding that will encode the query terms

Returns
-------
an Expr object
a PyTablesExpr object

Examples
--------
Expand All @@ -520,8 +525,8 @@ class Expr(expr.Expr):
"major_axis>=20130101"
"""

_visitor: Optional[ExprVisitor]
env: Scope
_visitor: Optional[PyTablesExprVisitor]
env: PyTablesScope

def __init__(
self,
Expand All @@ -542,14 +547,14 @@ def __init__(
# capture the environment if needed
local_dict = DeepChainMap()

if isinstance(where, Expr):
if isinstance(where, PyTablesExpr):
local_dict = where.env.scope
_where = where.expr

elif isinstance(where, (list, tuple)):
where = list(where)
for idx, w in enumerate(where):
if isinstance(w, Expr):
if isinstance(w, PyTablesExpr):
local_dict = w.env.scope
else:
w = _validate_where(w)
Expand All @@ -559,11 +564,11 @@ def __init__(
_where = where

self.expr = _where
self.env = Scope(scope_level + 1, local_dict=local_dict)
self.env = PyTablesScope(scope_level + 1, local_dict=local_dict)

if queryables is not None and isinstance(self.expr, str):
self.env.queryables.update(queryables)
self._visitor = ExprVisitor(
self._visitor = PyTablesExprVisitor(
self.env,
queryables=queryables,
parser="pytables",
Expand Down Expand Up @@ -601,30 +606,31 @@ def evaluate(self):
class TermValue:
""" hold a term value the we use to construct a condition/filter """

def __init__(self, value, converted, kind: Optional[str]):
def __init__(self, value, converted, kind: str):
assert isinstance(kind, str), kind
self.value = value
self.converted = converted
self.kind = kind

def tostring(self, encoding):
def tostring(self, encoding) -> str:
""" quote the string if not encoded
else encode and return """
if self.kind == "string":
if encoding is not None:
return self.converted
return str(self.converted)
return '"{converted}"'.format(converted=self.converted)
elif self.kind == "float":
# python 2 str(float) is not always
# round-trippable so use repr()
return repr(self.converted)
return self.converted
return str(self.converted)


def maybe_expression(s) -> bool:
""" loose checking if s is a pytables-acceptable expression """
if not isinstance(s, str):
return False
ops = ExprVisitor.binary_ops + ExprVisitor.unary_ops + ("=",)
ops = PyTablesExprVisitor.binary_ops + PyTablesExprVisitor.unary_ops + ("=",)

# make sure we have an op at least
return any(op in s for op in ops)
2 changes: 1 addition & 1 deletion pandas/core/computation/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def has_resolvers(self) -> bool:
"""
return bool(len(self.resolvers))

def resolve(self, key, is_local):
def resolve(self, key: str, is_local: bool):
"""
Resolve a variable name in a possibly local context.

Expand Down
6 changes: 3 additions & 3 deletions pandas/io/pytables.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from pandas.core.arrays.categorical import Categorical
from pandas.core.arrays.sparse import BlockIndex, IntIndex
import pandas.core.common as com
from pandas.core.computation.pytables import Expr, maybe_expression
from pandas.core.computation.pytables import PyTablesExpr, maybe_expression
from pandas.core.index import ensure_index
from pandas.core.internals import BlockManager, _block_shape, make_block

Expand Down Expand Up @@ -93,7 +93,7 @@ def _ensure_str(name):
return name


Term = Expr
Term = PyTablesExpr


def _ensure_term(where, scope_level: int):
Expand Down Expand Up @@ -5047,7 +5047,7 @@ def generate(self, where):

q = self.table.queryables()
try:
return Expr(where, queryables=q, encoding=self.table.encoding)
return PyTablesExpr(where, queryables=q, encoding=self.table.encoding)
except NameError:
# raise a nice message, suggesting that the user should use
# data_columns
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/computation/test_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -1891,7 +1891,7 @@ def test_invalid_parser():

_parsers: Dict[str, Type[BaseExprVisitor]] = {
"python": PythonExprVisitor,
"pytables": pytables.ExprVisitor,
"pytables": pytables.PyTablesExprVisitor,
"pandas": PandasExprVisitor,
}

Expand Down