Source code for psi.context.expression

import logging
log = logging.getLogger(__name__)

from atom.api import Atom, Typed
from psi.util import get_dependencies


[docs] class Expr: def __init__(self, expression): if not isinstance(expression, str): raise ValueError('Expression must be a string') if not expression: raise ValueError('No value provided for expression') self._expression = expression self._code = compile(expression, 'dynamic', 'eval') self._dependencies = get_dependencies(expression)
[docs] def evaluate(self, context): return eval(self._expression, context)
def __str__(self): return f'{self._expression}' def __repr__(self): return f'<Expr: {self}>'
[docs] class ExpressionNamespace(Atom): _locals = Typed(dict, {}) _expressions = Typed(dict, {}) _globals = Typed(dict, {}) def __init__(self, expressions=None, globals=None): if globals is None: globals = {} if expressions is None: expressions = {} self._locals = {} self._globals = globals self._expressions = {k: Expr(str(v)) for k, v in expressions.items()}
[docs] def update_expressions(self, expressions): self._expressions.update({k: Expr(str(v)) for k, v in expressions.items()})
[docs] def update_symbols(self, symbols): self._globals.update(symbols)
[docs] def reset(self, context_item_names=None): ''' Clears the computed values (as well as any user-provided values) in preparation for the next cycle. ''' self._locals = {}
[docs] def get_value(self, name, context=None, force_eval=False): if force_eval or name not in self._locals: self._evaluate_value(name, context) return self._locals[name]
[docs] def get_values(self, names=None, context=None): if names is None: names = self._expressions.keys() for name in names: if name not in self._locals: self._evaluate_value(name, context) return dict(self._locals.copy())
[docs] def set_value(self, name, value): _locals = self._locals.copy() _locals[name] = value self._locals = _locals
[docs] def set_values(self, values): _locals = self._locals.copy() _locals.update(values) self._locals = _locals
def _evaluate_value(self, name, context=None): if context is None: context = {} if name in context: self._locals[name] = context[name] return expr = self._expressions[name] c = self._globals.copy() c.update(self._locals) c.update(context) # Build a context dictionary containing the dependencies required for # evaluating the expression. for d in expr._dependencies: if d not in c and d in self._expressions: c[d] = self.get_value(d, c) # Note that in the past I was forcing a copy of self._locals to ensure # that the GUI was updated as needed; however, this proved to be a very # slow process since it triggered a cascade of GUI updates. try: self._locals[name] = expr.evaluate(c) except Exception: log.error('Unable to evaluate expression %s for %s', expr._expression, name) raise