Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement FPS-based Voila server #984

Closed
wants to merge 9 commits into from
Prev Previous commit
Next Next commit
Support progressive HTML rendering
  • Loading branch information
davidbrochart committed Nov 8, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 041f416601d73021186d5a3ae5a04963aeb993e9
13 changes: 2 additions & 11 deletions fps_plugins/voila/fps_voila/routes.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@

from mimetypes import guess_type
from fastapi import APIRouter, Depends
from fastapi.responses import RedirectResponse, HTMLResponse, Response
from fastapi.responses import RedirectResponse, StreamingResponse, Response
from fastapi.staticfiles import StaticFiles
from fps.hooks import register_router # type: ignore

@@ -23,15 +23,6 @@ class FPSVoilaHandler(_VoilaHandler):
def redirect(self, url):
return RedirectResponse(url)

def write(self, html):
self.html += [html]

def flush(self):
pass

def return_html(self):
return HTMLResponse("".join(self.html))

def get_argument(self, name, default):
if self.fps_arguments[name] is None:
return default
@@ -85,7 +76,7 @@ async def get_root(voila_template: Optional[str] = None, voila_theme: Optional[s
fps_voila_handler.fps_arguments["voila-template"] = voila_template
fps_voila_handler.fps_arguments["voila-theme"] = voila_theme
path = "" #voila_config.notebook_path or "/"
return await _get(fps_voila_handler, path)
return StreamingResponse(_get(fps_voila_handler, path))

@router.get("/voila/static/{path}")
def get_file1(path):
26 changes: 11 additions & 15 deletions voila/handler.py
Original file line number Diff line number Diff line change
@@ -97,21 +97,18 @@ async def _get(self, path=None):
QueryStringSocketHandler.send_updates({'kernel_id': kernel_id, 'payload': self.request.query})
# Send rendered cell to frontend
if len(rendered_cache) > 0:
self.write(''.join(rendered_cache))
self.flush()
yield ''.join(rendered_cache)

# Wait for current running cell finish and send this cell to
# frontend.
rendered, rendering = await render_task
if len(rendered) > len(rendered_cache):
html_snippet = ''.join(rendered[len(rendered_cache):])
self.write(html_snippet)
self.flush()
yield html_snippet

# Continue render cell from generator.
async for html_snippet, _ in rendering:
self.write(html_snippet)
self.flush()
yield html_snippet
self.flush()

else:
@@ -136,8 +133,7 @@ def time_out():
can be used in a template to give feedback to a user
"""

self.write('<script>voila_heartbeat()</script>\n')
self.flush()
yield '<script>voila_heartbeat()</script>\n'

kernel_env[ENV_VARIABLE.VOILA_PREHEAT] = 'False'
kernel_env[ENV_VARIABLE.VOILA_BASE_URL] = self.base_url
@@ -154,14 +150,9 @@ def time_out():
async for html_snippet, _ in gen.generate_content_generator(
kernel_id, kernel_future, time_out
):
self.write(html_snippet)
self.flush()
yield html_snippet
# we may not want to consider not flusing after each snippet, but add an explicit flush function to the jinja context
# yield # give control back to tornado's IO loop, so it can handle static files or other requests
self.flush()

if self.is_fps:
return self.return_html()

class _VoilaHandler:
is_fps = False
@@ -203,4 +194,9 @@ def should_use_rendered_notebook(
class VoilaHandler(_VoilaHandler, JupyterHandler):
@tornado.web.authenticated
async def get(self, path=None):
return await _get(self, path=path)
it = _get(self, path=path)
async for html in it:
self.write(html)
self.flush()

return it