29from typing
import Mapping, MutableMapping, Set, Type, Union, Optional, Any, Iterable
39OPERATORS = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul,
40 ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor,
83def makeColumnExpressionAction(className: str, expr: str,
84 exprDefaults: Optional[Mapping[str, Union[DataFrameAction,
85 Type[DataFrameAction]]]] =
None,
87 ) -> Type[DataFrameAction]:
88 """Factory function for producing ConfigurableAction classes which are
89 realizations of arithmetic operations.
94 The name of the class that will be produced
96 An arithmetic expression that will be parsed to produce the output
97 ConfigurableAction. Individual variable names will be the name of
98 individual `ConfigActions` inside the expression (i.e. "x+y" will
99 produce an action with configAction.actions.x and
100 configAction.actions.y). Expression can contain arithmatic python
101 operators as well as; sin, cos, sinh, cosh, log (which is base 10).
102 exprDefaults : `Mapping` of `str` to `DataFrameAction` optional
103 A mapping of strings which correspond to the names in the expression to
104 values which are default `ConfigurableActions` to assign in the
105 expression. If no default for a action is supplied `SingleColumnAction`
106 is set as the default.
108 A string that is assigned as the resulting classes docstring
112 action : `Type` of `DataFrameAction`
113 A `DataFrameAction` class that was programatically constructed from the
121 new_module = inspect.stack()[1].frame.f_locals[
'__name__']
122 node = ast.parse(expr, mode=
'eval')
125 names: Set[str] = set()
126 for elm
in ast.walk(node):
127 if isinstance(elm, ast.Name):
131 names -= EXTRA_MATH.keys()
133 fields: Mapping[str, ConfigurableActionField] = {}
134 for name
in sorted(names):
135 if exprDefaults
is not None and (value := exprDefaults.get(name))
is not None:
136 kwargs = {
"default": value}
139 fields[name] = ConfigurableActionField(doc=f
"expression action {name}", **kwargs)
143 def __call__(self, df: pd.DataFrame, **kwargs) -> pd.Series:
146 values_map[name] = getattr(self, name)(df, **kwargs)
149 return parser.visit(node.body)
152 def columns(self) -> Iterable[str]:
154 yield from getattr(self, name).columns
156 dct: MutableMapping[str, Any] = {
"__call__": __call__,
"columns": property(columns)}
157 if docstring
is not None:
158 dct[
'__doc__'] = docstring
160 dct[
'__module__'] = new_module
162 return type(className, (DataFrameAction, ), dct)