code: def register_callback(  # pylint: disable=R0914
      callback_list,
      callback_map,
      config_prevent_initial_callbacks,
      *_args,
      **_kwargs,
  ):
      (
          output,
          flat_inputs,
          flat_state,
          inputs_state_indices,
          prevent_initial_call,
      ) = handle_grouped_callback_args(_args, _kwargs)
      if isinstance(output, Output):
          # Insert callback with scalar (non-multi) Output
          insert_output = output
          multi = False
      else:
          # Insert callback as multi Output
          insert_output = flatten_grouping(output)
          multi = True
  
      long = _kwargs.get("long")
      manager = _kwargs.get("manager")
      allow_dynamic_callbacks = _kwargs.get("_allow_dynamic_callbacks")
  
      output_indices = make_grouping_by_index(
          output, list(range(grouping_len(output)))
      )
      callback_id = insert_callback(
          callback_list,
          callback_map,
          config_prevent_initial_callbacks,
          insert_output,
          output_indices,
          flat_inputs,
          flat_state,
          inputs_state_indices,
          prevent_initial_call,
          long=long,
          manager=manager,
          dynamic_creator=allow_dynamic_callbacks,
      )
  
      # pylint: disable=too-many-locals
      def wrap_func(func):
          if long is not None:
              long_key = BaseLongCallbackManager.register_func(
                  func,
                  long.get("progress") is not None,
                  callback_id,
              )
  
          @wraps(func)
          def add_context(*args, **kwargs):
              output_spec = kwargs.pop("outputs_list")
              app_callback_manager = kwargs.pop(
                  "long_callback_manager", None
              )
              callback_ctx = kwargs.pop("callback_context", {})
              callback_manager = long and long.get(
                  "manager", app_callback_manager
              )
              _validate.validate_output_spec(
                  insert_output, output_spec, Output
              )
  
              context_value.set(callback_ctx)
  
              (
                  func_args,
                  func_kwargs,
              ) = _validate.validate_and_group_input_args(
                  args, inputs_state_indices
              )
  
              response = {"multi": True}
  
              if long is not None:
                  if not callback_manager:
                      raise MissingLongCallbackManagerError(
                          "Running `long` callbacks requires a manager to be installed.\n"
                          "Available managers:\n"
                          "- Diskcache (`pip install dash[diskcache]`) to run callbacks in a separate Process"
                          " and store results on the local filesystem.\n"
                          "- Celery (`pip install dash[celery]`) to run callbacks in a celery worker"
                          " and store results on redis.\n"
                      )
  
                  progress_outputs = long.get("progress")
                  cache_key = flask.request.args.get("cacheKey")
                  job_id = flask.request.args.get("job")
                  old_job = flask.request.args.getlist("oldJob")
  
                  current_key = callback_manager.build_cache_key(
                      func,
                      # Inputs provided as dict is kwargs.
                      func_args if func_args else func_kwargs,
                      long.get("cache_args_to_ignore", []),
                  )
  
                  if old_job:
                      for job in old_job:
                          callback_manager.terminate_job(job)
  
                  if not cache_key:
                      cache_key = current_key
  
                      job_fn = callback_manager.func_registry.get(
                          long_key
                      )
  
                      job = callback_manager.call_job_fn(
                          cache_key,
                          job_fn,
                          func_args if func_args else func_kwargs,
                          AttributeDict(
                              args_grouping=callback_ctx.args_grouping,
                              using_args_grouping=callback_ctx.using_args_grouping,
                              outputs_grouping=callback_ctx.outputs_grouping,
                              using_outputs_grouping=callback_ctx.using_outputs_grouping,
                              inputs_list=callback_ctx.inputs_list,
                              states_list=callback_ctx.states_list,
                              outputs_list=callback_ctx.outputs_list,
                              input_values=callback_ctx.input_values,
                              state_values=callback_ctx.state_values,
                              triggered_inputs=callback_ctx.triggered_inputs,
                              ignore_register_page=True,
                          ),
                      )
  
                      data = {
                          "cacheKey": cache_key,
                          "job": job,
                      }
  
                      running = long.get("running")
  
                      if running:
                          data["running"] = {
                              str(r[0]): r[1] for r in running
                          }
                          data["runningOff"] = {
                              str(r[0]): r[2] for r in running
                          }
                      cancel = long.get("cancel")
                      if cancel:
                          data["cancel"] = cancel
  
                      progress_default = long.get("progressDefault")
                      if progress_default:
                          data["progressDefault"] = {
                              str(o): x
                              for o, x in zip(
                                  progress_outputs, progress_default
                              )
                          }
                      return to_json(data)
                  if progress_outputs:
                      # Get the progress before the result as it would be erased after the results.
                      progress = callback_manager.get_progress(
                          cache_key
                      )
                      if progress:
                          response["progress"] = {
                              str(x): progress[i]
                              for i, x in enumerate(progress_outputs)
                          }
  
                  output_value = callback_manager.get_result(
                      cache_key, job_id
                  )
                  # Must get job_running after get_result since get_results terminates it.
                  job_running = callback_manager.job_running(job_id)
                  if (
                      not job_running
                      and output_value is callback_manager.UNDEFINED
                  ):
                      # Job canceled -> no output to close the loop.
                      output_value = NoUpdate()
  
                  elif (
                      isinstance(output_value, dict)
                      and "long_callback_error" in output_value
                  ):
                      error = output_value.get("long_callback_error")
                      raise LongCallbackError(
                          f"An error occurred inside a long callback: {error['msg']}\n{error['tb']}"
                      )
  
                  if (
                      job_running
                      and output_value is not callback_manager.UNDEFINED
                  ):
                      # cached results.
                      callback_manager.terminate_job(job_id)
  
                  if multi and isinstance(output_value, (list, tuple)):
                      output_value = [
                          NoUpdate() if NoUpdate.is_no_update(r) else r
                          for r in output_value
                      ]
  
                  if output_value is callback_manager.UNDEFINED:
                      return to_json(response)
              else:
                  # don't touch the comment on the next line - used by debugger
                  output_value = func(
                      *func_args, **func_kwargs
                  )  # %% callback invoked %%
  
              if NoUpdate.is_no_update(output_value):
                  raise PreventUpdate
  
              if not multi:
                  output_value, output_spec = [output_value], [
                      output_spec
                  ]
                  flat_output_values = output_value
              else:
                  if isinstance(output_value, (list, tuple)):
                      # For multi-output, allow top-level collection to be
                      # list or tuple
                      output_value = list(output_value)
  
                  # Flatten grouping and validate grouping structure
                  flat_output_values = flatten_grouping(
                      output_value, output
                  )
  
              _validate.validate_multi_return(
                  output_spec, flat_output_values, callback_id
              )
  
              component_ids = collections.defaultdict(dict)
              has_update = False
              for val, spec in zip(flat_output_values, output_spec):
                  if isinstance(val, NoUpdate):
                      continue
                  for vali, speci in (
                      zip(val, spec)
                      if isinstance(spec, list)
                      else [[val, spec]]
                  ):
                      if not isinstance(vali, NoUpdate):
                          has_update = True
                          id_str = stringify_id(speci["id"])
                          prop = clean_property_name(speci["property"])
                          component_ids[id_str][prop] = vali
  
              if not has_update:
                  raise PreventUpdate
  
              response["response"] = component_ids
  
              try:
                  jsonResponse = to_json(response)
              except TypeError:
                  _validate.fail_callback_output(output_value, output)
  
              return jsonResponse
  
          callback_map[callback_id]["callback"] = add_context
  
          return func
  
      return wrap_func
  
file_path: dash/dash/_callback.py
imports: import collections
  import hashlib
  from functools import wraps
  import flask
  from .dependencies import handle_callback_args, handle_grouped_callback_args, Output
  from .exceptions import PreventUpdate, WildcardInLongCallback, MissingLongCallbackManagerError, LongCallbackError
  from ._grouping import flatten_grouping, make_grouping_by_index, grouping_len
  from ._utils import create_callback_id, stringify_id, to_json, coerce_to_list, AttributeDict, clean_property_name
  from .None import _validate
  from .long_callback.managers import BaseLongCallbackManager
  from ._callback_context import context_value
label_desc: Use image node_id 5 for calling a global function with example usage: register_callback(callback_list, callback_map, config_prevent_initial_callbacks) and returns: wrap_func, func, jsonResponse, to_json, to_json