code: def _groupby_apply_kernel_string_from_template(frame, args):
      """
      Function to write numba kernels for `Groupby.apply` as a string.
      Workaround until numba supports functions that use `*args`
      """
      # Create argument list for kernel
      frame = _supported_cols_from_frame(
          frame, supported_types=SUPPORTED_GROUPBY_NUMPY_TYPES
      )
      input_columns = ", ".join(
          [f"input_col_{i}" for i in range(len(frame))]
      )
      extra_args = ", ".join(
          [f"extra_arg_{i}" for i in range(len(args))]
      )
  
      # Generate the initializers for each device function argument
      initializers = []
      for i, colname in enumerate(frame.keys()):
          initializers.append(
              group_initializer_template.format(idx=i, name=colname)
          )
  
      return groupby_apply_kernel_template.format(
          input_columns=input_columns,
          extra_args=extra_args,
          group_initializers="\n".join(initializers),
      )
  
file_path: cudf/python/cudf/cudf/core/udf/groupby_utils.py
imports: import cupy
  import numpy
  from numba import cuda, types
  from numba.core.errors import TypingError
  from numba.cuda.cudadrv.devices import get_context
  from numba.np import numpy_support
  import cudf.core.udf.utils
  from cudf.core.udf.groupby_typing import SUPPORTED_GROUPBY_NUMPY_TYPES, Group, GroupByJITDataFrame, GroupType
  from cudf.core.udf.templates import group_initializer_template, groupby_apply_kernel_template
  from cudf.core.udf.utils import UDFError, _all_dtypes_from_frame, _compile_or_get, _get_extensionty_size, _get_kernel, _get_udf_return_type, _supported_cols_from_frame, _supported_dtypes_from_frame
  from cudf.utils._numba import _CUDFNumbaConfig
  from cudf.utils.nvtx_annotation import _cudf_nvtx_annotate
label_desc: Use image node_id 2 for calling a global function with example usage: _groupby_apply_kernel_string_from_template(frame, args) and returns: groupby_apply_kernel_template