11import os
22import random
33import subprocess
4- from os . path import join
4+ from typing import Any
55
66import docker
77from dockerspawner import DockerSpawner
@@ -46,8 +46,9 @@ def _default_environment(self) -> dict[str, str]:
4646 "BIRDHOUSE_HOST_URL" : constants .BIRDHOUSE_HOST_URL ,
4747 # https://docs.dask.org/en/stable/configuration.html
4848 # https://jupyterhub-on-hadoop.readthedocs.io/en/latest/dask.html
49- "DASK_DISTRIBUTED__DASHBOARD__LINK" : constants .BIRDHOUSE_HOST_URL
50- + "{JUPYTERHUB_SERVICE_PREFIX}proxy/{port}/status" ,
49+ "DASK_DISTRIBUTED__DASHBOARD__LINK" : (
50+ constants .BIRDHOUSE_HOST_URL + "{JUPYTERHUB_SERVICE_PREFIX}proxy/{port}/status"
51+ ),
5152 }
5253
5354 @default ("volumes" )
@@ -77,7 +78,7 @@ def _default_volumes(self) -> dict[str, str]:
7778 }
7879 if constants .README :
7980 volumes [constants .README ] = {
80- "bind" : join (constants .NOTEBOOK_DIR , "README.ipynb" ),
81+ "bind" : os . path . join (constants .NOTEBOOK_DIR , "README.ipynb" ),
8182 "mode" : "ro" ,
8283 }
8384 return volumes
@@ -140,7 +141,7 @@ def _default_args(self) -> list[str]:
140141 return args
141142
142143 @default ("extra_host_config" )
143- def _default_extra_host_config (self ) -> dict :
144+ def _default_extra_host_config (self ) -> dict [ str , Any ] :
144145 """Return extra host configuration dictionary."""
145146 return {
146147 # start init pid 1 process to reap defunct processes
@@ -197,22 +198,22 @@ def _default_allowed_images(self) -> list[str] | dict[str, str]:
197198 # https://jupyterhub.readthedocs.io/en/latest/reference/api/spawner.html#jupyterhub.spawner.Spawner
198199
199200 @default ("notebook_dir" )
200- def _default_notebook_dir (self ) -> int :
201+ def _default_notebook_dir (self ) -> str :
201202 """Return notebook directory path."""
202203 return constants .NOTEBOOK_DIR
203204
204205 @default ("disable_user_config" )
205- def _default_disable_user_config (self ) -> int :
206+ def _default_disable_user_config (self ) -> bool :
206207 """Disable per-user configuration of single-user servers."""
207208 return True
208209
209210 @default ("default_url" )
210- def _default_default_url (self ) -> int :
211+ def _default_default_url (self ) -> str :
211212 """Set the URL the single-user server should start in."""
212213 return "/lab"
213214
214215 @default ("debug" )
215- def _default_debug (self ) -> int :
216+ def _default_debug (self ) -> bool :
216217 """Debug log output."""
217218 return True
218219
@@ -238,37 +239,37 @@ def escaped_name(self) -> str:
238239
239240 def __create_tutorial_notebook_hook (self ) -> None :
240241 """Mount tutorial notebooks as volumes based on the selected singleuser jupyterlab image."""
241- container_tutorial_dir = join (constants .NOTEBOOK_DIR , "tutorial-notebooks" )
242+ container_tutorial_dir = os . path . join (constants .NOTEBOOK_DIR , "tutorial-notebooks" )
242243 if constants .JUPYTERHUB_MOUNT_IMAGE_SPECIFIC_NOTEBOOKS :
243- host_tutorial_dir = join (
244+ host_tutorial_dir = os . path . join (
244245 constants .JUPYTERHUB_DATA_DIR ,
245246 "tutorial-notebooks-specific-images" ,
246247 )
247248
248249 # Mount a volume with a tutorial-notebook subfolder corresponding to the image name, if it exists
249250 # The names are defined in the JUPYTERHUB_IMAGE_SELECTION_NAMES variable.
250251 image_name = self .user_options ["image" ]
251- host_tutorial_subdir = join (host_tutorial_dir , image_name )
252+ host_tutorial_subdir = os . path . join (host_tutorial_dir , image_name )
252253 if not os .path .isdir (host_tutorial_subdir ):
253254 # Try again, removing any colons and any following text. Useful if the image name contains
254255 # the version number, which should not be used in the directory name.
255- host_tutorial_subdir = join (host_tutorial_dir , image_name .split (":" )[0 ])
256+ host_tutorial_subdir = os . path . join (host_tutorial_dir , image_name .split (":" )[0 ])
256257 if os .path .isdir (host_tutorial_subdir ):
257258 self .volumes [host_tutorial_subdir ] = {
258259 "bind" : container_tutorial_dir ,
259260 "mode" : "ro" ,
260261 }
261262 else :
262263 # Mount the entire tutorial-notebooks directory
263- self .volumes [join (constants .JUPYTERHUB_DATA_DIR , "tutorial-notebooks" )] = {
264+ self .volumes [os . path . join (constants .JUPYTERHUB_DATA_DIR , "tutorial-notebooks" )] = {
264265 "bind" : container_tutorial_dir ,
265266 "mode" : "ro" ,
266267 }
267268
268269 def __create_dir_hook (self ) -> None :
269270 """Create user workspace directories on the host and update permissions if necessary."""
270271 username = self .user .name
271- jupyterhub_user_dir = join (constants .JUPYTERHUB_DATA_DIR , username )
272+ jupyterhub_user_dir = os . path . join (constants .JUPYTERHUB_DATA_DIR , username )
272273
273274 if not os .path .exists (jupyterhub_user_dir ):
274275 os .mkdir (jupyterhub_user_dir , 0o755 )
@@ -285,7 +286,7 @@ def __create_dir_hook(self) -> None:
285286 if constants .COWBIRD_ENABLED :
286287 # Case for cowbird setup. The workspace directory should also have the user's ownership,
287288 # to have working volume mounts with the DockerSpawner.
288- workspace_user_dir = join (constants .WORKSPACE_DIR , username )
289+ workspace_user_dir = os . path . join (constants .WORKSPACE_DIR , username )
289290 if not os .path .exists (workspace_user_dir ):
290291 os .symlink (jupyterhub_user_dir , workspace_user_dir , target_is_directory = True )
291292 subprocess .call (
0 commit comments