Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e8bd24d53997
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 846701316073
Choose a head ref
  • 3 commits
  • 7 files changed
  • 1 contributor

Commits on Dec 6, 2015

  1. Copy the full SHA
    3edf522 View commit details
  2. Copy the full SHA
    1cba685 View commit details
  3. Copy the full SHA
    8467013 View commit details
Showing with 82 additions and 21 deletions.
  1. +2 −1 artiq/frontend/artiq_gui.py
  2. +42 −12 artiq/gui/experiments.py
  3. +21 −3 artiq/master/repository.py
  4. +2 −2 artiq/master/worker.py
  5. +5 −3 artiq/master/worker_impl.py
  6. +2 −0 artiq/protocols/pc_rpc.py
  7. +8 −0 artiq/test/pc_rpc.py
3 changes: 2 additions & 1 deletion artiq/frontend/artiq_gui.py
Original file line number Diff line number Diff line change
@@ -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)
54 changes: 42 additions & 12 deletions artiq/gui/experiments.py
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ def __init__(self, argument):
QtGui.QLineEdit.__init__(self)
self.setText(argument["state"])
def update(text):
argument["state"] = text()
argument["state"] = text
self.textEdited.connect(update)

@staticmethod
@@ -119,7 +119,10 @@ def default_state(procdesc):


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 @@ def __init__(self, arguments):
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 @@ def _get_group(self, name):
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 @@ def __init__(self, manager, expname):
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 @@ def restore_state(self, state):
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 @@ def get_submission_arguments(self, expname):
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 @@ def request_inst_term(self, expname):
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()}
24 changes: 21 additions & 3 deletions artiq/master/repository.py
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
import tempfile
import shutil
import logging
from functools import partial

from artiq.protocols.sync_struct import Notifier
from artiq.master.worker import Worker
@@ -16,15 +17,15 @@ 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))
finally:
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 @@ async def scan(self, new_cur_rev=None):
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):
4 changes: 2 additions & 2 deletions artiq/master/worker.py
Original file line number Diff line number Diff line change
@@ -248,8 +248,8 @@ async def write_results(self, timeout=15.0):
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)
8 changes: 5 additions & 3 deletions artiq/master/worker_impl.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
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):
2 changes: 2 additions & 0 deletions artiq/protocols/pc_rpc.py
Original file line number Diff line number Diff line change
@@ -490,6 +490,8 @@ async def _handle_connection_cr(self, reader, writer):
else:
method = getattr(target, obj["name"])
ret = method(*obj["args"], **obj["kwargs"])
if inspect.iscoroutine(ret):
ret = await ret
obj = {"status": "ok", "ret": ret}
else:
raise ValueError("Unknown action: {}"
8 changes: 8 additions & 0 deletions artiq/test/pc_rpc.py
Original file line number Diff line number Diff line change
@@ -43,6 +43,8 @@ def _blocking_echo(self, target):
try:
test_object_back = remote.echo(test_object)
self.assertEqual(test_object, test_object_back)
test_object_back = remote.async_echo(test_object)
self.assertEqual(test_object, test_object_back)
with self.assertRaises(pc_rpc.RemoteError):
remote.non_existing_method()
remote.terminate()
@@ -68,6 +70,8 @@ async def _asyncio_echo(self, target):
try:
test_object_back = await remote.echo(test_object)
self.assertEqual(test_object, test_object_back)
test_object_back = await remote.async_echo(test_object)
self.assertEqual(test_object, test_object_back)
with self.assertRaises(pc_rpc.RemoteError):
await remote.non_existing_method()
await remote.terminate()
@@ -105,6 +109,10 @@ class Echo:
def echo(self, x):
return x

async def async_echo(self, x):
await asyncio.sleep(0.01)
return x


def run_server():
loop = asyncio.new_event_loop()