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: 6ee0f65b120a
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: dd349b0701cc
Choose a head ref
  • 6 commits
  • 7 files changed
  • 1 contributor

Commits on Jul 3, 2016

  1. Copy the full SHA
    4c8a835 View commit details
  2. Copy the full SHA
    fdc2577 View commit details
  3. Copy the full SHA
    cc9edc1 View commit details
  4. browser: log runs

    sbourdeauducq committed Jul 3, 2016
    Copy the full SHA
    0173a40 View commit details
  5. Copy the full SHA
    77f60a3 View commit details
  6. Copy the full SHA
    dd349b0 View commit details
Showing with 81 additions and 13 deletions.
  1. +42 −2 artiq/browser/datasets.py
  2. +3 −0 artiq/browser/experiments.py
  3. +3 −5 artiq/dashboard/datasets.py
  4. +14 −3 artiq/frontend/artiq_browser.py
  5. +12 −1 artiq/frontend/artiq_client.py
  6. +6 −1 artiq/master/databases.py
  7. +1 −1 artiq/master/worker.py
44 changes: 42 additions & 2 deletions artiq/browser/datasets.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import logging
import asyncio

from PyQt5 import QtCore, QtWidgets

from artiq.tools import short_format
from artiq.gui.tools import LayoutWidget
from artiq.gui.models import DictSyncTreeSepModel
from artiq.protocols.pc_rpc import AsyncioClient as RPCClient

# reduced read-only version of artiq.dashboard.datasets

# reduced read-only version of artiq.gui.datasets

logger = logging.getLogger(__name__)


class Model(DictSyncTreeSepModel):
@@ -16,7 +23,7 @@ def convert(self, k, v, column):


class DatasetsDock(QtWidgets.QDockWidget):
def __init__(self, datasets_sub):
def __init__(self, datasets_sub, master_host, master_port):
QtWidgets.QDockWidget.__init__(self, "Datasets")
self.setObjectName("Datasets")
self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable |
@@ -36,9 +43,17 @@ def __init__(self, datasets_sub):
QtWidgets.QAbstractItemView.SingleSelection)
grid.addWidget(self.table, 1, 0)

self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
upload_action = QtWidgets.QAction("Upload dataset to master", self.table)
upload_action.triggered.connect(self.upload_clicked)
self.table.addAction(upload_action)

self.set_model(Model(dict()))
datasets_sub.add_setmodel_callback(self.set_model)

self.master_host = master_host
self.master_port = master_port

