Add interactive template with python environment selector

This commit is contained in:
Benoît Seignovert 2024-01-30 16:15:18 +01:00
parent 494ba17aaf
commit dea39b9462
Signed by: Benoît Seignovert
GPG key ID: F5D8895227D18A0B
5 changed files with 105 additions and 43 deletions

View file

@ -58,6 +58,9 @@ quote-style = "single"
inline-quotes = "single"
docstring-quotes = "double"
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View file

@ -4,8 +4,6 @@ from importlib.metadata import version
from .spawner import GlicidSpawner
__all__ = [
'GlicidSpawner',
]
__all__ = ['GlicidSpawner']
__version__ = version('glicid-spawner')

View file

@ -0,0 +1,65 @@
"""Python environment module."""
from dataclasses import dataclass
@dataclass
class PyEnv:
"""Python environment generic class."""
name: str
path: str
def __eq__(self, item):
return self.path == str(item)
class UserPyEnv(PyEnv):
"""User python environment."""
scope = 'USER'
class TeamPyEnv(PyEnv):
"""Team python environment."""
scope = 'TEAM'
class GlobalPyEnv(PyEnv):
"""Global python environment."""
scope = 'GLOBAL'
def get_pyenv_user(username: str) -> list:
"""List of python environment available to the user."""
return [
# Dummy values
UserPyEnv('base', f'/micromamba/{username}'),
UserPyEnv('pytorch', f'/micromamba/{username}/envs/pytorch'),
]
def get_pyenv_team() -> list:
"""List of python environment available to the user's team."""
return [
# Dummy values
TeamPyEnv(
'nuts-workshop', '/micromamba/operator/share/nuts-workshop-team/env/envs/nuts-workshop'
),
]
def get_pyenv_global() -> list:
"""List of python environment available globally."""
return [
# Dummy values
GlobalPyEnv('base', '/micromamba/operator/envs/base'),
GlobalPyEnv('data-science', '/micromamba/operator/envs/data-science'),
]
def get_pyenv(username: str) -> list:
"""List of all the python environment available to a user."""
return get_pyenv_user() + get_pyenv_team() + get_pyenv_global()

View file

@ -1,51 +1,28 @@
"""GLiCID spawner module."""
import shlex
from batchspawner import SlurmSpawner
from jinja2 import Environment, PackageLoader, select_autoescape
from .pyenv import get_pyenv
class GlicidSpawner(SlurmSpawner):
"""Glicid SLURM Spawner."""
def _options_form_default(self):
default_env = f'YOURNAME={self.user.name}\n'
return f"""
<div class="form-group">
<label for="args">Extra notebook CLI arguments</label>
<input name="args" class="form-control"
placeholder="e.g. --debug"></input>
</div>
<div class="form-group">
<label for="env">Environment variables (one per line)</label>
<textarea class="form-control" name="env">{default_env}</textarea>
</div>
"""
def _options_form_default(self) -> str:
"""JupyterHub rendered form template."""
environment = Environment(
loader=PackageLoader('glicid_spawner'),
autoescape=select_autoescape(),
)
template = environment.get_template('interactive.html')
def options_from_form(self, formdata):
return template.render(
username=self.user.name,
python_envs=get_pyenv(self.user.name),
)
def options_from_form(self, formdata) -> dict:
options = {}
options['env'] = env = {}
env_lines = formdata.get('env', [''])
for line in env_lines[0].splitlines():
if line:
key, value = line.split('=', 1)
env[key.strip()] = value.strip()
arg_s = formdata.get('args', [''])[0].strip()
if arg_s:
options['argv'] = shlex.split(arg_s)
options['pyenv'] = formdata['python-env'][0]
return options
def get_args(self):
"""Return arguments to pass to the notebook server"""
argv = super().get_args()
if self.user_options.get('argv'):
argv.extend(self.user_options['argv'])
return argv
def get_env(self):
env = super().get_env()
if self.user_options.get('env'):
env.update(self.user_options['env'])
return env

View file

@ -0,0 +1,19 @@
<div class="form-horizontal">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">Username:</label>
<div class="col-sm-9">
<input class="form-control" name="username" type="text" placeholder="{{username}}" disabled>
</div>
</div>
<div class="form-group">
<label for="username" class="col-sm-3 control-label">Python environment:</label>
<div class="col-sm-9">
<select class="form-control" name="python-env">
{%- for pyenv in python_envs -%}
<option value="{{pyenv.path}}">{{pyenv.name}} ({{pyenv.scope | upper}})</option>
{% endfor -%}
</select>
<input class="form-control" name="username" type="text" placeholder="{username}" disabled>
</div>
</div>
</div>