Files
python3-damaris/src/damaris/gui/ResultHandling.py
T
markusro f9d8de7697
Build Debian Packages / build (bookworm, debian12) (push) Successful in 8m56s
Build Debian Packages / build (trixie, debian13) (push) Successful in 9m3s
fix return-value/deprecated API bugs, accumulation lock leaks, code cleanup
- raise instead of silent None for unsupported operands and empty negation
- validate before acquiring lock in Accumulation operators (no RLock leak)
- Accumulation._copy_provenance helper, ADC_Result._copy_metadata for all result paths
- shared _sandbox_stdout_redirect contextmanager for sandboxed scripts
- TemperatureMonitor dead code removal (gtk helper, traceback, unused properties)
- new unit tests incl. lock-freedom regression test
- gitignore sphinx generated doc/_autosummary/ and doc/damaris/
2026-10-17 19:17:43 +02:00

125 lines
4.3 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, _sandbox_stdout_redirect
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
if self._log_callback is not None:
with _sandbox_stdout_redirect(self._log_callback):
self._run_script()
else:
self._run_script()
def _run_script(self):
# 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
def sleep(self, seconds):
self.quit_flag.wait(seconds)
if self.quit_flag.is_set():
raise StopExperiment
def __iter__(self):
if self.quit_flag.is_set():
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.is_set():
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.is_set():
self.results=None
return
def stop(self):
self.quit_flag.set()