diff --git a/artiq/browser/files.py b/artiq/browser/files.py index 32b2b1424..4eca7ffa4 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -84,7 +84,7 @@ class ZoomIconView(QtWidgets.QListView): class FilesDock(QtWidgets.QDockWidget): - def __init__(self, datasets, main_window, browse_root="", select=None): + def __init__(self, datasets, exp_manager, browse_root="", select=None): QtWidgets.QDockWidget.__init__(self, "Files") self.setObjectName("Files") self.setFeatures(self.DockWidgetMovable | self.DockWidgetFloatable) @@ -93,7 +93,7 @@ class FilesDock(QtWidgets.QDockWidget): self.setWidget(self.splitter) self.datasets = datasets - self.main_window = main_window + self.exp_manager = exp_manager self.model = QtWidgets.QFileSystemModel() self.model.setFilter(QtCore.QDir.Drives | QtCore.QDir.NoDotAndDotDot | @@ -151,7 +151,7 @@ class FilesDock(QtWidgets.QDockWidget): with f: if "datasets" not in f: return - rd = dict((k, (True, v.value)) for k, v in f["datasets"].items()) + rd = {k: (True, v.value) for k, v in f["datasets"].items()} self.datasets.init(rd) def open_experiment(self, current): @@ -170,6 +170,9 @@ class FilesDock(QtWidgets.QDockWidget): if "expid" not in f: return expid = pyon.decode(f["expid"].value) + expurl = "file:{}@{}".format(expid["class_name"], + expid["file"]) + self.exp_manager.open_experiment(expurl) def select_dir(self, path): if not os.path.exists(path): @@ -185,10 +188,11 @@ class FilesDock(QtWidgets.QDockWidget): return self.model.directoryLoaded.disconnect(scroll_when_loaded) QtCore.QTimer.singleShot( - 100, lambda: - self.rt.scrollTo( + 100, + lambda: self.rt.scrollTo( self.rt.model().mapFromSource(self.model.index(path)), - self.rt.PositionAtCenter)) + self.rt.PositionAtCenter) + ) self.model.directoryLoaded.connect(scroll_when_loaded) idx = self.rt.model().mapFromSource(idx) self.rt.expand(idx) diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index f156f4c6d..ff8264fbf 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -585,3 +585,120 @@ class ExperimentManager: for expurl, dock_state in state["docks"].items(): dock = self.open_experiment(expurl) dock.restore_state(dock_state) + + +class SimpleExperimentManager: + def __init__(self, main_window): + self.main_window = main_window + + self.submission_options = dict() + self.submission_arguments = dict() + + self.open_experiments = dict() + + def get_submission_options(self, expurl): + if expurl in self.submission_options: + return self.submission_options[expurl] + else: + # mutated by _ExperimentDock + options = { + "log_level": logging.WARNING + } + if expurl[:5] == "repo:": + options["repo_rev"] = None + self.submission_options[expurl] = options + return options + + def initialize_submission_arguments(self, expurl, arginfo): + arguments = OrderedDict() + for name, (procdesc, group) in arginfo.items(): + state = argty_to_entry[procdesc["ty"]].default_state(procdesc) + arguments[name] = { + "desc": procdesc, + "group": group, + "state": state # mutated by entries + } + self.submission_arguments[expurl] = arguments + return arguments + + def get_submission_arguments(self, expurl): + if expurl in self.submission_arguments: + return self.submission_arguments[expurl] + else: + if expurl[:5] != "repo:": + raise ValueError("Submission arguments must be preinitialized " + "when not using repository") + arginfo = self.explist[expurl[5:]]["arginfo"] + arguments = self.initialize_submission_arguments(expurl, arginfo) + return arguments + + def open_experiment(self, expurl): + if expurl in self.open_experiments: + dock = self.open_experiments[expurl] + self.main_window.centralWidget().setActiveSubWindow(dock) + return dock + try: + dock = _ExperimentDock(self, expurl) + except: + logger.warning("Failed to create experiment dock for %s, " + "attempting to reset arguments", expurl, + exc_info=True) + del self.submission_arguments[expurl] + dock = _ExperimentDock(self, expurl) + self.open_experiments[expurl] = dock + self.main_window.centralWidget().addSubWindow(dock) + dock.show() + dock.sigClosed.connect(partial(self.on_dock_closed, expurl)) + return dock + + def on_dock_closed(self, expurl): + del self.open_experiments[expurl] + + async def _submit_task(self, *args): + rid = await self.schedule_ctl.submit(*args) + self.main_window.statusBar().showMessage( + "Submitted RID {}".format(rid)) + + def submit(self, expurl): + file, class_name, _ = self.resolve_expurl(expurl) + options = self.get_submission_options(expurl) + arguments = self.get_submission_arguments(expurl) + + argument_values = dict() + for name, argument in arguments.items(): + entry_cls = argty_to_entry[argument["desc"]["ty"]] + argument_values[name] = entry_cls.state_to_value(argument["state"]) + + expid = { + "log_level": options["log_level"], + "file": file, + "class_name": class_name, + "arguments": argument_values, + } + if "repo_rev" in options: + expid["repo_rev"] = options["repo_rev"] + asyncio.ensure_future(self._submit_task(expid)) + + async def compute_arginfo(self, expurl): + file, class_name, use_repository = self.resolve_expurl(expurl) + description = await self.experiment_db_ctl.examine(file, + use_repository) + return description[class_name]["arginfo"] + + def save_state(self): + docks = {expurl: dock.save_state() + for expurl, dock in self.open_experiments.items()} + return { + "options": self.submission_options, + "arguments": self.submission_arguments, + "docks": docks + } + + def restore_state(self, state): + if self.open_experiments: + raise NotImplementedError + self.submission_options = state["options"] + self.submission_arguments = state["arguments"] + for expurl, dock_state in state["docks"].items(): + dock = self.open_experiment(expurl) + dock.restore_state(dock_state) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 4f4cb87e8..2bb8e3ac4 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -12,6 +12,7 @@ from artiq import __artiq_dir__ as artiq_dir from artiq.tools import verbosity_args, init_logger, atexit_register_coroutine from artiq.gui import state, applets, models from artiq.browser import datasets, files +from artiq.dashboard import experiments def get_argparser(): @@ -94,7 +95,9 @@ def main(): status_bar = QtWidgets.QStatusBar() main_window.setStatusBar(status_bar) - d_files = files.FilesDock(datasets_sub, main_window, args.browse_root, + exp_manager = experiments.SimpleExperimentManager(main_window) + + d_files = files.FilesDock(datasets_sub, exp_manager, args.browse_root, select=args.select) smgr.register(d_files)