I am using nbgrader together with z2jh for multiple courses where each course has its own configuration (GPU, CPU, RAM, docker image, etc.). Each user (students & instructors) may be registered in multiple courses, therefore to spawn the correct course & its configuration, before spawning their pod I ask them within options_form to choose their course. then in the pre_spawn_hook I use user_options to spawn the correct course. But within the nbgrader assignment list (as shown in the attached picture) they have still the possibility to change the course (while spawner is spun for another course!).
I was wondering how I can avoid this. how can I override the function in nbgrader that generates this dropdown courselist menu? how can I pass the correct courses to this menu?
the picture shows that two courses (pyf1 & pyf2) are visible in the course list menu while only pyf1 (which the user has chosen in the options_form) should be visible.
class Authenticator(LoggingConfigurable):
plugin_class = Type(
NoAuthPlugin,
klass=BaseAuthPlugin,
help="A plugin for different authentication methods."
).tag(config=True)
plugin = Instance(BaseAuthPlugin).tag(config=False)
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.log.debug("Using authenticator: %s", self.plugin_class.__name__)
self.plugin = self.plugin_class(parent=self)
def get_student_courses(self, student_id: str) -> Optional[list]:
"""Gets the list of courses that the student is enrolled in.
Arguments
---------
student_id:
The unique id of the student.
Returns
-------
A list of unique course ids, or None. If None is returned this means
that the student has access to any course that might exist. Otherwise
the student is only allowed access to the specific courses returned in
the list.
"""
return self.plugin.get_student_courses(student_id)
class JupyterHubAuthPlugin(BaseAuthPlugin):
def get_student_courses(self, student_id: str) -> Optional[list]:
if student_id == "*":
student_id = "{authenticated_user}"
response = None
try:
response = _query_jupyterhub_api('GET', '/users/%s' % student_id)
except JupyterhubEnvironmentError: # Should only go here if we are not running on Jupyterhub.
self.log.info('Not running on Jupyterhub, not able to GET Jupyterhub user')
raise
except JupyterhubApiError: # Should only go here if the api_token is invalid.
self.log.error("Error: Not able to get Jupyterhub user: " + student_id)
self.log.error("Make sure you start your service with a valid admin_user 'api_token' in your Jupyterhub config")
raise
courses = set()
for group in response['groups']:
if group.startswith('nbgrader-') or group.startswith('formgrade-'):
course = group.split('-', 1)[1]
if course:
courses.add(course)
return list(courses)
Could someone please explain this part self.plugin = self.plugin_class(parent=self)? I don’t have any familiarity with types & traitlets. Would it be possible to override this function? how & where?