forked from M-Labs/artiq
1
0
Fork 0

master,gui: support recomputation+reset of arguments

This commit is contained in:
Sebastien Bourdeauducq 2015-12-06 17:27:15 +08:00
parent 1cba685326
commit 8467013160
5 changed files with 71 additions and 20 deletions

View File

@ -98,7 +98,8 @@ def main():
expmgr = experiments.ExperimentManager(status_bar, dock_area, expmgr = experiments.ExperimentManager(status_bar, dock_area,
sub_clients["explist"], sub_clients["explist"],
sub_clients["schedule"], sub_clients["schedule"],
rpc_clients["schedule"]) rpc_clients["schedule"],
rpc_clients["repository"])
smgr.register(expmgr) smgr.register(expmgr)
d_shortcuts = shortcuts.ShortcutsDock(win, expmgr) d_shortcuts = shortcuts.ShortcutsDock(win, expmgr)
smgr.register(d_shortcuts) smgr.register(d_shortcuts)

View File

@ -119,7 +119,10 @@ _argty_to_entry = {
class _ArgumentEditor(QtGui.QTreeWidget): class _ArgumentEditor(QtGui.QTreeWidget):
def __init__(self, arguments): def __init__(self, manager, expname):
self.manager = manager
self.expname = expname
QtGui.QTreeWidget.__init__(self) QtGui.QTreeWidget.__init__(self)
self.setColumnCount(3) self.setColumnCount(3)
self.header().setStretchLastSection(False) self.header().setStretchLastSection(False)
@ -132,16 +135,18 @@ class _ArgumentEditor(QtGui.QTreeWidget):
self.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel) self.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self._groups = dict() 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: if not arguments:
self.addTopLevelItem(QtGui.QTreeWidgetItem(["No arguments"])) self.addTopLevelItem(QtGui.QTreeWidgetItem(["No arguments"]))
for n, (name, argument) in enumerate(arguments.items()): for n, (name, argument) in enumerate(arguments.items()):
entry = _argty_to_entry[argument["desc"]["ty"]](argument) entry = _argty_to_entry[argument["desc"]["ty"]](argument)
self._args_to_entries[name] = entry
widget_item = QtGui.QTreeWidgetItem([name]) widget_item = QtGui.QTreeWidgetItem([name])
self._arg_to_entry_widgetitem[name] = entry, widget_item
if argument["group"] is None: if argument["group"] is None:
self.addTopLevelItem(widget_item) self.addTopLevelItem(widget_item)
else: else:
@ -172,8 +177,28 @@ class _ArgumentEditor(QtGui.QTreeWidget):
self._groups[name] = group self._groups[name] = group
return group return group
def _recompute_argument(self, argument): def _recompute_argument(self, name):
logger.warning("recompute_argument not implemented (%s)", argument) 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): def save_state(self):
expanded = [] expanded = []
@ -200,8 +225,7 @@ class _ExperimentDock(dockarea.Dock):
self.manager = manager self.manager = manager
self.expname = expname self.expname = expname
self.argeditor = _ArgumentEditor( self.argeditor = _ArgumentEditor(manager, expname)
manager.get_submission_arguments(expname))
self.addWidget(self.argeditor, 0, 0, colspan=5) self.addWidget(self.argeditor, 0, 0, colspan=5)
self.layout.setRowStretch(0, 1) self.layout.setRowStretch(0, 1)
@ -342,10 +366,11 @@ class _ExperimentDock(dockarea.Dock):
class ExperimentManager: class ExperimentManager:
def __init__(self, status_bar, dock_area, def __init__(self, status_bar, dock_area,
explist_sub, schedule_sub, explist_sub, schedule_sub,
schedule_ctl): schedule_ctl, repository_ctl):
self.status_bar = status_bar self.status_bar = status_bar
self.dock_area = dock_area self.dock_area = dock_area
self.schedule_ctl = schedule_ctl self.schedule_ctl = schedule_ctl
self.repository_ctl = repository_ctl
self.submission_scheduling = dict() self.submission_scheduling = dict()
self.submission_options = dict() self.submission_options = dict()
@ -395,8 +420,8 @@ class ExperimentManager:
return self.submission_arguments[expname] return self.submission_arguments[expname]
else: else:
arguments = OrderedDict() arguments = OrderedDict()
arginfo = self.explist[expname]["arguments"] arginfo = self.explist[expname]["arginfo"]
for name, (procdesc, group) in arginfo: for name, (procdesc, group) in arginfo.items():
state = _argty_to_entry[procdesc["ty"]].default_state(procdesc) state = _argty_to_entry[procdesc["ty"]].default_state(procdesc)
arguments[name] = { arguments[name] = {
"desc": procdesc, "desc": procdesc,
@ -470,6 +495,11 @@ class ExperimentManager:
rids.append(rid) rids.append(rid)
asyncio.ensure_future(self._request_term_multiple(rids)) 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): def save_state(self):
docks = {expname: dock.save_state() docks = {expname: dock.save_state()
for expname, dock in self.open_experiments.items()} for expname, dock in self.open_experiments.items()}

View File

@ -3,6 +3,7 @@ import os
import tempfile import tempfile
import shutil import shutil
import logging import logging
from functools import partial
from artiq.protocols.sync_struct import Notifier from artiq.protocols.sync_struct import Notifier
from artiq.master.worker import Worker from artiq.master.worker import Worker
@ -16,7 +17,7 @@ async def _get_repository_entries(entry_dict,
root, filename, get_device_db, log): root, filename, get_device_db, log):
worker = Worker({ worker = Worker({
"get_device_db": get_device_db, "get_device_db": get_device_db,
"log": lambda message: log("scan", message) "log": partial(log, "scan")
}) })
try: try:
description = await worker.examine(os.path.join(root, filename)) description = await worker.examine(os.path.join(root, filename))
@ -24,7 +25,7 @@ async def _get_repository_entries(entry_dict,
await worker.close() await worker.close()
for class_name, class_desc in description.items(): for class_name, class_desc in description.items():
name = class_desc["name"] name = class_desc["name"]
arguments = class_desc["arguments"] arginfo = class_desc["arginfo"]
if "/" in name: if "/" in name:
logger.warning("Character '/' is not allowed in experiment " logger.warning("Character '/' is not allowed in experiment "
"name (%s)", name) "name (%s)", name)
@ -39,7 +40,7 @@ async def _get_repository_entries(entry_dict,
entry = { entry = {
"file": filename, "file": filename,
"class_name": class_name, "class_name": class_name,
"arguments": arguments "arginfo": arginfo
} }
entry_dict[name] = entry entry_dict[name] = entry
@ -110,6 +111,23 @@ class Repository:
def scan_async(self, new_cur_rev=None): def scan_async(self, new_cur_rev=None):
asyncio.ensure_future(exc_to_warning(self.scan(new_cur_rev))) 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: class FilesystemBackend:
def __init__(self, root): def __init__(self, root):

View File

@ -248,8 +248,8 @@ class Worker:
async def examine(self, file, timeout=20.0): async def examine(self, file, timeout=20.0):
await self._create_process(logging.WARNING) await self._create_process(logging.WARNING)
r = dict() r = dict()
def register(class_name, name, arguments): def register(class_name, name, arginfo):
r[class_name] = {"name": name, "arguments": arguments} r[class_name] = {"name": name, "arginfo": arginfo}
self.register_experiment = register self.register_experiment = register
await self._worker_action({"action": "examine", "file": file}, await self._worker_action({"action": "examine", "file": file},
timeout) timeout)

View File

@ -2,6 +2,7 @@ import sys
import time import time
import os import os
import logging import logging
from collections import OrderedDict
from artiq.protocols import pyon from artiq.protocols import pyon
from artiq.tools import file_import from artiq.tools import file_import
@ -153,9 +154,10 @@ def examine(device_mgr, dataset_mgr, file):
if name[-1] == ".": if name[-1] == ".":
name = name[:-1] name = name[:-1]
exp_inst = exp_class(device_mgr, dataset_mgr, default_arg_none=True) exp_inst = exp_class(device_mgr, dataset_mgr, default_arg_none=True)
arguments = [(k, (proc.describe(), group)) arginfo = OrderedDict(
for k, (proc, group) in exp_inst.requested_args.items()] (k, (proc.describe(), group))
register_experiment(class_name, name, arguments) for k, (proc, group) in exp_inst.requested_args.items())
register_experiment(class_name, name, arginfo)
def string_to_hdf5(f, key, value): def string_to_hdf5(f, key, value):