#!/usr/bin/env python
# ###########################################################################
#
# This file is part of Taurus
#
# http://taurus-scada.org
#
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
#
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus. If not, see <http://www.gnu.org/licenses/>.
#
# ###########################################################################
"""This module provides a set of dialog based widgets
"""
import sys
from taurus.external.qt import Qt
from taurus.core.util.excepthook import BaseExceptHook
from taurus.core.util.log import LogExceptHook
from taurus.core.util.wrap import wraps
__docformat__ = "restructuredtext"
[docs]
class TaurusMessageBox(Qt.QDialog):
"""A panel intended to display a taurus error.
Example::
dev = taurus.Device("sys/tg_test/1")
try:
print(dev.read_attribute("throw_exception"))
except PyTango.DevFailed, df:
msgbox = TaurusMessageBox()
msgbox.show()
You can show the error outside the exception handling code. If you do this,
you should keep a record of the exception information as given by
:func:`sys.exc_info`::
dev = taurus.Device("sys/tg_test/1")
exc_info = None
try:
print(dev.read_attribute("throw_exception"))
except PyTango.DevFailed, df:
exc_info = sys.exc_info()
if exc_info:
msgbox = TaurusMessageBox(*exc_info)
msgbox.show()
"""
def __init__(
self,
err_type=None,
err_value=None,
err_traceback=None,
parent=None,
designMode=False,
):
Qt.QDialog.__init__(self, parent)
layout = Qt.QVBoxLayout()
self.setLayout(layout)
import taurus.qt.qtgui.panel
MsgPanel = taurus.qt.qtgui.panel.TaurusMessagePanel
self._panel = MsgPanel(
err_type, err_value, err_traceback, self, designMode
)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self._panel)
self.panel().buttonBox().accepted.connect(self.accept)
self._panel.toggledDetails.connect(self._onShowDetails)
def _onShowDetails(self, show):
self.adjustSize()
[docs]
def panel(self):
"""Returns the :class:`taurus.qt.qtgui.panel.TaurusMessagePanel`.
:return: the internal panel
:rtype: taurus.qt.qtgui.panel.TaurusMessagePanel
"""
return self._panel
[docs]
def setIconPixmap(self, pixmap):
"""Sets the icon to the dialog
:param pixmap: the icon pixmap
:type pixmap: PyQt5.Qt.QPixmap
"""
self._panel.setIconPixmap(pixmap)
[docs]
def setText(self, text):
"""Sets the text of the dialog
:param text: the new text
:type text: str
"""
self._panel.setText(text)
[docs]
def getText(self):
"""Returns the current text of this panel
:return: the text for this panel
:rtype: str
"""
return self._panel.getText()
[docs]
def setDetailedText(self, text):
"""Sets the detailed text of the dialog
:param text: the new text
:type text: str
"""
self._panel.setDetailedText(text)
[docs]
def setError(self, err_type=None, err_value=None, err_traceback=None):
"""Sets the exception object.
Example usage::
dev = taurus.Device("sys/tg_test/1")
exc_info = None
msgbox = TaurusMessageBox()
try:
print(dev.read_attribute("throw_exception"))
except PyTango.DevFailed, df:
exc_info = sys.exc_info()
if exc_info:
msgbox.setError(*exc_info)
msgbox.show()
:param err_type: the exception type of the exception being handled (a
class object)
:type error: class object
:param err_value: exception object
:type err_value: object
:param err_traceback: a traceback object which encapsulates the call
stack at the point where the exception originally occurred
:type err_traceback: TracebackType
"""
self._panel.setError(err_type, err_value, err_traceback)
_PROTECT_MESSAGE_BOX = None
def _ProtectMessageBox(
err_type=None, err_value=None, err_traceback=None, parent=None
):
global _PROTECT_MESSAGE_BOX
box = _PROTECT_MESSAGE_BOX
if box is None:
_PROTECT_MESSAGE_BOX = box = TaurusMessageBox(
err_type=err_type,
err_value=err_value,
err_traceback=err_traceback,
parent=parent,
)
box.panel().setCheckBoxVisible(True)
else:
box.setError(
err_type=err_type, err_value=err_value, err_traceback=err_traceback
)
if box.panel().checkBoxState() == Qt.Qt.Checked:
return
return box
[docs]
def protectTaurusMessageBox(fn):
"""The idea of this function is to be used as a decorator on any method
you which to protect against exceptions. The handle of the exception is to
display a :class:`TaurusMessageBox` with the exception information.
Example::
@protectTaurusMessgeBox
def turnBeamOn(device_name):
d = taurus.Device(device_name)
d.TurnOn()
"""
@wraps(fn)
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs)
except Exception:
msgbox = _ProtectMessageBox(*sys.exc_info())
if msgbox is None:
return
msgbox.exec_()
return wrapped
[docs]
class ProtectTaurusMessageBox(object):
"""The idea of this class is to be used as a decorator on any method
you which to protect against exceptions. The handle of the exception is to
display a :class:`TaurusMessageBox` with the exception information. The
optional parameter title gives the window bar a customized title. The
optional parameter msg allows you to give a customized message in the
dialog. Example::
@ProtectTaurusMessgeBox(title="Error trying to turn the beam on")
def turnBeamOn(device_name):
d = taurus.Device(device_name)
d.TurnOn()
"""
def __init__(self, title=None, msg=None):
self._title = title
self._msg = msg
def __call__(self, fn):
@wraps(fn)
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs)
except Exception:
msgbox = _ProtectMessageBox(*sys.exc_info())
if msgbox is None:
return
if self._title is not None:
msgbox.setWindowTitle(self._title)
if self._msg is not None:
msgbox.setText(self._msg)
msgbox.exec_()
return wrapped
[docs]
class TaurusExceptHookMessageBox(BaseExceptHook):
"""A callable class that acts as an excepthook that displays an unhandled
exception in a :class:`~taurus.qt.qtgui.dialog.TaurusMessageBox`.
:param hook_to: callable excepthook that will be called at the end of this
hook handling [default: None]
:type hook_to: callable
:param title: message box title [default: None meaning use exception value]
:type name: str
:param msg: message box text [default: None meaning use exception]
"""
MSG_BOX = None
def __init__(self, hook_to=None, title=None, msg=None):
BaseExceptHook.__init__(self, hook_to=hook_to)
self._title = title
self._msg = msg
def _getMessageBox(
self, err_type=None, err_value=None, err_traceback=None, parent=None
):
box = self.__class__.MSG_BOX
if box is None:
self.__class__.MSG_BOX = box = TaurusMessageBox(
err_type=err_type,
err_value=err_value,
err_traceback=err_traceback,
parent=parent,
)
box.panel().setCheckBoxVisible(True)
else:
box.setError(
err_type=err_type,
err_value=err_value,
err_traceback=err_traceback,
)
if box.panel().checkBoxState() == Qt.Qt.Checked:
return
return box
[docs]
def report(self, *exc_info):
app = Qt.QApplication.instance()
if app is None:
LogExceptHook().report(*exc_info)
return
msgbox = self._getMessageBox(*exc_info)
if msgbox is None:
return
if self._title is not None:
msgbox.setWindowTitle(self._title)
if self._msg is not None:
msgbox.setText(self._msg)
msgbox.exec_()
class DemoException(Exception):
pass
def s1():
return s2()
def s2():
return s3()
def s3():
raise DemoException("A demo exception occurred")
def py_exc():
try:
s1()
except Exception:
msgbox = TaurusMessageBox(*sys.exc_info())
msgbox.exec_()
def tg_exc():
import PyTango # TODO: tango-centric
try:
PyTango.Except.throw_exception(
"TangoException", "A simple tango exception", "right here"
)
except PyTango.DevFailed:
msgbox = TaurusMessageBox(*sys.exc_info())
msgbox.exec_()
def tg_serv_exc():
import PyTango # TODO: tango-centric
import taurus
dev = taurus.Device("sys/tg_test/1")
try:
dev.read_attribute("throw_exception")
except PyTango.DevFailed:
msgbox = TaurusMessageBox(*sys.exc_info())
msgbox.exec_()
except Exception:
msgbox = TaurusMessageBox(*sys.exc_info())
msgbox.exec_()
def py_tg_serv_exc():
import PyTango # TODO: tango-centric
try:
PyTango.Except.throw_exception(
"TangoException", "A simple tango exception", "right here"
)
except PyTango.DevFailed as df1:
try:
import traceback
import io
origin = io.StringIO()
traceback.print_stack(file=origin)
origin.seek(0)
origin = origin.read()
PyTango.Except.re_throw_exception(
df1,
"PyDs_Exception",
"DevFailed: A simple tango " "exception",
origin,
)
except PyTango.DevFailed:
msgbox = TaurusMessageBox(*sys.exc_info())
msgbox.exec_()
def demo():
"""Message dialog"""
panel = Qt.QWidget()
layout = Qt.QVBoxLayout()
panel.setLayout(layout)
m1 = Qt.QPushButton("Python exception")
layout.addWidget(m1)
m1.clicked.connect(py_exc)
m2 = Qt.QPushButton("Tango exception")
layout.addWidget(m2)
m2.clicked.connect(tg_exc)
layout.addWidget(m2)
m3 = Qt.QPushButton("Tango server exception")
layout.addWidget(m3)
m3.clicked.connect(tg_serv_exc)
layout.addWidget(m3)
m4 = Qt.QPushButton("Python tango server exception")
layout.addWidget(m4)
m4.clicked.connect(py_tg_serv_exc)
layout.addWidget(m4)
panel.show()
return panel
def main():
import taurus.qt.qtgui.application
Application = taurus.qt.qtgui.application.TaurusApplication
app = Application.instance()
owns_app = app is None
if owns_app:
app = Qt.QApplication([])
app.setApplicationName("Taurus message demo")
app.setApplicationVersion("1.0")
w = demo()
if owns_app:
sys.exit(app.exec_())
else:
return w
if __name__ == "__main__":
main()