Public Access
128 lines
4.4 KiB
Python
128 lines
4.4 KiB
Python
import threading
|
|
import io
|
|
import sys
|
|
import os
|
|
import os.path
|
|
import traceback
|
|
import logging
|
|
import ast
|
|
from damaris.data import Resultable
|
|
from damaris.gui.ExperimentHandling import StopExperiment, _SandboxStdout
|
|
|
|
logger = logging.getLogger("damaris.result_handling")
|
|
|
|
class ResultHandling(threading.Thread):
|
|
"""
|
|
runs the result script in sandbox
|
|
"""
|
|
|
|
def __init__(self, script_data, result_iterator, data_pool, log_callback=None):
|
|
threading.Thread.__init__(self,name="result handler")
|
|
self.script=script_data
|
|
self.results=result_iterator
|
|
self.data_space=data_pool
|
|
self.quit_flag=self.results.quit_flag
|
|
self._log_callback = log_callback
|
|
if self.data_space is not None:
|
|
self.data_space["__recentresult"]=-1
|
|
|
|
def run(self):
|
|
# Redirect stdout/stderr so print() in sandboxed scripts goes to the GUI
|
|
_orig_stdout = sys.stdout
|
|
_orig_stderr = sys.stderr
|
|
if self._log_callback is not None:
|
|
sys.stdout = _SandboxStdout(self._log_callback)
|
|
sys.stderr = _SandboxStdout(self._log_callback)
|
|
|
|
# execute it
|
|
dataspace={}
|
|
data_classes = __import__('damaris.data', dataspace, dataspace, ['*'])
|
|
for name in dir(data_classes):
|
|
if name[:2]=="__" and name[-2:]=="__": continue
|
|
dataspace[name]=data_classes.__dict__[name]
|
|
del data_classes
|
|
dataspace["results"]=self
|
|
dataspace["data"]=self.data_space
|
|
dataspace["sleep"]=self.sleep
|
|
self.raised_exception=None
|
|
self.location = None
|
|
|
|
# check for time.sleep()
|
|
try:
|
|
tree = ast.parse(self.script)
|
|
for node in ast.walk(tree):
|
|
found_blocking_sleep = False
|
|
if isinstance(node, ast.Call):
|
|
func = node.func
|
|
if isinstance(func, ast.Attribute) and func.attr == 'sleep':
|
|
if isinstance(func.value, ast.Name) and func.value.id == 'time':
|
|
found_blocking_sleep = True
|
|
elif isinstance(node, ast.ImportFrom) and node.module == 'time':
|
|
for alias in node.names:
|
|
if alias.name == 'sleep':
|
|
found_blocking_sleep = True
|
|
|
|
if found_blocking_sleep:
|
|
logger.warning("time.sleep() detected in result script. This is blocking and not interruptible. Please use sleep() instead.")
|
|
break
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
exec(self.script, dataspace)
|
|
except StopExperiment:
|
|
return
|
|
except Exception as e:
|
|
self.raised_exception=e
|
|
self.location=traceback.extract_tb(sys.exc_info()[2])[-1][1:3]
|
|
traceback_file=io.StringIO()
|
|
traceback.print_tb(sys.exc_info()[2], None, traceback_file)
|
|
self.traceback=traceback_file.getvalue()
|
|
traceback_file=None
|
|
return
|
|
if not "result" in dataspace:
|
|
dataspace=None
|
|
return
|
|
try:
|
|
dataspace["result"]()
|
|
except StopExperiment:
|
|
pass
|
|
except Exception as e:
|
|
self.raised_exception=e
|
|
self.location=traceback.extract_tb(sys.exc_info()[2])[-1][1:3]
|
|
traceback_file=io.StringIO()
|
|
traceback.print_tb(sys.exc_info()[2], None, traceback_file)
|
|
self.traceback=traceback_file.getvalue()
|
|
traceback_file=None
|
|
dataspace=None
|
|
|
|
# Restore stdout/stderr
|
|
sys.stdout = _orig_stdout
|
|
sys.stderr = _orig_stderr
|
|
|
|
def sleep(self, seconds):
|
|
self.quit_flag.wait(seconds)
|
|
if self.quit_flag.isSet():
|
|
raise StopExperiment
|
|
|
|
def __iter__(self):
|
|
if self.quit_flag.isSet():
|
|
self.results=None
|
|
return
|
|
for i in self.results:
|
|
if hasattr(self.results, "in_advance"):
|
|
self.data_space["__resultsinadvance"]=self.results.in_advance
|
|
if self.quit_flag.isSet():
|
|
self.results=None
|
|
return
|
|
if isinstance(i, Resultable.Resultable):
|
|
if self.data_space is not None:
|
|
self.data_space["__recentresult"]=i.job_id+0
|
|
yield i
|
|
if self.quit_flag.isSet():
|
|
self.results=None
|
|
return
|
|
|
|
def stop(self):
|
|
self.quit_flag.set()
|