Skip to content

Commit 06790d7

Browse files
jbrockmendeljreback
authored andcommitted
DEPR: deprecate truediv param in pd.eval (#29812)
1 parent 854bcb5 commit 06790d7

File tree

6 files changed

+49
-30
lines changed

6 files changed

+49
-30
lines changed

doc/source/whatsnew/v1.0.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ Deprecations
364364
value in ``idx`` of ``idx_val`` and a new value of ``val``, ``idx.set_value(arr, idx_val, val)``
365365
is equivalent to ``arr[idx.get_loc(idx_val)] = val``, which should be used instead (:issue:`28621`).
366366
- :func:`is_extension_type` is deprecated, :func:`is_extension_array_dtype` should be used instead (:issue:`29457`)
367-
367+
- :func:`eval` keyword argument "truediv" is deprecated and will be removed in a future version (:issue:`29812`)
368368

369369
.. _whatsnew_1000.prior_deprecations:
370370

pandas/core/computation/engines.py

+5-14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import abc
66

77
from pandas.core.computation.align import align_terms, reconstruct_object
8-
from pandas.core.computation.ops import UndefinedVariableError, _mathops, _reductions
8+
from pandas.core.computation.ops import _mathops, _reductions
99

1010
import pandas.io.formats.printing as printing
1111

@@ -114,19 +114,10 @@ def _evaluate(self):
114114
# convert the expression to a valid numexpr expression
115115
s = self.convert()
116116

117-
try:
118-
env = self.expr.env
119-
scope = env.full_scope
120-
truediv = scope["truediv"]
121-
_check_ne_builtin_clash(self.expr)
122-
return ne.evaluate(s, local_dict=scope, truediv=truediv)
123-
except KeyError as e:
124-
# python 3 compat kludge
125-
try:
126-
msg = e.message
127-
except AttributeError:
128-
msg = str(e)
129-
raise UndefinedVariableError(msg)
117+
env = self.expr.env
118+
scope = env.full_scope
119+
_check_ne_builtin_clash(self.expr)
120+
return ne.evaluate(s, local_dict=scope)
130121

131122

132123
class PythonEngine(AbstractEngine):

pandas/core/computation/eval.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import tokenize
88
import warnings
99

10+
from pandas._libs.lib import _no_default
1011
from pandas.util._validators import validate_bool_kwarg
1112

1213
from pandas.core.computation.engines import _engines
@@ -169,7 +170,7 @@ def eval(
169170
expr,
170171
parser="pandas",
171172
engine=None,
172-
truediv=True,
173+
truediv=_no_default,
173174
local_dict=None,
174175
global_dict=None,
175176
resolvers=(),
@@ -219,6 +220,8 @@ def eval(
219220
220221
truediv : bool, optional
221222
Whether to use true division, like in Python >= 3.
223+
deprecated:: 1.0.0
224+
222225
local_dict : dict or None, optional
223226
A dictionary of local variables, taken from locals() by default.
224227
global_dict : dict or None, optional
@@ -284,6 +287,14 @@ def eval(
284287

285288
inplace = validate_bool_kwarg(inplace, "inplace")
286289

290+
if truediv is not _no_default:
291+
warnings.warn(
292+
"The `truediv` parameter in pd.eval is deprecated and will be "
293+
"removed in a future version.",
294+
FutureWarning,
295+
stacklevel=2,
296+
)
297+
287298
if isinstance(expr, str):
288299
_check_expression(expr)
289300
exprs = [e.strip() for e in expr.splitlines() if e.strip() != ""]
@@ -317,7 +328,7 @@ def eval(
317328
target=target,
318329
)
319330

320-
parsed_expr = Expr(expr, engine=engine, parser=parser, env=env, truediv=truediv)
331+
parsed_expr = Expr(expr, engine=engine, parser=parser, env=env)
321332

322333
# construct the engine and evaluate the parsed expression
323334
eng = _engines[engine]

pandas/core/computation/expr.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import itertools as it
88
import operator
99
import tokenize
10-
from typing import Type
10+
from typing import Optional, Type
1111

1212
import numpy as np
1313

@@ -564,8 +564,7 @@ def visit_BinOp(self, node, **kwargs):
564564
return self._maybe_evaluate_binop(op, op_class, left, right)
565565

566566
def visit_Div(self, node, **kwargs):
567-
truediv = self.env.scope["truediv"]
568-
return lambda lhs, rhs: Div(lhs, rhs, truediv)
567+
return lambda lhs, rhs: Div(lhs, rhs)
569568

570569
def visit_UnaryOp(self, node, **kwargs):
571570
op = self.visit(node.op)
@@ -813,18 +812,25 @@ class Expr:
813812
engine : str, optional, default 'numexpr'
814813
parser : str, optional, default 'pandas'
815814
env : Scope, optional, default None
816-
truediv : bool, optional, default True
817815
level : int, optional, default 2
818816
"""
819817

818+
env: Scope
819+
engine: str
820+
parser: str
821+
820822
def __init__(
821-
self, expr, engine="numexpr", parser="pandas", env=None, truediv=True, level=0
823+
self,
824+
expr,
825+
engine: str = "numexpr",
826+
parser: str = "pandas",
827+
env: Optional[Scope] = None,
828+
level: int = 0,
822829
):
823830
self.expr = expr
824831
self.env = env or Scope(level=level + 1)
825832
self.engine = engine
826833
self.parser = parser
827-
self.env.scope["truediv"] = truediv
828834
self._visitor = _parsers[parser](self.env, self.engine, self.parser)
829835
self.terms = self.parse()
830836

pandas/core/computation/ops.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,6 @@ def __call__(self, env):
391391
object
392392
The result of an evaluated expression.
393393
"""
394-
# handle truediv
395-
if self.op == "/" and env.scope["truediv"]:
396-
self.func = operator.truediv
397394

398395
# recurse over the left/right nodes
399396
left = self.lhs(env)
@@ -505,12 +502,9 @@ class Div(BinOp):
505502
----------
506503
lhs, rhs : Term or Op
507504
The Terms or Ops in the ``/`` expression.
508-
truediv : bool
509-
Whether or not to use true division. With Python 3 this happens
510-
regardless of the value of ``truediv``.
511505
"""
512506

513-
def __init__(self, lhs, rhs, truediv: bool, **kwargs):
507+
def __init__(self, lhs, rhs, **kwargs):
514508
super().__init__("/", lhs, rhs, **kwargs)
515509

516510
if not isnumeric(lhs.return_type) or not isnumeric(rhs.return_type):

pandas/tests/computation/test_eval.py

+17
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,23 @@ def test_inf(engine, parser):
20062006
assert result == expected
20072007

20082008

2009+
def test_truediv_deprecated(engine, parser):
2010+
# GH#29182
2011+
match = "The `truediv` parameter in pd.eval is deprecated"
2012+
2013+
with tm.assert_produces_warning(FutureWarning) as m:
2014+
pd.eval("1+1", engine=engine, parser=parser, truediv=True)
2015+
2016+
assert len(m) == 1
2017+
assert match in str(m[0].message)
2018+
2019+
with tm.assert_produces_warning(FutureWarning) as m:
2020+
pd.eval("1+1", engine=engine, parser=parser, truediv=False)
2021+
2022+
assert len(m) == 1
2023+
assert match in str(m[0].message)
2024+
2025+
20092026
def test_negate_lt_eq_le(engine, parser):
20102027
df = pd.DataFrame([[0, 10], [1, 20]], columns=["cat", "count"])
20112028
expected = df[~(df.cat > 0)]

0 commit comments

Comments
 (0)