code: def _attach(
      logger_module: Union[str, ModuleType],
      modules: List[ModuleType],
      classes: List[Type[Any]],
      missings: List[Tuple[Type[Any], Type[Any]]],
  ) -> None:
      if isinstance(logger_module, str):
          logger_module = importlib.import_module(logger_module)
  
      logger = getattr(logger_module, "get_logger")()
  
      special_functions = set(
          [
              "__init__",
              "__repr__",
              "__str__",
              "_repr_html_",
              "__len__",
              "__getitem__",
              "__setitem__",
              "__getattr__",
              "__enter__",
              "__exit__",
          ]
      )
  
      # Modules
      for target_module in modules:
          target_name = target_module.__name__.split(".")[-1]
          for name in getattr(target_module, "__all__"):
              func = getattr(target_module, name)
              if not inspect.isfunction(func):
                  continue
              setattr(
                  target_module,
                  name,
                  _wrap_function(target_name, name, func, logger),
              )
  
      # Classes
      for target_class in classes:
          for name, func in inspect.getmembers(
              target_class, inspect.isfunction
          ):
              if name.startswith("_") and name not in special_functions:
                  continue
              try:
                  isstatic = isinstance(
                      inspect.getattr_static(target_class, name),
                      staticmethod,
                  )
              except AttributeError:
                  isstatic = False
              wrapped_function = _wrap_function(
                  target_class.__name__, name, func, logger
              )
              setattr(
                  target_class,
                  name,
                  staticmethod(wrapped_function)
                  if isstatic
                  else wrapped_function,
              )
  
          for name, prop in inspect.getmembers(
              target_class, lambda o: isinstance(o, property)
          ):
              if name.startswith("_"):
                  continue
              setattr(
                  target_class,
                  name,
                  _wrap_property(
                      target_class.__name__, name, prop, logger
                  ),
              )
  
      # Missings
      for original, missing in missings:
          for name, func in inspect.getmembers(
              missing, inspect.isfunction
          ):
              setattr(
                  missing,
                  name,
                  _wrap_missing_function(
                      original.__name__, name, func, original, logger
                  ),
              )
  
          for name, prop in inspect.getmembers(
              missing, lambda o: isinstance(o, property)
          ):
              setattr(
                  missing,
                  name,
                  _wrap_missing_property(
                      original.__name__, name, prop, logger
                  ),
              )
  
file_path: spark/python/pyspark/instrumentation_utils.py
imports: import functools
  import inspect
  import threading
  import importlib
  import time
  from types import ModuleType
  from typing import Tuple, Union, List, Callable, Any, Type
label_desc: Use image node_id 5 for calling a global function with example usage: _attach(logger_module, modules, classes, missings) without return types