sendelogsls.py uses bdbase.sendelogframe.py

This commit is contained in:
2022-10-24 08:12:47 +02:00
parent a332aecd87
commit 87def4961c
4 changed files with 460 additions and 19 deletions

40
base.py
View File

@@ -5,6 +5,7 @@ from collections import OrderedDict
from datetime import datetime
import getpass
import h5py
import logging
import inspect
import platform
import os
@@ -29,7 +30,7 @@ from pyqtacc.bdbase.helpbrowser import HelpBrowser
from pyqtacc.bdbase.readjson import ReadJSON
from pyqtacc.bdbase.savehdf import QSaveHDF
from pyqtacc.bdbase.hdf5filemenu import HDF5GroupBox
from pyqtacc.bdbase.sendelog import QSendToELOG
from pyqtacc.bdbase.screenshot import QScreenshot
from pyqtacc.bdbase.guiframe import GUIFrame
@@ -331,7 +332,8 @@ class BaseWindow(QMainWindow):
self.facility = facility
self.user_mode = user_mode
self.appname, self.appext = self.pymodule.split(".")
print("=============================================")
print("Starting {0} at: {1}".format(self.appname, datetime.now()))
print("User: {0} Host: {1}".format(os.getlogin(), os.uname()[1]))
@@ -340,6 +342,8 @@ class BaseWindow(QMainWindow):
self.settings = ReadJSON(self.appname)
#Read out current_logbook
self.cafe = PyCafe.CyCafe()
self.cyca = PyCafe.CyCa()
self.cafe_exception = PyCafe.CafeException
@@ -390,6 +394,12 @@ class BaseWindow(QMainWindow):
self.stdlog_dest = (self.settings.data["stdlog"]["destination"] +
self.appname + "-" + os.getlogin() + ".log")
self.logging = logging
#self.logging.basicConfig(filename=self.stdlog_dest, level=logging.DEBUG)
self.logging.basicConfig(level=logging.DEBUG)
self.logger = self.logging.getLogger(__name__)
self.logger.info("Logging activated")
self.date_str = None
self.autopost_elog = True
@@ -492,8 +502,10 @@ class BaseWindow(QMainWindow):
if self.facility == Facility.SwissFEL:
from pyqtacc.sf.guiheader import GUIHeader
from pyqtacc.bdbase.sendelog import QSendToELOG
elif self.facility == Facility.SLS:
from pyqtacc.sls.guiheader import GUIHeader
from pyqtacc.sls.sendelog import QSendToELOG
self.gui_header = GUIHeader(self, user_mode=self.user_mode,
extended=extended)
@@ -553,7 +565,7 @@ class BaseWindow(QMainWindow):
if self.settings.data["Parameters"][key]["flag"]:
self.input_parameters[key] = val
self.all_input_parameters[key] = val
self.all_input_parameters[key] = val
#print("val=",val, key)
except KeyError as e:
@@ -599,8 +611,8 @@ class BaseWindow(QMainWindow):
if self.settings.data["Expert"][key]["flag"]:
self.expert_parameters[key] = val
self.all_expert_parameters[key] = val
#print("val=",val, key)
self.all_expert_parameters[key] = val
#print("val=",val, key)
except KeyError as e:
print("Key Error in base.py initialization:", e)
@@ -841,7 +853,7 @@ class BaseWindow(QMainWindow):
"""
#Close all dock widgets
#self.removeDockWidget(self.hdf_dock_widget)
self.logger.info("Closing Application")
self.save_application_settings()
QApplication.processEvents()
self.cafe.monitorStopAll()
@@ -1716,18 +1728,26 @@ class BaseWindow(QMainWindow):
@Slot(dict)
def receive_analysis_results(self, all_dict):
print("receive analysis results===>")
self.all_data = all_dict
self.gui_frame.canvas_update(all_dict['Figure data'])
print("here")
if self.gui_frame.results_output_wgt_dict:
#all_dict['Processed data']['Results']={}
#all_dict['Processed data']['Results']['mean'] = 123.23
#all_dict['Processed data']['Results']['SD'] = 0.23
try:
results_data = all_dict['Processed data']['Results']
self.gui_frame.send_to_results_output_wgt(results_data)
except:
pass
self.gui_frame.central_tab_widget.setCurrentIndex(1)
self.gui_frame.results_tab_wgt.setCurrentIndex(0)
self.gui_frame.results_tab_wgt.setCurrentIndex(0)
@Slot()
def receive_abort_analysis(self):
"""Instantiate action on abort
"""
print("Aborting", flush=True)
if self.analysis_procedure.abort:
return
self.gui_frame.in_abort_procedure()

View File

@@ -18,6 +18,7 @@ class Facility(IntEnum):
PSI = 0
SwissFEL = 1
SLS = 2
HIPA = 3
class MsgSeverity(IntEnum):
""" For use with message logger

