def _run_hook_function(
    obj: Settings,
    hook_type: str,
    hook_func: Callable,
    hook_source: str = "default",
    key: str = "",
):
    """
    Run a hook function:

    It execute @hook_func, update the results into settings @obj and
    add it to _loaded_hook registry ([@hook_source][@hook_type])
    """
    # if the function has a _dynaconf_hook_source attribute set
    # hook_source to it
    hook_source = getattr(hook_func, "_dynaconf_hook_source", hook_source)

    # optional settings argument
    try:
        hook_dict = hook_func(obj.dynaconf.clone())
    except TypeError:
        hook_dict = hook_func()

    # mark as called so executors such as `load_file` can avoid calling it again
    with suppress(AttributeError, TypeError):
        # callable may not be writable, the caveat is that it will be called again in case of reload
        # however, this must not be a problem since the function should be idempotent
        # and documentation warns about this behavior.
        hook_func._called = True

    identifier = _get_unique_hook_id(hook_func, hook_source)

    if hook_dict:
        # update obj settings
        merge = hook_dict.pop(
            "dynaconf_merge", hook_dict.pop("DYNACONF_MERGE", False)
        )
        if key and key in hook_dict:
            obj.set(
                key,
                hook_dict[key],
                tomlfy=False,
                merge=merge,
                loader_identifier=identifier,
            )
        elif not key:
            obj.update(
                hook_dict,
                tomlfy=False,
                merge=merge,
                loader_identifier=identifier,
            )

    # add to registry
    obj._loaded_hooks[identifier][hook_type] = hook_dict

    Run a hook function:

    It execute @hook_func, update the results into settings @obj and
    add it to _loaded_hook registry ([@hook_source][@hook_type])
    
dynaconf/loaders/__init__.py