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

make profile_list union of List and Callable #192

Merged
merged 2 commits into from
Jul 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/traitlets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ Module: :mod:`kubespawner.traitlets`
------------------------------------

.. automodule:: kubespawner.traitlets

.. autoclass:: Callable
41 changes: 30 additions & 11 deletions kubespawner/spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -896,20 +896,21 @@ def _hub_connect_port_default(self):
"""
)

profile_list = List(
trait=Dict(),
default_value=None,
minlen=0,
profile_list = Union([
List(trait=Dict()),
Callable()
],
config=True,
help="""
List of profiles to offer for selection by the user.

Signature is: List(Dict()), where each item is a dictionary that has two keys:

- 'display_name': the human readable display name (should be HTML safe)
- 'description': Optional description of this profile displayed to the user.
- 'kubespawner_override': a dictionary with overrides to apply to the KubeSpawner
settings. Each value can be either the final value to change or a callable that
take the `KubeSpawner` instance as parameter and return the final value.
settings. Each value can be either the final value to change or a callable that
take the `KubeSpawner` instance as parameter and return the final value.
- 'default': (optional Bool) True if this is the default selected option

Example::
Expand Down Expand Up @@ -954,6 +955,13 @@ def _hub_connect_port_default(self):
}
}
]

Instead of a list of dictionaries, this could also be a callable that takes as one
parameter the current spawner instance and returns a list of dictionaries. The
callable will be called asynchronously if it returns a future, rather than
a list. Note that the interface of the spawner class is not deemed stable
across versions, so using this functionality might cause your JupyterHub
or kubespawner upgrades to break.
"""
)

Expand Down Expand Up @@ -1402,6 +1410,16 @@ def get_args(self):
break
return args

def _render_options_form(self, profile_list):
self._profile_list = profile_list
profile_form_template = Environment(loader=BaseLoader).from_string(self.profile_form_template)
return profile_form_template.render(profile_list=profile_list)

@gen.coroutine
def _render_options_form_dynamically(self, current_spawner):
profile_list = yield gen.maybe_future(self.profile_list(current_spawner))
return self._render_options_form(profile_list)

def _options_form_default(self):
'''
Build the form template according to the `profile_list` setting.
Expand All @@ -1412,8 +1430,10 @@ def _options_form_default(self):
'''
if not self.profile_list:
return ''
profile_form_template = Environment(loader=BaseLoader).from_string(self.profile_form_template)
return profile_form_template.render(profile_list=self.profile_list)
if callable(self.profile_list):
return self._render_options_form_dynamically
else:
return self._render_options_form(self.profile_list)

def options_from_form(self, formdata):
"""get the option selected by the user on the form
Expand All @@ -1437,12 +1457,11 @@ def options_from_form(self, formdata):
Returns:
the selected user option
"""

if not self.profile_list:
if not self.profile_list or not hasattr(self, '_profile_list'):
return formdata
# Default to first profile if somehow none is provided
selected_profile = int(formdata.get('profile', [0])[0])
options = self.profile_list[selected_profile]
options = self._profile_list[selected_profile]
self.log.debug("Applying KubeSpawner override for profile '%s'", options['display_name'])
kubespawner_override = options.get('kubespawner_override', {})
for k, v in kubespawner_override.items():
Expand Down