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

Add support for query variables in preheat kernel mode #999

Merged
Next Next commit
POC query string
  • Loading branch information
trungleduc committed Oct 11, 2021
commit 4f903ef3927e5bd95b494acd353f643571519978
15 changes: 13 additions & 2 deletions voila/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
from .exporter import VoilaExporter
from .shutdown_kernel_handler import VoilaShutdownKernelHandler
from .voila_kernel_manager import voila_kernel_manager_factory
from .query_parameters_handler import QueryParametersHandler

_kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"

Expand Down Expand Up @@ -423,7 +424,7 @@ def start(self):
self.voila_configuration.multi_kernel_manager_class,
preheat_kernel,
pool_size
)
)
self.kernel_manager = kernel_manager_class(
parent=self,
connection_dir=self.connection_dir,
Expand Down Expand Up @@ -483,6 +484,16 @@ def start(self):
(url_path_join(self.server_url, r'/voila/api/shutdown/(.*)'), VoilaShutdownKernelHandler)
])

if preheat_kernel:
handlers.append(
(
url_path_join(self.server_url, r'/voila/env/%s\/(?P<var_name>.*)' % _kernel_id_regex),
QueryParametersHandler,
{
'kernel_manager': self.kernel_manager
}
)
)
# Serving notebook extensions
if self.voila_configuration.enable_nbextensions:
handlers.append(
Expand Down Expand Up @@ -533,7 +544,7 @@ def start(self):
'template_paths': self.template_paths,
'config': self.config,
'voila_configuration': self.voila_configuration
}),
}),
])

self.app.add_handlers('.*$', handlers)
Expand Down
15 changes: 9 additions & 6 deletions voila/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,12 @@ async def get(self, path=None):
# Get the pre-rendered content of notebook, the result can be all rendered cells
# of the notebook or some rendred cells and a generator which can be used by this
# handler to continue rendering calls.
render_task, rendered_cache = await self.kernel_manager.get_rendered_notebook(

render_task, rendered_cache, kernel_id = await self.kernel_manager.get_rendered_notebook(
notebook_name=notebook_path,
)
for name, value in self.request.arguments.items():
self.kernel_manager.set_query_params(kernel_id, name, value)

# Send rendered cell to frontend
if len(rendered_cache) > 0:
Expand Down Expand Up @@ -180,10 +183,10 @@ def should_use_rendered_notebook(
return False
if theme is not None and rendered_theme != theme:
return False
args_list = [
key for key in request_args if key not in ['voila-template', 'voila-theme']
]
if len(args_list) > 0:
return False
# args_list = [
# key for key in request_args if key not in ['voila-template', 'voila-theme']
# ]
# if len(args_list) > 0:
# return False

return True
11 changes: 11 additions & 0 deletions voila/notebook_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,17 @@ async def _jinja_kernel_start(self, nb, kernel_id, kernel_future):
)
self.executor.kc.allow_stdin = False
###
await ensure_async(
self.executor.kc.execute(
f'''import os
\nos.environ["VOILA_KERNEL_ID"]="{kernel_id}"
\nos.environ["VOILA_PREHEAT"]= "{self.voila_configuration.preheat_kernel}"
\nos.environ["VOILA_BASE_URL"]="{self.base_url}"
''',
store_history=False,
)
)

self.kernel_started = True
return kernel_id

Expand Down
16 changes: 16 additions & 0 deletions voila/query_parameters_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from tornado.web import RequestHandler


class QueryParametersHandler(RequestHandler):

def initialize(self, kernel_manager=None):
self._kernel_manager = None
if hasattr(kernel_manager, 'get_query_params'):
self._kernel_manager = kernel_manager

async def get(self, kernel_id: str, var_name: str):
if self._kernel_manager is not None:
content = self._kernel_manager.get_query_params(kernel_id, var_name)
self.finish(content[0])
else:
self.finish(None)
17 changes: 15 additions & 2 deletions voila/voila_kernel_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def __init__(self, **kwargs):
self.notebook_data: TypeDict = {}
self._pools: TypeDict[str, List[TypeDict]] = {}
self.root_dir = self.parent.root_dir
self._query_params = dict()
if self.parent.notebook_path is not None:
self.notebook_path = os.path.relpath(
self.parent.notebook_path, self.root_dir
Expand Down Expand Up @@ -143,11 +144,12 @@ async def get_rendered_notebook(
content = await pool_item
renderer: NotebookRenderer = content['renderer']
render_task: asyncio.Task = content['task']
kernel_id: str = content['kernel_id']
renderer.stop_generator = True
self.log.info('Using pre-heated kernel: %s for %s', 'kernel_id', notebook_name)
self.fill_if_needed(delay=None, notebook_name=notebook_name, **kwargs)

return render_task, renderer.rendered_cache
return render_task, renderer.rendered_cache, kernel_id

def get_pool_size(self, notebook_name: str) -> int:
return len(self._pools.get(notebook_name, []))
Expand Down Expand Up @@ -284,7 +286,6 @@ async def _initialize(
self.notebook_data[renderer.notebook_path]['kernel_ids'].add(kernel_id)

kernel_future = self.get_kernel(kernel_id)

task = asyncio.get_event_loop().create_task(renderer.generate_content_hybrid(kernel_id, kernel_future))
return {'task': task, 'renderer': renderer, 'kernel_id': kernel_id}

Expand Down Expand Up @@ -356,4 +357,16 @@ def _get_notebook_from_kernel(self, kernel_id: str) -> Union[None, str]:
return nb_name
return None

def get_query_params(self, kernel_id: str, variable_name: str) -> str:
return self._query_params.get(kernel_id, {}).get(variable_name, [None])

def set_query_params(self, kernel_id: str, variable_name: str, value: str) -> None:
if kernel_id not in self._query_params:
self._query_params[kernel_id] = {variable_name: value}
else:
self._query_params[kernel_id][variable_name] = value

def remove_query_params(self, kernel_id: str) -> None:
self._query_params.pop(kernel_id, None)

return VoilaKernelManager