mirror of
https://github.com/status-im/spiff-arena.git
synced 2025-01-15 04:34:16 +00:00
02855719b8
0e61be85 Merge pull request #289 from sartography/improvement/execution-and-serialization-cleanup 527684da fix some typos in the class & method docs 0dff44a4 Merge branch 'main' into improvement/execution-and-serialization-cleanup 64737498 Allow for other PythonScriptEngine environments besides task data (#288) dd63e916 remove some unused tests & diagrams 24aae519 clean up various small stuff 3b2dc35d use context when opening files for parsing 69eec3eb update class/method docs 24528dfb move all spec conversion classes to top level 5af33b11 remove some unused methods related to old serializer 931b90fb reorganize serializer 4e81ed29 consolidate pointless serializer classes d62acf02 change task_spec._update_hook to return a boolean indicating whether the task is ready git-subtree-dir: SpiffWorkflow git-subtree-split: 0e61be85c47474a33037e6f398e64c96e02f13ad
123 lines
4.0 KiB
Python
123 lines
4.0 KiB
Python
import copy
|
|
import warnings
|
|
|
|
class BasePythonScriptEngineEnvironment:
|
|
def __init__(self, environment_globals=None):
|
|
self.globals = environment_globals or {}
|
|
|
|
def evaluate(self, expression, context, external_methods=None):
|
|
raise NotImplementedError("Subclass must implement this method")
|
|
|
|
def execute(self, script, context, external_methods=None):
|
|
raise NotImplementedError("Subclass must implement this method")
|
|
|
|
class TaskDataEnvironment(BasePythonScriptEngineEnvironment):
|
|
def evaluate(self, expression, context, external_methods=None):
|
|
my_globals = copy.copy(self.globals) # else we pollute all later evals.
|
|
self._prepare_context(context)
|
|
my_globals.update(external_methods or {})
|
|
my_globals.update(context)
|
|
return eval(expression, my_globals)
|
|
|
|
def execute(self, script, context, external_methods=None):
|
|
my_globals = copy.copy(self.globals)
|
|
self._prepare_context(context)
|
|
my_globals.update(external_methods or {})
|
|
context.update(my_globals)
|
|
try:
|
|
exec(script, context)
|
|
finally:
|
|
self._remove_globals_and_functions_from_context(context, external_methods)
|
|
|
|
def _prepare_context(self, context):
|
|
pass
|
|
|
|
def _remove_globals_and_functions_from_context(self, context,
|
|
external_methods=None):
|
|
"""When executing a script, don't leave the globals, functions
|
|
and external methods in the context that we have modified."""
|
|
for k in list(context):
|
|
if k == "__builtins__" or \
|
|
hasattr(context[k], '__call__') or \
|
|
k in self.globals or \
|
|
external_methods and k in external_methods:
|
|
context.pop(k)
|
|
|
|
class Box(dict):
|
|
"""
|
|
Example:
|
|
m = Box({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
warnings.warn('The usage of Box has been deprecated.', DeprecationWarning, stacklevel=2)
|
|
super(Box, self).__init__(*args, **kwargs)
|
|
for arg in args:
|
|
if isinstance(arg, dict):
|
|
for k, v in arg.items():
|
|
if isinstance(v, dict):
|
|
self[k] = Box(v)
|
|
else:
|
|
self[k] = v
|
|
|
|
if kwargs:
|
|
for k, v in kwargs.items():
|
|
if isinstance(v, dict):
|
|
self[k] = Box(v)
|
|
else:
|
|
self[k] = v
|
|
|
|
def __deepcopy__(self, memodict=None):
|
|
if memodict is None:
|
|
memodict = {}
|
|
my_copy = Box()
|
|
for k, v in self.items():
|
|
my_copy[k] = copy.deepcopy(v)
|
|
return my_copy
|
|
|
|
def __getattr__(self, attr):
|
|
try:
|
|
output = self[attr]
|
|
except:
|
|
raise AttributeError(
|
|
"Dictionary has no attribute '%s' " % str(attr))
|
|
return output
|
|
|
|
def __setattr__(self, key, value):
|
|
self.__setitem__(key, value)
|
|
|
|
def __setitem__(self, key, value):
|
|
super(Box, self).__setitem__(key, value)
|
|
self.__dict__.update({key: value})
|
|
|
|
def __getstate__(self):
|
|
return self.__dict__
|
|
|
|
def __setstate__(self, state):
|
|
self.__init__(state)
|
|
|
|
def __delattr__(self, item):
|
|
self.__delitem__(item)
|
|
|
|
def __delitem__(self, key):
|
|
super(Box, self).__delitem__(key)
|
|
del self.__dict__[key]
|
|
|
|
@classmethod
|
|
def convert_to_box(cls, data):
|
|
if isinstance(data, dict):
|
|
for key, value in data.items():
|
|
if not isinstance(value, Box):
|
|
data[key] = cls.convert_to_box(value)
|
|
return Box(data)
|
|
if isinstance(data, list):
|
|
for idx, value in enumerate(data):
|
|
data[idx] = cls.convert_to_box(value)
|
|
return data
|
|
return data
|
|
|
|
class BoxedTaskDataEnvironment(TaskDataEnvironment):
|
|
def _prepare_context(self, context):
|
|
Box.convert_to_box(context)
|
|
|