Skip to content

Commit

Permalink
Add margin symbols for context errors
Browse files Browse the repository at this point in the history
Also added a warning dialog that appears when the user tries to move a ROI when
there's a syntax error in the code (which libcst will fail to parse).
  • Loading branch information
JamesWrigley committed Apr 6, 2022
1 parent f88ed30 commit 65f9619
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 4 deletions.
10 changes: 10 additions & 0 deletions extra_foam/special_suite/correlator_proc.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,17 @@ def send_index(self):
class CorrelatorProcessor(QThreadWorker):
# Emitted when the views are changed
updated_views_sgn = pyqtSignal(dict)

# Emitted when incoming data is processed, only contains paths generated
# from the incoming data (not including e.g. view paths).
updated_data_paths_sgn = pyqtSignal(dict)

# Emitted upon a ContextError
context_error_sgn = pyqtSignal(object)

# Emitted upon a successful reload
reloaded_sgn = pyqtSignal()

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

Expand Down Expand Up @@ -424,16 +431,19 @@ def setContext(self, source: str):
except ContextError as e:
# ContextError's have their own functions for pretty printing
logger.error(e.format_for_context(source))
self.context_error_sgn.emit(e)
return
except Exception as e:
# For all other exceptions we log the traceback and error
logger.error("".join([*traceback.format_tb(e.__traceback__), repr(e)]))
self.context_error_sgn.emit(e)
return

self._next_ctx_version += 1
self._paths = self._ctx.get_paths()
self._pipeline.set_context(self._ctx)

self.reloaded_sgn.emit()
self.log.info("Reloaded")

def close(self, timeout=1):
Expand Down
67 changes: 63 additions & 4 deletions extra_foam/special_suite/correlator_w.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import sys
import time
import textwrap
import itertools
import traceback
import dataclasses
import os.path as osp
from enum import Enum
Expand All @@ -18,10 +20,12 @@
QStackedWidget, QComboBox, QLabel, QAction, QMenu,
QStyle, QTabBar, QToolButton, QFileDialog,
QCheckBox, QGridLayout, QHBoxLayout, QMessageBox,
QTreeWidget, QTreeWidgetItem, QAbstractItemView)
QTreeWidget, QTreeWidgetItem, QAbstractItemView,
QApplication)
from PyQt5.Qsci import QsciScintilla, QsciLexerPython, QsciAbstractAPIs

from metropc.client import ViewOutput
from metropc import error as mpc_error

from .. import ROOT_PATH
from ..utils import RectROI as MetroRectROI
Expand Down Expand Up @@ -974,11 +978,14 @@ def initUI(self):
self._editor.setIndentationsUseTabs(False)
self._editor.setTabWidth(4)
self._editor.setAutoIndent(True)
self._editor.setMarginWidth(0, "0000")
self._editor.setMarginLineNumbers(0, True)
self._editor.setBraceMatching(QsciScintilla.BraceMatch.SloppyBraceMatch)
self._editor.textChanged.connect(self._onContextModified)

self._editor.setMarginWidth(0, "0000")
self._editor.setMarginLineNumbers(0, True)
self._editor.setMarginWidth(1, "0000")
self._editor.setMarginType(1, QsciScintilla.MarginType.SymbolMargin)

self._tab_widget.addTab(self._editor, "Context")

# Add fake tab to add create new tabs
Expand All @@ -997,6 +1004,11 @@ def initUI(self):

self.resize(self._TOTAL_W, self._TOTAL_H)

self._error_marker_nr = 0
self._editor.markerDefine(QsciScintilla.MarkerSymbol.Circle, self._error_marker_nr)
self._editor.setMarkerForegroundColor(FColor.mkColor("r"), self._error_marker_nr)
self._editor.setMarkerBackgroundColor(FColor.mkColor("r"), self._error_marker_nr)

def initConnections(self):
ctrl = self._ctrl_widget_st
worker = self._worker_st
Expand All @@ -1013,10 +1025,41 @@ def initConnections(self):
self._com_ctrl_st.port_changed_sgn.connect(self._onPortChanged)
self._com_ctrl_st.client_type_changed_sgn.connect(self._onClientTypeChanged)

worker.reloaded_sgn.connect(self._clearMarkers)
worker.context_error_sgn.connect(self._onContextError)
worker.updated_views_sgn.connect(self._onViewsUpdated)
worker.updated_data_paths_sgn.connect(self._completer.setDataPaths)
worker.updated_data_paths_sgn.connect(self._ctrl_widget_st.setDataPaths)

def _onContextError(self, error):
self._clearMarkers()

# Find the error line number in the context file
lineno = -1
if isinstance(error, cst.ParserSyntaxError):
lineno = error.raw_line
elif isinstance(error, mpc_error.PathResolutionError):
lineno = error.view.kernel.__code__.co_firstlineno
elif isinstance(error, mpc_error.ViewDefError):
lineno = error._find_context_frame("<ctx>")
elif isinstance(error, mpc_error.ContextSyntaxError):
lineno = error.orig_error.lineno
elif isinstance(error, Exception):
tb = sys.exc_info()[2]
for frame in traceback.extract_tb(tb):
if frame.filename == "<ctx>":
lineno = frame.lineno
break

if lineno == -1:
logger.error(f"Couldn't get line number from {type(error)} for display")
return

handle = self._editor.markerAdd(lineno - 1, self._error_marker_nr)

def _clearMarkers(self):
self._editor.markerDeleteAll()

@property
def context(self):
return self._worker_st._ctx
Expand Down Expand Up @@ -1065,7 +1108,23 @@ def onRoiChanged(self, roi):
raise RuntimeError("Unsupported ROI type")

# Modify the source as needed
module = cstmeta.MetadataWrapper(cst.parse_module(ctx))
try:
module = cstmeta.MetadataWrapper(cst.parse_module(ctx))
except cst.ParserSyntaxError as e:
logger.error(str(e))

marker_exists = self._editor.markerFindNext(e.raw_line - 1, 1) == e.raw_line - 1
if not marker_exists:
self._onContextError(e)
active_window = QApplication.activeWindow()
QMessageBox.warning(active_window,
"Syntax error in context",
"The context file has a syntax error, updating the parameters in the context file will not work until it is fixed.")

return
else:
self._clearMarkers()

transformer = RoiTransformer(roi_cls, roi_name, roi_args)
new_source = module.visit(transformer)

Expand Down

0 comments on commit 65f9619

Please sign in to comment.