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: 141edb521a70
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: 5f7f4ed39824
Choose a head ref
  • 7 commits
  • 5 files changed
  • 1 contributor

Commits on May 20, 2016

  1. Copy the full SHA
    8ab6011 View commit details
  2. dashboard.log -> gui.log

    jordens committed May 20, 2016
    Copy the full SHA
    7a71939 View commit details
  3. gui.log: export LogDock

    jordens committed May 20, 2016
    Copy the full SHA
    e5a75ea View commit details
  4. browser: log stub

    jordens committed May 20, 2016
    Copy the full SHA
    3db1a7c View commit details
  5. browser: log_worker_exception

    jordens committed May 20, 2016
    Copy the full SHA
    9c30f62 View commit details
  6. Copy the full SHA
    af317f9 View commit details
  7. browser: wire up log dock

    jordens committed May 20, 2016
    5
    Copy the full SHA
    5f7f4ed View commit details
Showing with 71 additions and 31 deletions.
  1. +3 −7 artiq/browser/experiments.py
  2. +50 −10 artiq/frontend/artiq_browser.py
  3. +2 −2 artiq/frontend/artiq_dashboard.py
  4. +11 −10 artiq/{dashboard → gui}/log.py
  5. +5 −2 artiq/gui/models.py
10 changes: 3 additions & 7 deletions artiq/browser/experiments.py
Original file line number Diff line number Diff line change
@@ -11,8 +11,7 @@
from artiq.gui.tools import LayoutWidget, log_level_to_name, get_open_file_name
from artiq.gui.entries import argty_to_entry
from artiq.protocols import pyon
from artiq.protocols.sync_struct import process_mod
from artiq.master.worker import Worker
from artiq.master.worker import Worker, log_worker_exception

logger = logging.getLogger(__name__)

@@ -297,10 +296,8 @@ async def _get_run_task(self, expid):
expid=expid, priority=0)
await worker.analyze()
except:
# May happen when experiment has been removed
# from repository/explist
logger.error("Failed to run '%s'",
self.expurl, exc_info=True)
logger.info("Failed to run '%s'", self.expurl)
log_worker_exception()
finally:
await worker.close()

@@ -343,7 +340,6 @@ def get(self, key):

def update(self, mod):
self.datasets_sub.update(mod)
process_mod(self._data, mod)


class ExperimentsArea(QtWidgets.QMdiArea):
60 changes: 50 additions & 10 deletions artiq/frontend/artiq_browser.py
Original file line number Diff line number Diff line change
@@ -5,15 +5,16 @@
import atexit
import os
import logging
from functools import partial

from PyQt5 import QtCore, QtGui, QtWidgets
from quamash import QEventLoop

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.tools import verbosity_args, atexit_register_coroutine
from artiq.gui import state, applets, models, log
from artiq.browser import datasets, files, experiments

from artiq.protocols.logging import SourceFilter

logger = logging.getLogger(__name__)

@@ -67,12 +68,16 @@ def restore_state(self, state):
def main():
# initialize application
args = get_argparser().parse_args()
init_logger(args)

log_sub = models.LocalModelManager(log.Model)
init_log(args, log_sub)

app = QtWidgets.QApplication(["ARTIQ Browser"])
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
atexit.register(loop.close)
loop.call_soon(partial(log_sub.init, []))

smgr = state.StateManager(args.db_file)

datasets_sub = models.LocalModelManager(datasets.Model)
@@ -100,20 +105,23 @@ def main():
d_datasets = datasets.DatasetsDock(datasets_sub)
smgr.register(d_datasets)

d_log = log.LogDock(None, "log", log_sub)
d_log.setFeatures(d_log.DockWidgetMovable | d_log.DockWidgetFloatable)
smgr.register(d_log)

main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, d_files)
main_window.addDockWidget(QtCore.Qt.BottomDockWidgetArea, d_applets)
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, d_datasets)
main_window.addDockWidget(QtCore.Qt.BottomDockWidgetArea, d_log)

toolbar = main_window.addToolBar("Experiment")
toolbar.setObjectName("experiment_toolbar")
toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)

open_action = QtWidgets.QAction("Open Experiment", main_window)
open_action = QtWidgets.QAction("&Open", main_window)
open_action.setIcon(app.style().standardIcon(
QtWidgets.QStyle.SP_DialogOpenButton))
open_action.setShortcuts(QtGui.QKeySequence.Open)
open_action.setStatusTip("Open an experiment")
open_action.triggered.connect(mdi_area.select_experiment)
toolbar.addAction(open_action)
exp_group = main_window.menuBar().addMenu("&Experiment")
exp_group.addAction(open_action)

