Skip to content

Commit 93f4180

Browse files
committed
Add Jupyverse contents
1 parent f19e337 commit 93f4180

File tree

7 files changed

+281
-5
lines changed

7 files changed

+281
-5
lines changed

voila/app.py

+31-5
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ class Voila(Application):
9595
examples = "voila example.ipynb --port 8888"
9696

9797
flags = {
98+
"jupyverse": (
99+
{"Voila": {"jupyverse": True}},
100+
_("Use Jupyverse backend."),
101+
),
98102
"debug": (
99103
{
100104
"Voila": {"log_level": logging.DEBUG},
@@ -128,6 +132,11 @@ class Voila(Application):
128132
),
129133
}
130134

135+
jupyverse = Bool(
136+
False,
137+
config=True,
138+
help=_("Use Jupyverse backend"),
139+
)
131140
description = Unicode(
132141
"""voila [OPTIONS] NOTEBOOK_FILENAME
133142
@@ -776,11 +785,28 @@ def start(self):
776785

777786
settings = self.init_settings()
778787

779-
self.app = tornado.web.Application(**settings)
780-
self.app.settings.update(self.tornado_settings)
781-
handlers = self.init_handlers()
782-
self.app.add_handlers(".*$", handlers)
783-
self.listen()
788+
if self.jupyverse:
789+
try:
790+
from fps_voila import run_application
791+
except ImportError:
792+
raise RuntimeError(
793+
"Please install fps-voila in order to use the Jupyverse backend"
794+
)
795+
796+
run_application(
797+
settings,
798+
self.voila_configuration,
799+
self.static_paths,
800+
self.base_url,
801+
self.ip,
802+
self.port,
803+
)
804+
else:
805+
self.app = tornado.web.Application(**settings)
806+
self.app.settings.update(self.tornado_settings)
807+
handlers = self.init_handlers()
808+
self.app.add_handlers(".*$", handlers)
809+
self.listen()
784810

785811
def _handle_signal_stop(self, sig, frame):
786812
self.log.info("Handle signal %s." % sig)

voila/jupyverse/LICENSE

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
BSD License
2+
3+
Copyright (c) 2018 Voilà contributors.
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
a. Redistributions of source code must retain the above copyright notice,
10+
this list of conditions and the following disclaimer.
11+
12+
b. Redistributions in binary form must reproduce the above copyright
13+
notice, this list of conditions and the following disclaimer in the
14+
documentation and/or other materials provided with the distribution.
15+
16+
c. Neither the name of the authors nor the names of the contributors to
17+
this package may be used to endorse or promote products
18+
derived from this software without specific prior written
19+
permission.
20+
21+
22+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25+
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
26+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32+
DAMAGE.

voila/jupyverse/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# fps-voila
2+
3+
An FPS plugin for the Voilà API.

voila/jupyverse/fps_voila/__init__.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from asphalt.core import run_application as _run_application
2+
3+
from .main import RootComponent
4+
5+
6+
__version__ = "0.1.0"
7+
8+
9+
def run_application(settings, voila_configuration, static_paths, base_url, ip, port):
10+
_run_application(
11+
RootComponent(
12+
settings,
13+
voila_configuration,
14+
static_paths,
15+
base_url,
16+
ip,
17+
port,
18+
)
19+
)

voila/jupyverse/fps_voila/main.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import pkg_resources
2+
3+
from asphalt.core import Component, ContainerComponent, Context
4+
from jupyverse_api.app import App
5+
from jupyverse_api.auth import Auth
6+
7+
from .routes import Voila
8+
9+
10+
class VoilaComponent(Component):
11+
def __init__(
12+
self,
13+
*,
14+
settings,
15+
voila_configuration,
16+
static_paths,
17+
base_url,
18+
):
19+
super().__init__()
20+
self.settings = settings
21+
self.voila_configuration = voila_configuration
22+
self.static_paths = static_paths
23+
self.base_url = base_url
24+
25+
async def start(
26+
self,
27+
ctx: Context,
28+
) -> None:
29+
app = await ctx.request_resource(App)
30+
auth = await ctx.request_resource(Auth)
31+
32+
voila = Voila(
33+
app,
34+
auth,
35+
self.settings,
36+
self.voila_configuration,
37+
self.static_paths,
38+
self.base_url,
39+
)
40+
ctx.add_resource(voila)
41+
42+
43+
class RootComponent(ContainerComponent):
44+
def __init__(
45+
self,
46+
settings,
47+
voila_configuration,
48+
static_paths,
49+
base_url,
50+
ip,
51+
port,
52+
):
53+
super().__init__()
54+
self.settings = settings
55+
self.voila_configuration = voila_configuration
56+
self.static_paths = static_paths
57+
self.base_url = base_url
58+
self.ip = ip
59+
self.port = port
60+
61+
async def start(self, ctx: Context) -> None:
62+
asphalt_components = {
63+
ep.name: ep
64+
for ep in pkg_resources.iter_entry_points(group="asphalt.components")
65+
}
66+
67+
self.add_component(
68+
"fastapi",
69+
asphalt_components["fastapi"].load(),
70+
host=self.ip,
71+
port=self.port,
72+
)
73+
self.add_component(
74+
"voila",
75+
asphalt_components["voila"].load(),
76+
settings=self.settings,
77+
voila_configuration=self.voila_configuration,
78+
static_paths=self.static_paths,
79+
base_url=self.base_url,
80+
)
81+
self.add_component(
82+
"contents",
83+
asphalt_components["contents"].load(),
84+
prefix="/voila",
85+
)
86+
self.add_component(
87+
"auth",
88+
asphalt_components["noauth"].load(),
89+
)
90+
self.add_component(
91+
"app",
92+
asphalt_components["app"].load(),
93+
)
94+
await super().start(ctx)

voila/jupyverse/fps_voila/routes.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import logging
2+
from typing import List
3+
4+
from fastapi import APIRouter, Request
5+
from fastapi.responses import HTMLResponse
6+
from starlette.staticfiles import PathLike, StaticFiles
7+
from jupyverse_api import Router
8+
from jupyverse_api.app import App
9+
from jupyverse_api.auth import Auth
10+
from voila.utils import get_page_config
11+
12+
13+
logger = logging.getLogger(__name__)
14+
15+
16+
class Voila(Router):
17+
def __init__(
18+
self,
19+
app: App,
20+
auth: Auth,
21+
settings,
22+
voila_configuration,
23+
static_paths,
24+
base_url,
25+
):
26+
super().__init__(app=app)
27+
28+
router = APIRouter()
29+
30+
@router.get("/", response_class=HTMLResponse)
31+
async def get_root(request: Request):
32+
page_config = get_page_config(
33+
base_url=base_url,
34+
settings=settings,
35+
log=logger,
36+
voila_configuration=voila_configuration,
37+
)
38+
template = settings["voila_jinja2_env"].get_template("tree-lab.html")
39+
return template.render(
40+
page_config=page_config,
41+
)
42+
43+
self.include_router(router)
44+
45+
self.mount(
46+
"/voila/static",
47+
MultiStaticFiles(directories=static_paths, check_dir=False),
48+
)
49+
50+
51+
class MultiStaticFiles(StaticFiles):
52+
def __init__(self, directories: List[PathLike] = [], **kwargs) -> None:
53+
super().__init__(**kwargs)
54+
self.all_directories = self.all_directories + directories

voila/jupyverse/pyproject.toml

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "fps_voila"
7+
description = "An FPS plugin for the Voilà API"
8+
readme = "README.md"
9+
requires-python = ">=3.8"
10+
authors = [
11+
{ name = "Voila Development Team" },
12+
]
13+
keywords = [
14+
"Jupyter",
15+
"JupyterLab",
16+
"Voila",
17+
]
18+
classifiers = [
19+
"Framework :: Jupyter",
20+
"Framework :: Jupyter :: JupyterLab",
21+
"Framework :: Jupyter :: JupyterLab :: 3",
22+
"Framework :: Jupyter :: JupyterLab :: Extensions",
23+
"Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt",
24+
"License :: OSI Approved :: BSD License",
25+
"Programming Language :: Python",
26+
"Programming Language :: Python :: 3",
27+
"Programming Language :: Python :: 3.8",
28+
"Programming Language :: Python :: 3.9",
29+
"Programming Language :: Python :: 3.10",
30+
"Programming Language :: Python :: 3.11",
31+
]
32+
dependencies = [
33+
"fps-contents >0.2.4,<1"
34+
]
35+
dynamic = [ "version",]
36+
37+
[project.license]
38+
file = "LICENSE"
39+
40+
[project.entry-points]
41+
"asphalt.components" = {voila = "fps_voila.main:VoilaComponent"}
42+
"jupyverse.components" = {voila = "fps_voila.main:VoilaComponent"}
43+
44+
[project.urls]
45+
Homepage = "https://github.com/voila-dashboards/voila"
46+
47+
[tool.hatch.version]
48+
path = "fps_voila/__init__.py"

0 commit comments

Comments
 (0)