View File

@@ -17,7 +17,7 @@ from qtpy.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QFrame,
QStackedWidget, QTabBar, QTabWidget, QToolButton,
QVBoxLayout, QWidget)
from caqtwidgets.pvwidgets import (CAQLabel, CAQTableWidget, QMessageWidget,
QHLine)
QHLine, QVLine)
from pyqtacc.bdbase.enumkind import Facility, MsgSeverity, UserMode
@@ -61,6 +61,8 @@ class GUIFrame(QWidget):
self.all_expert_parameters = parent.all_expert_parameters
self.all_expert_labels = parent.all_expert_labels
self.results_output_wgt_dict = {}
try:
self.widget_height = self.settings.data["StyleGuide"][
"widgetHeight"]
@@ -75,6 +77,7 @@ class GUIFrame(QWidget):
self.expert_parameters_group = None
self.operator_parameters_group = None
self.output_parameters_wgt = None
self.optics_group = None
self.energy_stacked_widget = None
@@ -268,6 +271,76 @@ class GUIFrame(QWidget):
self.optics_group.cycle_quads = None
return self.optics_group
def output_parameters_group(self, title="Results Output"):
""" Generic group box for user supplied input
"""
self.output_parameters_wgt = QWidget()
qtop = QVBoxLayout()
self.output_parameters_group_box = QGroupBox(title)
self.output_parameters_group_box.setObjectName("OUTER")
vbox = QVBoxLayout()
vbox.setContentsMargins(9, 19, 9, 9)
vbox.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
keys = self.settings.data["Results"].keys()
max_str_len = 4
for key in keys:
if len(key) > max_str_len:
max_str_len = len(key)
for key in keys:
ikey = self.settings.data["Results"][key]
if ikey['flag']:
_widget = ikey["data"]["widget"].upper()
_text = ikey["data"]["text"]
_value = str(ikey["data"]["value"])
_width = int(ikey["data"]["width"])
if _widget == "QLINEEDIT":
ql = QLabel(str(_text))
_label_width = (ql.fontMetrics().averageCharWidth() *
max_str_len+2)
ql.setMinimumWidth(_label_width)
ql.setFixedHeight(self.widget_height)
ql.setFont(self.font_pts10)
wgt = QLineEdit()
wgt.setFixedWidth(_width)
wgt.setObjectName("ReadRight")
wgt.setFixedHeight(self.widget_height)
wgt.setFont(self.font_pts10)
wgt.setAlignment(Qt.AlignRight)
self.results_output_wgt_dict[key] = wgt
if "NONE" not in _value.upper():
self.results_output_wgt_dict[key].setText(_value)
hbox = QHBoxLayout()
hbox.setContentsMargins(0, 0, 0, 0)
hbox.addWidget(ql)
hbox.addWidget(wgt)
hbox.setAlignment(Qt.AlignLeft)
vbox.addLayout(hbox)
self.output_parameters_group_box.setContentsMargins(9, 19, 9, 9)
self.output_parameters_group_box.setMinimumWidth(140)
self.output_parameters_group_box.setMaximumWidth(300)
#self.output_parameters_group_box.setMaximumHeight(400)
self.output_parameters_group_box.setFont(self.font_gui)
self.output_parameters_group_box.setAlignment(Qt.AlignTop |
Qt.AlignHCenter)
qf = QFrame()
qf.setFixedHeight(35)
self.output_parameters_group_box.setLayout(vbox)
qtop.addWidget(qf)
qtop.addWidget(self.output_parameters_group_box)
self.output_parameters_wgt.setLayout(qtop)
return self.output_parameters_wgt
def send_to_results_output_wgt(self, results_data):
for key, value in results_data.items():
self.results_output_wgt_dict[key].setText(str(value))
def input_parameters_group(self, title="Input Parameters"):
""" Generic group box for user supplied input
"""
@@ -309,11 +382,12 @@ class GUIFrame(QWidget):
#print(self.input_parameters)
checkbox = QCheckBox(text)
checkbox.setToolTip(tip)
checkbox.setFont(self.font_gui)
checkbox.stateChanged.connect(on_checkbox_change)
#checkbox.setFixedHeight(30)
#checkbox.setLayoutDirection(Qt.RightToLeft)
checked_value = default_value
if key in self.parent.input_parameters.keys():
if "data" in self.settings.data[top_key][key].keys():
@@ -564,6 +638,13 @@ class GUIFrame(QWidget):
for table in self.table_wgt:
table.init_value_button.setEnabled(False)
table.restore_value_button.setEnabled(False)
if self.output_parameters_wgt is not None:
for wgt in self.results_output_wgt_dict.values():
wgt.setText("")
#self.output_parameters_wg.setEnabled(False)
def in_abort_procedure(self):
self.abort_wgt.setEnabled(False)
@@ -585,6 +666,8 @@ class GUIFrame(QWidget):
for table in self.table_wgt:
table.init_value_button.setEnabled(True)
table.restore_value_button.setEnabled(True)
#if self.output_parameters_wgt is not None:
# self.output_parameters_wgt.setEnabled(True)
def in_hdf_measurement_procedure(self):
self.parent.h5_groupbox.analyze_h5_widget.setEnabled(False)
@@ -748,7 +831,7 @@ class GUIFrame(QWidget):
except KeyError as error:
print(("KeyError in guiframe.py; Unknown key {0} " +
"in def checkbox_wgt: {1}").format(key, error))
text = key
text = key
checkbox = QCheckBox(text)
checkbox.setToolTip(tooltip)
@@ -756,6 +839,7 @@ class GUIFrame(QWidget):
if object_name:
checkbox.setObjectName(object_name)
checkbox.setLayoutDirection(Qt.LeftToRight) #is default
checkbox.stateChanged.connect(on_change)
checked_value = Qt.Unchecked
@@ -1319,6 +1403,8 @@ class GUIFrame(QWidget):
self.line_sender_dict[item].setText(str(value_list))
line = self.radio_buttons(key=key, options=value)
line.setContentsMargins(0, 0, 0, 0)
rblist = line.findChildren(QRadioButton)
for rb in rblist:
@@ -1326,6 +1412,7 @@ class GUIFrame(QWidget):
wgt_grid.addWidget(line, irow, 0, 1, 4, Qt.AlignLeft)
rblist[0].setChecked(True)
rblist[0].toggled.emit(True)
@@ -1340,10 +1427,26 @@ class GUIFrame(QWidget):
line.setChecked(Qt.Checked if value else Qt.Unchecked)
line.stateChanged.connect(check_cb)
line.setMaximumWidth(320)
line.setMinimumWidth(220)
line.setMinimumWidth(100)
line.setFixedHeight(28)
if key in self.settings.data["Expert"].keys():
top_key = "Expert"
elif key in self.settings.data["Parameters"].keys():
top_key = "Parameters"
wgt_grid.addWidget(line, irow, 0, 1, 4, Qt.AlignLeft | Qt.AlignVCenter)
col_wdt = 4
try:
orientation = self.settings.data[top_key][key]["data"]["orientation"]
orientation = Qt.RightToLeft if "RightToLeft" in orientation \
else Qt.LeftToRight
line.setLayoutDirection(orientation)
col_wdt=3
except KeyError:
pass
wgt_grid.addWidget(line, irow, 0, 1, col_wdt, Qt.AlignLeft | Qt.AlignVCenter)
return line
@@ -1488,7 +1591,10 @@ class GUIFrame(QWidget):
wgt_grid.addWidget(qFrame, irow, 0, 1, 4)
def input_wgt(self, buddy, label, key, value, irow=0, wgt_grid=None):
def input_wgt(self, buddy, label, key, value, irow=0, wgt_grid=None,):
if "QVLINE" in buddy:
print("QVLine", label, key, value)
if wgt_grid is None:
wgt_grid = self.input_wgt_grid
@@ -1581,12 +1687,21 @@ class GUIFrame(QWidget):
except KeyError:
pass
def draw_widget(buddy):
flag = self.settings.data["Parameters"][key]["flag"]
if buddy == "NONE":
return False
elif buddy not in ["QHLINE", "QFRAME"] and not flag:
return False
return True
for (key, val), label in zip(self.all_input_parameters.items(),
self.all_input_labels.values()):
buddy = self.settings.data[
"Parameters"][key]["data"]["widget"].upper()
j = self.input_wgt_grid.rowCount()
if buddy != "NONE":
#if buddy != "NONE":
if draw_widget(buddy):
self.input_wgt(buddy=buddy, label=label, key=key, value=val,
irow=j, wgt_grid=self.input_wgt_grid)
@@ -1697,7 +1812,7 @@ class GUIFrame(QWidget):
widget = QWidget()
layout = QGridLayout()
layout.setContentsMargins(5, 0, 5, 0)
widget.setFixedWidth(220)
widget.setMaximumWidth(220)
#self.setLayout(layout)
target_list = options
@@ -1715,7 +1830,7 @@ class GUIFrame(QWidget):
elif key in self.settings.data["Parameters"].keys():
top_key = "Parameters"
_width = 1
_width = 1
_full_width = _width * len(options) + 1
layout.addWidget(QHLine(), 0, 0, 1, _full_width)

