Raise errors and display traceback messages from panel dashboards

Question:

When I link widget updates to a function and display the output in a panel, errors that result from updating the widget to a value that the function cannot handle, cause the function to fail silently instead of terminating the execution of the panel and displaying a traceback.

In the following example, x is undefined so when the slider is dragged to 5, the function fails silently and the output value is not updated. If the slider start value is set to 5, the function will raise a NameError as expected and the panel will not be initialized.

import panel as pn

pn.extension()
int_slider = pn.widgets.IntSlider(
    name='Integer Slider', value=1, end=5)

@pn.depends(int_slider.param.value, watch=True)
def print_slider_value(slider_value):
    if slider_value <= 4:
        return slider_value
    else:
        return slider_value * x

pn.Column(int_slider, print_slider_value) #.app('localhost:8888')

I would like errors to be raised when they result from a widget value change, so that it is clear when an error has occured and what happened from the traceback. How can I achieve this with panel? (I saw this issue on debugging mode with pipelines, but couldn’t find anything similar for panels).

I have been trying this in the JupyterLab notebook with the following packages versions

bokeh       1.2.0
panel       0.6.0
param       1.9.1
IPython     6.5.0
jupyter_client  5.2.3
jupyter_core    4.4.0
jupyterlab  1.0.2
notebook    5.6.0
Asked By: joelostblom

||

Answers:

I asked this question on the panel issue tracker and received the response that the errors can be seen in the JS console. On Firefox, you can open this with Ctrl-Shift-k or right click -> inspect element -> console. In Chrome it is Ctrl-Shift-c or right click -> inspect -> console.

This SO answer shows how to embed the console in a div so that it can be displayed together with other elements directly in the app.

Answered By: joelostblom

Hey so I had a similar issue and came up with a "widget" solution to this problem. The idea is you capture the error, format it as an html and then output the error into a widget that is already inside the dashboard.

In the example below you can see that I have a dashboard that will return almost any string you type into it after submit is pressed, the exception is the string "roger". If "roger" is entered into the dashboard a traceback will be presented to the user directly in the notebook/ Panel app itself.

import panel as pn
import traceback as tb
from pygments import highlight
from pygments.lexers import Python3TracebackLexer
from pygments.formatters import HtmlFormatter
pn.extension()

toggle = pn.widgets.Toggle(name='Press Here')
field = pn.widgets.TextInput(placeholder='Type something here . . .', visible=False)
submit = pn.widgets.Button(name='Submit', button_type='primary', visible=False)
out = pn.widgets.StaticText(value='orginal output')

def extract_format_tb_html(e):
    traceback_str = ''.join(tb.format_exception(None, e, e.__traceback__))
    return highlight(traceback_str, Python3TracebackLexer(), HtmlFormatter(noclasses=True))

def myfunc(x):
    if x != 'roger':
        out.value = field.value
    else:
        raise

def test(event):
    try:
        myfunc(field.value)
    except Exception as e:
        out.value = extract_format_tb_html(e)

def callback(target, event):
    if event.new:
        target.visible=True
    else:
        target.visible=False

toggle.link(field, callbacks={'value': callback})
toggle.link(submit, callbacks={'value': callback})
submit.on_click(test)

widget_row = pn.Row(toggle, field, submit)
dashboard = pn.Column(widget_row, out)

dashboard

The result is:

enter image description here

Answered By: itwasthekix

Panel v0.14.0 update

As of version 0.14.0, you can also plug in a simple exception_handler, to show notifications on the client side.

e.g.

import logging
import panel as pn

def exception_handler(ex):
    logging.error("Error", exc_info=ex)
    pn.state.notifications.error('Error: %s' % ex)

pn.extension(exception_handler=exception_handler, notifications=True)

As of version 0.13.0, you can get this functionality out of the box via the Debugging widget.

e.g.

logger = logging.getLogger('panel.myapp')

debug_info = pn.widgets.Debugger(
  name='Debugger info level', 
  level=logging.INFO, 
  sizing_mode='stretch_both',
  # comment this line out to get all panel errors
  logger_names=['panel.myapp'] 
)
Answered By: danwild