diff --git a/docs/customize.md b/docs/customize.md index 5ac170f82..b4f869b5d 100644 --- a/docs/customize.md +++ b/docs/customize.md @@ -233,7 +233,7 @@ Voila provides hooks that allow you to customize its behavior to fit your specif Currently, Voila supports the following hooks: - prelaunch_hook: Access and modify the Tornado request and notebook before execution. -- config_page_hook: Customize the page_config object, which controls the Voila frontend configuration. +- page_config_hook: Customize the page_config object, which controls the Voila frontend configuration. #### Accessing the tornado request (`prelaunch-hook`) @@ -261,7 +261,7 @@ def prelaunch_hook(req: tornado.web.RequestHandler, #### Customize the page config object (`page_config_hook`) -The config_page_hook allows you to customize the page_config object, which controls various aspects of the Voila frontend. This is useful when you need to modify frontend settings such as the URLs for static assets or other configuration parameters. +The page_config_hook allows you to customize the page_config object, which controls various aspects of the Voila frontend. This is useful when you need to modify frontend settings such as the URLs for static assets or other configuration parameters. By default, Voila uses the following page_config: @@ -305,7 +305,7 @@ def prelaunch_hook_function(req, notebook, cwd): """Do your stuffs here""" return notebook -def page_config_hook_function(current_page_config,**kwargs): +def page_config_hook_function(current_page_config, **kwargs): """Modify the current_page_config""" return new_page_config @@ -378,7 +378,7 @@ config = VoilaConfiguration() config.prelaunch_hook = parameterize_with_papermill # set the page config hook -config.config_page_hook = page_config_hook +config.page_config_hook = page_config_hook # create a voila instance app = Voila() diff --git a/tests/app/page_config_hook_test.py b/tests/app/page_config_hook_test.py new file mode 100644 index 000000000..2c0f74645 --- /dev/null +++ b/tests/app/page_config_hook_test.py @@ -0,0 +1,29 @@ +import os + +import pytest + + +BASE_DIR = os.path.dirname(__file__) + + +@pytest.fixture +def voila_notebook(notebook_directory): + return os.path.join(notebook_directory, "print.ipynb") + + +@pytest.fixture +def voila_config(): + def foo(current_page_config, **kwargs): + current_page_config["foo"] = "my custom config" + return current_page_config + + def config(app): + app.voila_configuration.page_config_hook = foo + + return config + + +async def test_prelaunch_hook(http_server_client, base_url): + response = await http_server_client.fetch(base_url) + assert response.code == 200 + assert "my custom config" in response.body.decode("utf-8") diff --git a/voila/app.py b/voila/app.py index b7f4e5e36..7a4a36e11 100644 --- a/voila/app.py +++ b/voila/app.py @@ -70,6 +70,7 @@ from traitlets import ( Bool, + Callable, Dict, Integer, List, @@ -192,8 +193,6 @@ class Voila(Application): "theme": "VoilaConfiguration.theme", "classic_tree": "VoilaConfiguration.classic_tree", "kernel_spec_manager_class": "VoilaConfiguration.kernel_spec_manager_class", - "prelaunch_hook": "VoilaConfiguration.prelaunch_hook", # For backward compatibility - "page_config_hook": "VoilaConfiguration.page_config_hook", } if JUPYTER_SERVER_2: aliases = {**aliases, "token": "Voila.token"} @@ -326,6 +325,40 @@ class Voila(Application): ), ) + prelaunch_hook = Callable( + default_value=None, + allow_none=True, + config=True, + help=_( + """A function that is called prior to the launch of a new kernel instance + when a user visits the voila webpage. Used for custom user authorization + or any other necessary pre-launch functions. + + Should be of the form: + + def hook(req: tornado.web.RequestHandler, + notebook: nbformat.NotebookNode, + cwd: str) + + Although most customizations can leverage templates, if you need access + to the request object (e.g. to inspect cookies for authentication), + or to modify the notebook itself (e.g. to inject some custom structure, + although much of this can be done by interacting with the kernel + in javascript) the prelaunch hook lets you do that. + """ + ), + ) + + @validate("prelaunch_hook") + def _valid_prelaunch_hook(self, proposal): + warn( + "Voila.prelaunch_hook is deprecated, please use VoilaConfiguration.prelaunch_hook instead", + DeprecationWarning, + stacklevel=2, + ) + self.voila_configuration.prelaunch_hook = proposal["value"] + return proposal["value"] + if JUPYTER_SERVER_2: cookie_secret = Bytes( b"",