# load/initialize state
if os.name == "nt":
@@ -132,5 +140,37 @@ def main():

loop.run_until_complete(main_window.exit_request.wait())


class LogBufferHandler(logging.Handler):
def __init__(self, log, *args, **kwargs):
logging.Handler.__init__(self, *args, **kwargs)
self.log = log
self.setFormatter(logging.Formatter("%(name)s:%(message)s"))

def emit(self, record):
if getattr(self.log, "model") is not None:
self.log.model.append((record.levelno, record.source,
record.created, self.format(record)))


def init_log(args, log):
root_logger = logging.getLogger()
root_logger.setLevel(logging.NOTSET) # we use our custom filter only
flt = SourceFilter(logging.WARNING + args.quiet*10 - args.verbose*10,
"browser")
handlers = []
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter(
"%(levelname)s:%(source)s:%(name)s:%(message)s"))
handlers.append(console_handler)

buffer_handler = LogBufferHandler(log)
handlers.append(buffer_handler)

for handler in handlers:
handler.addFilter(flt)
root_logger.addHandler(handler)


if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions artiq/frontend/artiq_dashboard.py
Original file line number Diff line number Diff line change
@@ -12,9 +12,9 @@
from artiq.tools import *
from artiq.protocols.pc_rpc import AsyncioClient
from artiq.gui.models import ModelSubscriber
from artiq.gui import state, applets
from artiq.gui import state, applets, log
from artiq.dashboard import (experiments, shortcuts, explorer,
moninj, datasets, schedule, log)
moninj, datasets, schedule)


def get_argparser():
21 changes: 11 additions & 10 deletions artiq/dashboard/log.py → artiq/gui/log.py
Original file line number Diff line number Diff line change
@@ -188,7 +188,7 @@ def set_freetext(self, freetext):
self.invalidateFilter()


class _LogDock(QDockWidgetCloseDetect):
class LogDock(QDockWidgetCloseDetect):
def __init__(self, manager, name, log_sub):
QDockWidgetCloseDetect.__init__(self, "Log")
self.setObjectName(name)
@@ -215,13 +215,14 @@ def __init__(self, manager, name, log_sub):
QtWidgets.QStyle.SP_ArrowDown))
grid.addWidget(scrollbottom, 0, 3)
scrollbottom.clicked.connect(self.scroll_to_bottom)
newdock = QtWidgets.QToolButton()
newdock.setToolTip("Create new log dock")
newdock.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_FileDialogNewFolder))
# note the lambda, the default parameter is overriden otherwise
newdock.clicked.connect(lambda: manager.create_new_dock())
grid.addWidget(newdock, 0, 4)
if manager:
newdock = QtWidgets.QToolButton()
newdock.setToolTip("Create new log dock")
newdock.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_FileDialogNewFolder))
# note the lambda, the default parameter is overriden otherwise
newdock.clicked.connect(lambda: manager.create_new_dock())
grid.addWidget(newdock, 0, 4)
grid.layout.setColumnStretch(2, 1)

self.log = QtWidgets.QTreeView()
@@ -345,7 +346,7 @@ def create_new_dock(self, add_to_area=True):
n += 1
name = "log" + str(n)

dock = _LogDock(self, name, self.log_sub)
dock = LogDock(self, name, self.log_sub)
self.docks[name] = dock
if add_to_area:
self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
@@ -375,7 +376,7 @@ def restore_state(self, state):
if self.docks:
raise NotImplementedError
for name, dock_state in state.items():
dock = _LogDock(self, name, self.log_sub)
dock = LogDock(self, name, self.log_sub)
self.docks[name] = dock
dock.restore_state(dock_state)
self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
7 changes: 5 additions & 2 deletions artiq/gui/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from PyQt5 import QtCore

from artiq.protocols.sync_struct import Subscriber
from artiq.protocols.sync_struct import Subscriber, process_mod


class ModelManager:
@@ -33,12 +33,15 @@ def __init__(self, model_factory):
self.notify_cbs = []

def update(self, mod):
process_mod(self.model, mod)
for notify_cb in self.notify_cbs:
notify_cb(mod)

def init(self, struct):
self._create_model(struct)
self.update({"action": "init", "struct": struct})
mod = {"action": "init", "struct": struct}
for notify_cb in self.notify_cbs:
notify_cb(mod)


class _SyncSubstruct: