Skip to content

Commit abece9c

Browse files
TYP: pandas/core/computation/expr.py (#31365)
1 parent 497c564 commit abece9c

File tree

1 file changed

+63
-36
lines changed

1 file changed

+63
-36
lines changed

pandas/core/computation/expr.py

+63-36
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
""":func:`~pandas.eval` parsers
1+
"""
2+
:func:`~pandas.eval` parsers.
23
"""
34

45
import ast
56
from functools import partial, reduce
67
from keyword import iskeyword
78
import tokenize
8-
from typing import Optional, Type
9+
from typing import Callable, Optional, Set, Tuple, Type, TypeVar
910

1011
import numpy as np
1112

@@ -34,8 +35,9 @@
3435
import pandas.io.formats.printing as printing
3536

3637

37-
def _rewrite_assign(tok):
38-
"""Rewrite the assignment operator for PyTables expressions that use ``=``
38+
def _rewrite_assign(tok: Tuple[int, str]) -> Tuple[int, str]:
39+
"""
40+
Rewrite the assignment operator for PyTables expressions that use ``=``
3941
as a substitute for ``==``.
4042
4143
Parameters
@@ -45,15 +47,16 @@ def _rewrite_assign(tok):
4547
4648
Returns
4749
-------
48-
t : tuple of int, str
50+
tuple of int, str
4951
Either the input or token or the replacement values
5052
"""
5153
toknum, tokval = tok
5254
return toknum, "==" if tokval == "=" else tokval
5355

5456

55-
def _replace_booleans(tok):
56-
"""Replace ``&`` with ``and`` and ``|`` with ``or`` so that bitwise
57+
def _replace_booleans(tok: Tuple[int, str]) -> Tuple[int, str]:
58+
"""
59+
Replace ``&`` with ``and`` and ``|`` with ``or`` so that bitwise
5760
precedence is changed to boolean precedence.
5861
5962
Parameters
@@ -63,7 +66,7 @@ def _replace_booleans(tok):
6366
6467
Returns
6568
-------
66-
t : tuple of int, str
69+
tuple of int, str
6770
Either the input or token or the replacement values
6871
"""
6972
toknum, tokval = tok
@@ -76,8 +79,9 @@ def _replace_booleans(tok):
7679
return toknum, tokval
7780

7881

79-
def _replace_locals(tok):
80-
"""Replace local variables with a syntactically valid name.
82+
def _replace_locals(tok: Tuple[int, str]) -> Tuple[int, str]:
83+
"""
84+
Replace local variables with a syntactically valid name.
8185
8286
Parameters
8387
----------
@@ -86,7 +90,7 @@ def _replace_locals(tok):
8690
8791
Returns
8892
-------
89-
t : tuple of int, str
93+
tuple of int, str
9094
Either the input or token or the replacement values
9195
9296
Notes
@@ -102,12 +106,16 @@ def _replace_locals(tok):
102106

103107

104108
def _compose2(f, g):
105-
"""Compose 2 callables"""
109+
"""
110+
Compose 2 callables.
111+
"""
106112
return lambda *args, **kwargs: f(g(*args, **kwargs))
107113

108114

109115
def _compose(*funcs):
110-
"""Compose 2 or more callables"""
116+
"""
117+
Compose 2 or more callables.
118+
"""
111119
assert len(funcs) > 1, "At least 2 callables must be passed to compose"
112120
return reduce(_compose2, funcs)
113121

@@ -117,8 +125,9 @@ def _preparse(
117125
f=_compose(
118126
_replace_locals, _replace_booleans, _rewrite_assign, clean_backtick_quoted_toks
119127
),
120-
):
121-
"""Compose a collection of tokenization functions
128+
) -> str:
129+
"""
130+
Compose a collection of tokenization functions.
122131
123132
Parameters
124133
----------
@@ -132,7 +141,7 @@ def _preparse(
132141
133142
Returns
134143
-------
135-
s : str
144+
str
136145
Valid Python source code
137146
138147
Notes
@@ -146,7 +155,9 @@ def _preparse(
146155

147156

148157
def _is_type(t):
149-
"""Factory for a type checking function of type ``t`` or tuple of types."""
158+
"""
159+
Factory for a type checking function of type ``t`` or tuple of types.
160+
"""
150161
return lambda x: isinstance(x.value, t)
151162

152163

@@ -164,7 +175,9 @@ def _is_type(t):
164175

165176

166177
def _filter_nodes(superclass, all_nodes=_all_nodes):
167-
"""Filter out AST nodes that are subclasses of ``superclass``."""
178+
"""
179+
Filter out AST nodes that are subclasses of ``superclass``.
180+
"""
168181
node_names = (node.__name__ for node in all_nodes if issubclass(node, superclass))
169182
return frozenset(node_names)
170183

@@ -227,30 +240,35 @@ def _filter_nodes(superclass, all_nodes=_all_nodes):
227240
assert not intersection, _msg
228241

229242

230-
def _node_not_implemented(node_name, cls):
231-
"""Return a function that raises a NotImplementedError with a passed node
232-
name.
243+
# TODO: Python 3.6.2: replace Callable[..., None] with Callable[..., NoReturn]
244+
def _node_not_implemented(node_name: str) -> Callable[..., None]:
245+
"""
246+
Return a function that raises a NotImplementedError with a passed node name.
233247
"""
234248