305
sendelogframe.py Normal file
View File

@@ -0,0 +1,305 @@
import getpass
import inspect
import os
import time
from qtpy.QtCore import Qt
from qtpy.QtWidgets import (QComboBox, QDialog, QFileDialog, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QTextEdit,
QVBoxLayout)
import elog # https://github.com/paulscherrerinstitute/py_elog
from pyqtacc.bdbase.enumkind import MsgSeverity
_version = "1.0.0"
_pymodule = os.path.basename(__file__)
_appname, _appext = _pymodule.split(".")
def _line():
"""Macro to return the current line number.
The current line number within the file is used when
reporting messages to the message logging window.
Returns:
int: Current line number.
"""
return inspect.currentframe().f_back.f_lineno
class QSendToELOGFrame(QDialog):
""" Graphical interface to elog
"""
def __init__(self, parent, logbook=None, title=None, message=None,
attachFile=None, destination_folder=None):
super().__init__()
self.files_text = ''
self.fflag = False
self.parent = parent
if destination_folder is None:
self.destination = self.parent.elog_dest + " / " + self.parent.appname
else:
self.destination = destination_folder
self.window_title = self.parent.appname + ": " + _appname
self.pymodule = _pymodule
self.setWindowTitle(self.window_title)
elog_books = list(self.parent.settings.data["ElogBooks"])
self.elog_items = QComboBox()
self.elog_items.addItems(elog_books)
self.elog_items.currentIndexChanged.connect(self.on_elog_change)
idx = 0
if logbook is not None:
try:
idx = elog_books.index(logbook)
except Exception:
mess = "Index not found for logbook {0}".format(logbook)
self.parent.show_log_message(MsgSeverity.WARN, self.pymodule,
_line(), mess)
else:
logbook = self.parent.settings.data["Elog"]["book"]
try:
idx = elog_books.index(logbook)
except Exception:
mess = "Index not found for logbook {0}".format(logbook)
self.parent.show_log_message(MsgSeverity.WARN, self.pymodule,
_line(), mess)
self.logbook = logbook
print("logbook===>", self.logbook)
self.elog_items.setCurrentIndex(idx)
self.elog_items.currentIndexChanged.emit(idx)
self.elog_items.setObjectName("Elog")
self.title_items = QHBoxLayout()
self.title_items.addWidget(QLabel('Title: '))
self.titleline = QLineEdit()
self.titleline.setObjectName('Elog')
#self.titleline.setStatusTip('elog')
if title is None:
title = self.parent.appname
self.titleline.setText(str(title))
self.titleline.setFixedWidth(300)
self.titleline.setAlignment(Qt.AlignCenter)
self.title_items.addWidget(self.titleline)
self.applicationbox = QHBoxLayout()
self.applicationbox.addWidget(QLabel('Application:'))
self.applicationlabel = QLabel(self.parent.pymodule)
self.applicationlabel.setObjectName("Elog")
# self.applicationbox.addStretch()
self.applicationbox.addWidget(self.applicationlabel)
logbook = QHBoxLayout()
logbook.addWidget(QLabel('Logbook: '))
logbook.addWidget(self.elog_items)
authorbox = QHBoxLayout()
authorbox.addWidget(QLabel('Author: '))
self.author = QLineEdit()
self.author.setObjectName('Elog')
self.author.setFixedWidth(195)
self.author.setStatusTip('elog')
self.author.setText(getpass.getuser())
authorbox.addWidget(self.author)
self.files = []
self.attributes = {}
self.layout = QVBoxLayout(self)
self.layout.addLayout(logbook)
self.layout.addLayout(self.applicationbox)
self.layout.addLayout(authorbox)
self.layout.addLayout(self.title_items)
report = QLabel('Report: ')
self.layout.addWidget(report)
self.message = QTextEdit(message)
self.layout.addWidget(self.message)
filebox = QHBoxLayout()
qlfile = QLabel('Attach:')
qlfile.setAlignment(Qt.AlignTop)
filebox.addWidget(qlfile)
self.filesE = QTextEdit()
self.filesE.setAlignment(Qt.AlignTop)
self.filesE.setFixedHeight(80)
self.filesE.setReadOnly(True)
self.attachFile = attachFile
if self.attachFile is not None:
_attachFile = []
if isinstance(self.attachFile, str):
_attachFile.append(self.attachFile)
elif isinstance(self.attachFile, list):
_attachFile = self.attachFile
for i, file in enumerate(_attachFile):
_attach_base = os.path.basename(file)
if i > 0:
self.files_text += "\n"
self.files_text += str(_attach_base)
self.filesE.setText(self.files_text)
self.fflag = True
filebox.addWidget(self.filesE)
openCloseVBox = QVBoxLayout()
self.openBtn = QPushButton('Add')
self.openBtn.setAutoDefault(False)
self.openBtn.clicked.connect(self.openFiles)
openCloseVBox.addWidget(self.openBtn)
closeBtn = QPushButton('Clear')
closeBtn.setAutoDefault(False)
closeBtn.clicked.connect(self.clearFiles)
openCloseVBox.addWidget(closeBtn)
filebox.addLayout(openCloseVBox)
self.layout.addLayout(filebox)
btnLayout = QHBoxLayout()
self.okBtn = QPushButton('Send')
self.okBtn.setAutoDefault(False)
self.okBtn.clicked.connect(self.ok)
self.cancelBtn = QPushButton('Cancel')
self.cancelBtn.setAutoDefault(False)
self.cancelBtn.clicked.connect(self.close)
btnLayout.addWidget(self.okBtn)
btnLayout.addWidget(self.cancelBtn)
self.messagelbl = QLabel('')
self.messagelbl.setStyleSheet("QLabel { color : red; }")
self.layout.addWidget(self.messagelbl)
self.layout.addLayout(btnLayout)
print("logbook5", logbook)
self.setMinimumWidth(440)
#self.exec()
def on_elog_change(self, elog_change_val):
if "test" in self.elog_items.currentText():
_bgcolor = "QComboBox {background: plum; color : black;}"
else:
_bgcolor = "QComboBox {background: lightblue; color : black;}"
self.elog_items.setStyleSheet(_bgcolor)
def ok(self):
message = self.message.document().toPlainText()
if not message:
self.messagelbl.setText('Please enter a brief Report')
return
title = self.titleline.text()
if not title:
self.messagelbl.setText('Titel attribute is required')
return
author = self.author.text()
application = self.applicationlabel.text()
self.attributes['Autor'] = author
self.attributes['Author'] = author
self.attributes['Application'] = application
self.attributes['Titel'] = title
self.attributes['Title'] = title
self.attributes['When'] = str(time.time())
self.attributes['Wann'] = str(time.time())
if self.attachFile is not None:
_attachFile = []
if isinstance(self.attachFile, str):
_attachFile.append(self.attachFile)
elif isinstance(self.attachFile, list):
_attachFile = self.attachFile
for i in range(0, len(_attachFile)):
if "/tmp" in _attachFile[i]:
self.files.append(str(_attachFile[i]))
elif "/afs/psi.ch" in _attachFile[i]:
self.files.append(str(_attachFile[i]))
elif "/sls/bd/data/" in _attachFile[i]:
self.files.append(str(_attachFile[i]))
else:
self.files.append(self.destination + str(_attachFile[i]))
el = self.elog_items.currentText()
print("el==============>", el)
url = self.parent.settings.data["ElogBooks"][el]["url"]
self.logbook = elog.open(url, user='robot', password='robot')
print("sendelogframe.py========>: ", url, flush=True)
print(message, flush=True)
try:
if self.files:
self.logbook.post(message, attributes=self.attributes,
attachments=self.files)
else:
self.logbook.post(message, attributes=self.attributes)
#self.trigger_elog_entry.emit(True, url, "OK")
self.receive_elog_notification(True, url, "OK")
except Exception as ex:
#self.trigger_elog_entry.emit(False, url, str(ex))
print("Exception in sendelog.py", str(ex))
self.receive_elog_notification(False, url, str(ex))
#for file in self.files:
# if os.path.exists(file):
# os.remove(file)
self.close()
def clearFiles(self):
self.attachFile = []
self.filesE.clear()
self.files = []
self.files_text = ''
self.fflag = False
def openFiles(self):
# Notethat openFiles also gets called when qDialog cacnel is clicked!
qFileDialog = QFileDialog()
extensions = ("Images (*.bmp *.eps *.gif *.jpeg *.jpg *.pdf *.png " +
"*.ps *.tiff *.xpm);;Text files (*.txt *.text);;" +
"JSON/XML files (*.json *.xml)")
flocal = qFileDialog.getOpenFileNames(
self, 'Open File', self.destination, extensions)[0]
if not flocal:
return
self.files.append(flocal[0])
if self.fflag:
self.files_text += '\n'
self.files_text += str(flocal[0].split('/')[-1])
self.fflag = True
self.filesE.setText(self.files_text)
def receive_elog_notification(self, is_accepted, logbook_url, elog_message):
'''Receive notification from ELOG, and report to log window'''
yes_no = "made" if is_accepted else "failed"
mess = "Entry into ELOG: {0} {1}".format(logbook_url, yes_no)
if is_accepted:
self.parent.show_log_message(MsgSeverity.INFO, self.pymodule,
_line(), mess)
else:
mess += ".\n" + elog_message
self.parent.show_log_message(MsgSeverity.WARN, self.pymodule,
_line(), mess)
self.parent.statusbar.showMessage(mess)