From 846701316073a93fdc89b1eabde9ddbe63bb8e48 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Dec 2015 17:27:15 +0800 Subject: [PATCH] master,gui: support recomputation+reset of arguments --- artiq/frontend/artiq_gui.py | 3 ++- artiq/gui/experiments.py | 52 +++++++++++++++++++++++++++++-------- artiq/master/repository.py | 24 ++++++++++++++--- artiq/master/worker.py | 4 +-- artiq/master/worker_impl.py | 8 +++--- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/artiq/frontend/artiq_gui.py b/artiq/frontend/artiq_gui.py index c92b7940b..46658d60b 100755 --- a/artiq/frontend/artiq_gui.py +++ b/artiq/frontend/artiq_gui.py @@ -98,7 +98,8 @@ def main(): expmgr = experiments.ExperimentManager(status_bar, dock_area, sub_clients["explist"], sub_clients["schedule"], - rpc_clients["schedule"]) + rpc_clients["schedule"], + rpc_clients["repository"]) smgr.register(expmgr) d_shortcuts = shortcuts.ShortcutsDock(win, expmgr) smgr.register(d_shortcuts) diff --git a/artiq/gui/experiments.py b/artiq/gui/experiments.py index 157a9d7e6..8e718d6f9 100644 --- a/artiq/gui/experiments.py +++ b/artiq/gui/experiments.py @@ -119,7 +119,10 @@ _argty_to_entry = { class _ArgumentEditor(QtGui.QTreeWidget): - def __init__(self, arguments): + def __init__(self, manager, expname): + self.manager = manager + self.expname = expname + QtGui.QTreeWidget.__init__(self) self.setColumnCount(3) self.header().setStretchLastSection(False) @@ -132,16 +135,18 @@ class _ArgumentEditor(QtGui.QTreeWidget): self.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel) self._groups = dict() - self._args_to_entries = dict() + self._arg_to_entry_widgetitem = dict() + + arguments = self.manager.get_submission_arguments(self.expname) if not arguments: self.addTopLevelItem(QtGui.QTreeWidgetItem(["No arguments"])) for n, (name, argument) in enumerate(arguments.items()): entry = _argty_to_entry[argument["desc"]["ty"]](argument) - self._args_to_entries[name] = entry - widget_item = QtGui.QTreeWidgetItem([name]) + self._arg_to_entry_widgetitem[name] = entry, widget_item + if argument["group"] is None: self.addTopLevelItem(widget_item) else: @@ -172,8 +177,28 @@ class _ArgumentEditor(QtGui.QTreeWidget): self._groups[name] = group return group - def _recompute_argument(self, argument): - logger.warning("recompute_argument not implemented (%s)", argument) + def _recompute_argument(self, name): + asyncio.ensure_future(self._recompute_argument_task(name)) + + async def _recompute_argument_task(self, name): + try: + arginfo = await self.manager.recompute_arginfo(self.expname) + except: + logger.warning("Could not recompute argument '%s' of '%s'", + name, self.expname, exc_info=True) + argument = self.manager.get_submission_arguments(self.expname)[name] + + procdesc = arginfo[name][0] + state = _argty_to_entry[procdesc["ty"]].default_state(procdesc) + argument["desc"] = procdesc + argument["state"] = state + + old_entry, widget_item = self._arg_to_entry_widgetitem[name] + old_entry.deleteLater() + + entry = _argty_to_entry[procdesc["ty"]](argument) + self._arg_to_entry_widgetitem[name] = entry, widget_item + self.setItemWidget(widget_item, 1, entry) def save_state(self): expanded = [] @@ -200,8 +225,7 @@ class _ExperimentDock(dockarea.Dock): self.manager = manager self.expname = expname - self.argeditor = _ArgumentEditor( - manager.get_submission_arguments(expname)) + self.argeditor = _ArgumentEditor(manager, expname) self.addWidget(self.argeditor, 0, 0, colspan=5) self.layout.setRowStretch(0, 1) @@ -342,10 +366,11 @@ class _ExperimentDock(dockarea.Dock): class ExperimentManager: def __init__(self, status_bar, dock_area, explist_sub, schedule_sub, - schedule_ctl): + schedule_ctl, repository_ctl): self.status_bar = status_bar self.dock_area = dock_area self.schedule_ctl = schedule_ctl + self.repository_ctl = repository_ctl self.submission_scheduling = dict() self.submission_options = dict() @@ -395,8 +420,8 @@ class ExperimentManager: return self.submission_arguments[expname] else: arguments = OrderedDict() - arginfo = self.explist[expname]["arguments"] - for name, (procdesc, group) in arginfo: + arginfo = self.explist[expname]["arginfo"] + for name, (procdesc, group) in arginfo.items(): state = _argty_to_entry[procdesc["ty"]].default_state(procdesc) arguments[name] = { "desc": procdesc, @@ -470,6 +495,11 @@ class ExperimentManager: rids.append(rid) asyncio.ensure_future(self._request_term_multiple(rids)) + async def recompute_arginfo(self, expname): + expinfo = self.explist[expname] + description = await self.repository_ctl.examine(expinfo["file"]) + return description[expinfo["class_name"]]["arginfo"] + def save_state(self): docks = {expname: dock.save_state() for expname, dock in self.open_experiments.items()} diff --git a/artiq/master/repository.py b/artiq/master/repository.py index 6a3889ca6..10dfaf6d6 100644 --- a/artiq/master/repository.py +++ b/artiq/master/repository.py @@ -3,6 +3,7 @@ import os import tempfile import shutil import logging +from functools import partial from artiq.protocols.sync_struct import Notifier from artiq.master.worker import Worker @@ -16,7 +17,7 @@ async def _get_repository_entries(entry_dict, root, filename, get_device_db, log): worker = Worker({ "get_device_db": get_device_db, - "log": lambda message: log("scan", message) + "log": partial(log, "scan") }) try: description = await worker.examine(os.path.join(root, filename)) @@ -24,7 +25,7 @@ async def _get_repository_entries(entry_dict, await worker.close() for class_name, class_desc in description.items(): name = class_desc["name"] - arguments = class_desc["arguments"] + arginfo = class_desc["arginfo"] if "/" in name: logger.warning("Character '/' is not allowed in experiment " "name (%s)", name) @@ -39,7 +40,7 @@ async def _get_repository_entries(entry_dict, entry = { "file": filename, "class_name": class_name, - "arguments": arguments + "arginfo": arginfo } entry_dict[name] = entry @@ -110,6 +111,23 @@ class Repository: def scan_async(self, new_cur_rev=None): asyncio.ensure_future(exc_to_warning(self.scan(new_cur_rev))) + async def examine(self, filename, use_repository=True): + if use_repository: + revision = self.cur_rev + wd, _ = self.backend.request_rev(revision) + filename = os.path.join(wd, filename) + worker = Worker({ + "get_device_db": self.get_device_db_fn, + "log": partial(self.log_fn, "examine") + }) + try: + description = await worker.examine(filename) + finally: + await worker.close() + if use_repository: + self.backend.release_rev(revision) + return description + class FilesystemBackend: def __init__(self, root): diff --git a/artiq/master/worker.py b/artiq/master/worker.py index f08679239..6471ee0d8 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -248,8 +248,8 @@ class Worker: async def examine(self, file, timeout=20.0): await self._create_process(logging.WARNING) r = dict() - def register(class_name, name, arguments): - r[class_name] = {"name": name, "arguments": arguments} + def register(class_name, name, arginfo): + r[class_name] = {"name": name, "arginfo": arginfo} self.register_experiment = register await self._worker_action({"action": "examine", "file": file}, timeout) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index e97fe6276..89a296d03 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -2,6 +2,7 @@ import sys import time import os import logging +from collections import OrderedDict from artiq.protocols import pyon from artiq.tools import file_import @@ -153,9 +154,10 @@ def examine(device_mgr, dataset_mgr, file): if name[-1] == ".": name = name[:-1] exp_inst = exp_class(device_mgr, dataset_mgr, default_arg_none=True) - arguments = [(k, (proc.describe(), group)) - for k, (proc, group) in exp_inst.requested_args.items()] - register_experiment(class_name, name, arguments) + arginfo = OrderedDict( + (k, (proc.describe(), group)) + for k, (proc, group) in exp_inst.requested_args.items()) + register_experiment(class_name, name, arginfo) def string_to_hdf5(f, key, value):