Skip to content

Commit

Permalink
feat: allow showing of stacktraces in server extension mode
Browse files Browse the repository at this point in the history
Closes voila-dashboards#751
This is a followup of voila-dashboards#630
  • Loading branch information
maartenbreddels committed Nov 2, 2020
1 parent 6bcc277 commit 29646f3
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 17 deletions.
23 changes: 23 additions & 0 deletions tests/app/show_traceback_test.py
@@ -0,0 +1,23 @@
import pytest


@pytest.fixture(params=[True, False])
def show_tracebacks(request):
return request.param


@pytest.fixture
def voila_args(notebook_directory, voila_args_extra, show_tracebacks):
return ['--VoilaTest.root_dir=%r' % notebook_directory, f'--VoilaConfiguration.show_tracebacks={show_tracebacks}'] + voila_args_extra


async def test_syntax_error(http_server_client, syntax_error_notebook_url, show_tracebacks):
response = await http_server_client.fetch(syntax_error_notebook_url)
assert response.code == 200
output = response.body.decode('utf-8')
if show_tracebacks:
assert 'this is a syntax error' in output, 'should show the "code"'
assert 'SyntaxError' in output and 'invalid syntax' in output, "should show the error"
else:
assert 'There was an error when executing cell' in output
assert 'This should not be executed' not in output
9 changes: 2 additions & 7 deletions tests/app/syntax_error_test.py
@@ -1,18 +1,13 @@
import pytest


@pytest.fixture
def syntax_error_notebook(base_url):
return base_url + "voila/render/syntax_error.ipynb"


@pytest.fixture
def voila_args(notebook_directory, voila_args_extra):
return ['--VoilaTest.root_dir=%r' % notebook_directory] + voila_args_extra


async def test_syntax_error(capsys, http_server_client, syntax_error_notebook):
response = await http_server_client.fetch(syntax_error_notebook)
async def test_syntax_error(capsys, http_server_client, syntax_error_notebook_url):
response = await http_server_client.fetch(syntax_error_notebook_url)
assert response.code == 200
output = response.body.decode('utf-8')
assert 'There was an error when executing cell' in output
Expand Down
5 changes: 5 additions & 0 deletions tests/conftest.py
Expand Up @@ -17,6 +17,11 @@ def print_notebook_url(base_url):
return base_url + "voila/render/print.ipynb"


@pytest.fixture
def syntax_error_notebook_url(base_url):
return base_url + "voila/render/syntax_error.ipynb"


@pytest.fixture
def voila_notebook(notebook_directory):
return os.path.join(notebook_directory, 'print.ipynb')
23 changes: 23 additions & 0 deletions tests/server/show_traceback_test.py
@@ -0,0 +1,23 @@
import pytest


@pytest.fixture(params=[True, False])
def show_tracebacks(request):
return request.param


@pytest.fixture
def jupyter_server_args_extra(show_tracebacks):
return [f'--VoilaConfiguration.show_tracebacks={show_tracebacks}']


async def test_syntax_error(http_server_client, syntax_error_notebook_url, show_tracebacks):
response = await http_server_client.fetch(syntax_error_notebook_url)
assert response.code == 200
output = response.body.decode('utf-8')
if show_tracebacks:
assert 'this is a syntax error' in output, 'should show the "code"'
assert 'SyntaxError' in output and 'invalid syntax' in output, "should show the error"
else:
assert 'There was an error when executing cell' in output
assert 'This should not be executed' not in output
12 changes: 6 additions & 6 deletions voila/app.py
Expand Up @@ -75,7 +75,10 @@ class Voila(Application):

flags = {
'debug': (
{'Voila': {'log_level': logging.DEBUG, 'show_tracebacks': True}},
{
'Voila': {'log_level': logging.DEBUG},
'VoilaConfiguration': {'show_tracebacks': True},
},
_("Set the log level to logging.DEBUG, and show exception tracebacks in output.")
),
'no-browser': ({'Voila': {'open_browser': False}}, _('Don\'t open the notebook in a browser after startup.'))
Expand Down Expand Up @@ -125,7 +128,8 @@ class Voila(Application):
'theme': 'VoilaConfiguration.theme',
'base_url': 'Voila.base_url',
'server_url': 'Voila.server_url',
'enable_nbextensions': 'VoilaConfiguration.enable_nbextensions'
'enable_nbextensions': 'VoilaConfiguration.enable_nbextensions',
'show_tracebacks': 'VoilaConfiguration.show_tracebacks',
}
classes = [
VoilaConfiguration,
Expand Down Expand Up @@ -187,10 +191,6 @@ class Voila(Application):
)
)

show_tracebacks = Bool(False, config=True, help=_(
'Whether to send tracebacks to clients on exceptions.'
))

port_retries = Integer(50, config=True,
help=_("The number of additional ports to try if the specified port is not available.")
)
Expand Down
4 changes: 4 additions & 0 deletions voila/configuration.py
Expand Up @@ -81,3 +81,7 @@ class VoilaConfiguration(traitlets.config.Configurable):
When a cell takes a long time to execute, the http connection can timeout (possibly because of a proxy).
Voila sends a 'heartbeat' message after the timeout is passed to keep the http connection alive.
""").tag(config=True)

show_tracebacks = Bool(False, config=True, help=(
'Whether to send tracebacks to clients on exceptions.'
))
10 changes: 7 additions & 3 deletions voila/execute.py
Expand Up @@ -11,7 +11,7 @@
from nbclient.exceptions import CellExecutionError
from nbclient import NotebookClient

from traitlets import Unicode
from traitlets import Bool, Unicode


def strip_code_cell_warnings(cell):
Expand All @@ -32,7 +32,7 @@ def strip_code_cell_warnings(cell):
class VoilaExecutor(NotebookClient):
"""Execute, but respect the output widget behaviour"""
cell_error_instruction = Unicode(
'Please run Voilà with --debug to see the error message.',
'Please run Voilà with --show_tracebacks=True or --debug to see the error message, or configure VoilaConfigurion.show_tracebacks.',
config=True,
help=(
'instruction given to user to debug cell errors'
Expand All @@ -47,6 +47,10 @@ class VoilaExecutor(NotebookClient):
)
)

show_tracebacks = Bool(False, config=True, help=(
'Whether to send tracebacks to clients on exceptions.'
))

def execute(self, nb, resources, km=None):
try:
result = super(VoilaExecutor, self).execute()
Expand Down Expand Up @@ -77,7 +81,7 @@ async def execute_cell(self, cell, resources, cell_index, store_history=True):

def should_strip_error(self):
"""Return True if errors should be stripped from the Notebook, False otherwise, depending on the current config."""
return 'Voila' not in self.config or not self.config['Voila'].get('show_tracebacks', False)
return not self.show_tracebacks

def strip_notebook_errors(self, nb):
"""Strip error messages and traceback from a Notebook."""
Expand Down
3 changes: 2 additions & 1 deletion voila/handler.py
Expand Up @@ -170,7 +170,8 @@ async def _jinja_kernel_start(self, nb):
))
km = self.kernel_manager.get_kernel(kernel_id)

self.executor = VoilaExecutor(nb, km=km, config=self.traitlet_config)
self.executor = VoilaExecutor(nb, km=km, config=self.traitlet_config,
show_tracebacks=self.voila_configuration.show_tracebacks)

###
# start kernel client
Expand Down

0 comments on commit 29646f3

Please sign in to comment.