Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/pandas/core/computation/engines.py : 52%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2Engine classes for :func:`~pandas.eval`
3"""
5import abc
6from typing import Dict, Type
8from pandas.core.computation.align import align_terms, reconstruct_object
9from pandas.core.computation.ops import _mathops, _reductions
11import pandas.io.formats.printing as printing
13_ne_builtins = frozenset(_mathops + _reductions)
16class NumExprClobberingError(NameError):
17 pass
20def _check_ne_builtin_clash(expr):
21 """
22 Attempt to prevent foot-shooting in a helpful way.
24 Parameters
25 ----------
26 terms : Term
27 Terms can contain
28 """
29 names = expr.names
30 overlap = names & _ne_builtins
32 if overlap:
33 s = ", ".join(repr(x) for x in overlap)
34 raise NumExprClobberingError(
35 f'Variables in expression "{expr}" overlap with builtins: ({s})'
36 )
39class AbstractEngine(metaclass=abc.ABCMeta):
40 """Object serving as a base class for all engines."""
42 has_neg_frac = False
44 def __init__(self, expr):
45 self.expr = expr
46 self.aligned_axes = None
47 self.result_type = None
49 def convert(self) -> str:
50 """
51 Convert an expression for evaluation.
53 Defaults to return the expression as a string.
54 """
55 return printing.pprint_thing(self.expr)
57 def evaluate(self) -> object:
58 """
59 Run the engine on the expression.
61 This method performs alignment which is necessary no matter what engine
62 is being used, thus its implementation is in the base class.
64 Returns
65 -------
66 object
67 The result of the passed expression.
68 """
69 if not self._is_aligned:
70 self.result_type, self.aligned_axes = align_terms(self.expr.terms)
72 # make sure no names in resolvers and locals/globals clash
73 res = self._evaluate()
74 return reconstruct_object(
75 self.result_type, res, self.aligned_axes, self.expr.terms.return_type
76 )
78 @property
79 def _is_aligned(self) -> bool:
80 return self.aligned_axes is not None and self.result_type is not None
82 @abc.abstractmethod
83 def _evaluate(self):
84 """
85 Return an evaluated expression.
87 Parameters
88 ----------
89 env : Scope
90 The local and global environment in which to evaluate an
91 expression.
93 Notes
94 -----
95 Must be implemented by subclasses.
96 """
97 pass
100class NumExprEngine(AbstractEngine):
101 """NumExpr engine class"""
103 has_neg_frac = True
105 def _evaluate(self):
106 import numexpr as ne
108 # convert the expression to a valid numexpr expression
109 s = self.convert()
111 env = self.expr.env
112 scope = env.full_scope
113 _check_ne_builtin_clash(self.expr)
114 return ne.evaluate(s, local_dict=scope)
117class PythonEngine(AbstractEngine):
118 """
119 Evaluate an expression in Python space.
121 Mostly for testing purposes.
122 """
124 has_neg_frac = False
126 def evaluate(self):
127 return self.expr()
129 def _evaluate(self) -> None:
130 pass
133_engines: Dict[str, Type[AbstractEngine]] = {
134 "numexpr": NumExprEngine,
135 "python": PythonEngine,
136}