def _disable_user_config(serverapp):
    """
    disable user-controlled sources of configuration
    by excluding directories in their home from paths.

    This _does not_ disable frontend config,
    such as UI settings persistence.

    1. Python config file paths
    2. Search paths for extensions, etc.
    3. import path
    """
    # delayed import to avoid triggering early ImportError
    # with unmet dependencies
    from jupyter_core import paths

    original_jupyter_path = paths.jupyter_path()
    jupyter_path_without_home = list(_exclude_home(original_jupyter_path))

    # config_file_paths is a property without a setter
    # can't override on the instance
    default_config_file_paths = serverapp.config_file_paths
    config_file_paths = list(_exclude_home(default_config_file_paths))
    serverapp.__class__.config_file_paths = property(
        lambda self: config_file_paths,
    )
    # verify patch applied
    assert serverapp.config_file_paths == config_file_paths

    # patch jupyter_path to exclude $HOME
    global \
        _original_jupyter_paths, \
        _jupyter_paths_without_home, \
        _original_jupyter_config_dir
    _original_jupyter_paths = paths.jupyter_path()
    _jupyter_paths_without_home = list(_exclude_home(_original_jupyter_paths))

    def get_jupyter_path_without_home(*subdirs):
        # reimport because of our `__code__` patch
        # affects what is resolved as the parent namespace
        from jupyterhub.singleuser._disable_user_config import (
            _jupyter_paths_without_home,
        )

        paths = list(_jupyter_paths_without_home)
        if subdirs:
            paths = [os.path.join(p, *subdirs) for p in paths]
        return paths

    # patch `jupyter_path.__code__` to ensure all callers are patched,
    # even if they've already imported
    # this affects e.g. nbclassic.nbextension_paths
    paths.jupyter_path.__code__ = get_jupyter_path_without_home.__code__

    # same thing for config_dir,
    # which applies to some things like ExtensionApp config paths
    # and nbclassic.static_custom_path

    # allows explicit override if $JUPYTER_CONFIG_DIR is set
    # or config dir is otherwise not in $HOME

    if not os.getenv("JUPYTER_CONFIG_DIR") and not list(
        _exclude_home([paths.jupyter_config_dir()])
    ):
        # patch specifically Application.config_dir
        # this affects ServerApp and ExtensionApp,
        # but does not affect JupyterLab's user-settings, etc.
        # patching the traitlet directly affects all instances,
        # already-created or future
        from jupyter_core.application import JupyterApp

        def get_env_config_dir(obj, cls=None):
            return paths.ENV_CONFIG_PATH[0]

        JupyterApp.config_dir.get = get_env_config_dir

    # record disabled state on app object
    serverapp.disable_user_config = True
disable user-controlled sources of configuration
by excluding directories in their home from paths.

This _does not_ disable frontend config,
such as UI settings persistence.

1. Python config file paths
2. Search paths for extensions, etc.
3. import path
jupyterhub/singleuser/_disable_user_config.py