Add interactive template with python environment selector
This commit is contained in:
parent
494ba17aaf
commit
dea39b9462
5 changed files with 105 additions and 43 deletions
|
@ -58,6 +58,9 @@ quote-style = "single"
|
||||||
inline-quotes = "single"
|
inline-quotes = "single"
|
||||||
docstring-quotes = "double"
|
docstring-quotes = "double"
|
||||||
|
|
||||||
|
[tool.ruff.lint.pydocstyle]
|
||||||
|
convention = "numpy"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["poetry-core"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
|
@ -4,8 +4,6 @@ from importlib.metadata import version
|
||||||
|
|
||||||
from .spawner import GlicidSpawner
|
from .spawner import GlicidSpawner
|
||||||
|
|
||||||
__all__ = [
|
__all__ = ['GlicidSpawner']
|
||||||
'GlicidSpawner',
|
|
||||||
]
|
|
||||||
|
|
||||||
__version__ = version('glicid-spawner')
|
__version__ = version('glicid-spawner')
|
||||||
|
|
65
src/glicid_spawner/pyenv.py
Normal file
65
src/glicid_spawner/pyenv.py
Normal 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()
|
|
@ -1,51 +1,28 @@
|
||||||
"""GLiCID spawner module."""
|
"""GLiCID spawner module."""
|
||||||
|
|
||||||
import shlex
|
|
||||||
|
|
||||||
from batchspawner import SlurmSpawner
|
from batchspawner import SlurmSpawner
|
||||||
|
from jinja2 import Environment, PackageLoader, select_autoescape
|
||||||
|
|
||||||
|
from .pyenv import get_pyenv
|
||||||
|
|
||||||
|
|
||||||
class GlicidSpawner(SlurmSpawner):
|
class GlicidSpawner(SlurmSpawner):
|
||||||
"""Glicid SLURM Spawner."""
|
"""Glicid SLURM Spawner."""
|
||||||
|
|
||||||
def _options_form_default(self):
|
def _options_form_default(self) -> str:
|
||||||
default_env = f'YOURNAME={self.user.name}\n'
|
"""JupyterHub rendered form template."""
|
||||||
return f"""
|
environment = Environment(
|
||||||
<div class="form-group">
|
loader=PackageLoader('glicid_spawner'),
|
||||||
<label for="args">Extra notebook CLI arguments</label>
|
autoescape=select_autoescape(),
|
||||||
<input name="args" class="form-control"
|
)
|
||||||
placeholder="e.g. --debug"></input>
|
template = environment.get_template('interactive.html')
|
||||||
</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_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 = {}
|
||||||
options['env'] = env = {}
|
options['pyenv'] = formdata['python-env'][0]
|
||||||
|
|
||||||
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)
|
|
||||||
return options
|
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
|
|
||||||
|
|
19
src/glicid_spawner/templates/interactive.html
Normal file
19
src/glicid_spawner/templates/interactive.html
Normal 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>
|
Loading…
Add table
Reference in a new issue