235249
def f(self, *args, **kwargs):
236-
raise NotImplementedError(f"{repr(node_name)} nodes are not implemented")
250+
raise NotImplementedError(f"'{node_name}' nodes are not implemented")
237251

238252
return f
239253

240254

241-
def disallow(nodes):
242-
"""Decorator to disallow certain nodes from parsing. Raises a
255+
_T = TypeVar("_T", bound="BaseExprVisitor")
256+
257+
258+
def disallow(nodes: Set[str]) -> Callable[[Type[_T]], Type[_T]]:
259+
"""
260+
Decorator to disallow certain nodes from parsing. Raises a
243261
NotImplementedError instead.
244262
245263
Returns
246264
-------
247-
disallowed : callable
265+
callable
248266
"""
249267

250-
def disallowed(cls):
268+
def disallowed(cls: Type[_T]) -> Type[_T]:
251269
cls.unsupported_nodes = ()
252270
for node in nodes:
253-
new_method = _node_not_implemented(node, cls)
271+
new_method = _node_not_implemented(node)
254272
name = f"visit_{node}"
255273
cls.unsupported_nodes += (name,)
256274
setattr(cls, name, new_method)
@@ -260,20 +278,21 @@ def disallowed(cls):
260278

261279

262280
def _op_maker(op_class, op_symbol):
263-
"""Return a function to create an op class with its symbol already passed.
281+
"""
282+
Return a function to create an op class with its symbol already passed.
264283
265284
Returns
266285
-------
267-
f : callable
286+
callable
268287
"""
269288

270289
def f(self, node, *args, **kwargs):
271-
"""Return a partial function with an Op subclass with an operator
272-
already passed.
290+
"""
291+
Return a partial function with an Op subclass with an operator already passed.
273292
274293
Returns
275294
-------
276-
f : callable
295+
callable
277296
"""
278297
return partial(op_class, op_symbol, *args, **kwargs)
279298

@@ -284,7 +303,9 @@ def f(self, node, *args, **kwargs):
284303

285304

286305
def add_ops(op_classes):
287-
"""Decorator to add default implementation of ops."""
306+
"""
307+
Decorator to add default implementation of ops.
308+
"""
288309

289310
def f(cls):
290311
for op_attr_name, op_class in op_classes.items():
@@ -353,6 +374,8 @@ class BaseExprVisitor(ast.NodeVisitor):
353374
ast.NotIn: ast.NotIn,
354375
}
355376

377+
unsupported_nodes: Tuple[str, ...]
378+
356379
def __init__(self, env, engine, parser, preparser=_preparse):
357380
self.env = env
358381
self.engine = engine
@@ -647,7 +670,7 @@ def visit_Call(self, node, side=None, **kwargs):
647670
f'Function "{res.name}" does not support keyword arguments'
648671
)
649672

650-
return res(*new_args, **kwargs)
673+
return res(*new_args)
651674

652675
else:
653676

@@ -777,12 +800,16 @@ def __len__(self) -> int:
777800
return len(self.expr)
778801

779802
def parse(self):
780-
"""Parse an expression"""
803+
"""
804+
Parse an expression.
805+
"""
781806
return self._visitor.visit(self.expr)
782807

783808
@property
784809
def names(self):
785-
"""Get the names in an expression"""
810+
"""
811+
Get the names in an expression.
812+
"""
786813
if is_term(self.terms):
787814
return frozenset([self.terms.name])
788815
return frozenset(term.name for term in com.flatten(self.terms))

0 commit comments

Comments
 (0)