def _search_datasets(self):
if hasattr(self, "table_model_filter"):
self.table_model_filter.setFilterFixedString(
@@ -50,6 +65,31 @@ def set_model(self, model):
self.table_model_filter.setSourceModel(self.table_model)
self.table.setModel(self.table_model_filter)

async def _upload_dataset(self, name, value,):
logger.info("Uploading dataset '%s' to master...", name)
try:
remote = RPCClient()
await remote.connect_rpc(self.master_host, self.master_port,
"master_dataset_db")
try:
await remote.set(name, value)
finally:
remote.close_rpc()
except:
logger.error("Failed uploading dataset '%s'",
name, exc_info=True)
else:
logger.info("Finished uploading dataset '%s'", name)

def upload_clicked(self):
idx = self.table.selectedIndexes()
if idx:
idx = self.table_model_filter.mapToSource(idx[0])
key = self.table_model.index_to_key(idx)
if key is not None:
persist, value = self.table_model.backing_store[key]
asyncio.ensure_future(self._upload_dataset(key, value))

def save_state(self):
return bytes(self.table.header().saveState())

3 changes: 3 additions & 0 deletions artiq/browser/experiments.py
Original file line number Diff line number Diff line change
@@ -309,6 +309,7 @@ def done(fut):
self._run_task.add_done_callback(done)

async def _get_run_task(self, expid):
logger.info("Running '%s'...", self.expurl)
worker = Worker(self._area.worker_handlers)
try:
await worker.build(rid=None, pipeline_name="browser",
@@ -318,6 +319,8 @@ async def _get_run_task(self, expid):
except:
logger.error("Failed to run '%s'", self.expurl)
log_worker_exception()
else:
logger.info("Finished running '%s'", self.expurl)
finally:
await worker.close()

8 changes: 3 additions & 5 deletions artiq/dashboard/datasets.py
Original file line number Diff line number Diff line change
@@ -13,12 +13,11 @@


class Editor(QtWidgets.QDialog):
def __init__(self, parent, dataset_ctl, key, value, persist):
def __init__(self, parent, dataset_ctl, key, value):
QtWidgets.QDialog.__init__(self, parent=parent)
self.dataset_ctl = dataset_ctl
self.key = key
self.initial_type = type(value)
self.persist = persist

self.setWindowTitle("Edit dataset")
grid = QtWidgets.QGridLayout()
@@ -39,8 +38,7 @@ def __init__(self, parent, dataset_ctl, key, value, persist):

def accept(self):
value = self.initial_type(self.get_edit_widget_value())
asyncio.ensure_future(self.dataset_ctl.set(
self.key, value, self.persist))
asyncio.ensure_future(self.dataset_ctl.set(self.key, value))
QtWidgets.QDialog.accept(self)

def get_edit_widget(self, initial_value):
@@ -165,7 +163,7 @@ def edit_clicked(self):
logger.error("Cannot edit dataset %s: "
"type %s is not supported", key, t)
return
dialog_cls(self, self.dataset_ctl, key, value, persist).open()
dialog_cls(self, self.dataset_ctl, key, value).open()

def delete_clicked(self):
idx = self.table.selectedIndexes()
17 changes: 14 additions & 3 deletions artiq/frontend/artiq_browser.py
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
from artiq.gui import state, applets, models, log
from artiq.browser import datasets, files, experiments


logger = logging.getLogger(__name__)


@@ -30,14 +31,22 @@ def get_argparser():
parser.add_argument("--browse-root", default="",
help="root path for directory tree "
"(default %(default)s)")
parser.add_argument(
"-s", "--server", default="::1",
help="hostname or IP of the master to connect to "
"when uploading datasets")
parser.add_argument(
"--port", default=3251, type=int,
help="TCP port to use to connect to the master")
parser.add_argument("select", metavar="SELECT", nargs="?",
help="directory to browse or file to load")
verbosity_args(parser)
return parser


class Browser(QtWidgets.QMainWindow):
def __init__(self, datasets_sub, browse_root, select):
def __init__(self, datasets_sub, browse_root, select,
master_host, master_port):
QtWidgets.QMainWindow.__init__(self)

icon = QtGui.QIcon(os.path.join(artiq_dir, "gui", "logo.svg"))
@@ -69,7 +78,8 @@ def __init__(self, datasets_sub, browse_root, select):
self.applets = applets.AppletsDock(self, datasets_sub)
atexit_register_coroutine(self.applets.stop)

self.datasets = datasets.DatasetsDock(datasets_sub)
self.datasets = datasets.DatasetsDock(
datasets_sub, master_host, master_port)

self.log = log.LogDock(None, "log")
self.log.setFeatures(self.log.DockWidgetMovable |
@@ -139,7 +149,8 @@ def main():

smgr = state.StateManager(args.db_file)

main_window = Browser(datasets_sub, args.browse_root, args.select)
main_window = Browser(datasets_sub, args.browse_root, args.select,
args.server, args.port)
widget_log_handler.callback = main_window.log.append_message
smgr.register(main_window)

13 changes: 12 additions & 1 deletion artiq/frontend/artiq_client.py
Original file line number Diff line number Diff line change
@@ -81,6 +81,8 @@ def get_argparser():
help="value in PYON format")
parser_set_dataset.add_argument("-p", "--persist", action="store_true",
help="make the dataset persistent")
parser_set_dataset.add_argument("-n", "--no-persist", action="store_true",
help="make the dataset non-persistent")

parser_del_dataset = subparsers.add_parser(
"del-dataset", help="delete a dataset")
@@ -151,7 +153,16 @@ def _action_delete(remote, args):


def _action_set_dataset(remote, args):
remote.set(args.name, pyon.decode(args.value), args.persist)
if args.persist and args.no_persist:
print("Options --persist and --no-persist cannot be specified "
"at the same time")
sys.exit(1)
persist = None
if args.persist:
persist = True
if args.no_persist:
persist = False
remote.set(args.name, pyon.decode(args.value), persist)


def _action_del_dataset(remote, args):
7 changes: 6 additions & 1 deletion artiq/master/databases.py
Original file line number Diff line number Diff line change
@@ -57,7 +57,12 @@ def update(self, mod):
process_mod(self.data, mod)

# convenience functions (update() can be used instead)
def set(self, key, value, persist=False):
def set(self, key, value, persist=None):
if persist is None:
if key in self.data.read:
persist = self.data.read[key][0]
else:
persist = False
self.data[key] = (persist, value)

def delete(self, key):
2 changes: 1 addition & 1 deletion artiq/master/worker.py
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ def log_worker_exception():


class Worker:
def __init__(self, handlers=dict(), send_timeout=2.0):
def __init__(self, handlers=dict(), send_timeout=10.0):
self.handlers = handlers
self.send_timeout = send_timeout