code: def hypergraph(
      g,
      raw_events: DataframeLike,
      entity_types: Optional[List[str]] = None,
      opts: dict = {},
      drop_na: bool = True,
      drop_edge_attrs: bool = False,
      verbose: bool = True,
      direct: bool = False,
      engine: str = "pandas",  # see Engine for valid values
      npartitions: Optional[int] = None,
      chunksize: Optional[int] = None,
      debug: bool = False,
  ):
      """
      Internal details:
          - IDs currently strings: `${namespace(col)}${delim}${str(val)}`
          - debug: sprinkle persist() to catch bugs earlier
      """
      # TODO: String -> categorical
      # TODO: col_name column can be prohibitively wide & sparse: drop / warning?
  
      engine_resolved: Engine
      if not isinstance(engine, Engine):
          engine_resolved = getattr(Engine, str(engine).upper())  # type: ignore
      else:
          engine_resolved = engine
      defs = HyperBindings(**opts)
      entity_types = [
          i
          for i in screen_entities(raw_events, entity_types, defs)
          if i != defs.event_id
      ]
      events = clean_events(raw_events, defs, dropna=drop_na, engine=engine_resolved, npartitions=npartitions, chunksize=chunksize, debug=debug)  # type: ignore
      if debug and (engine in [Engine.DASK, Engine.DASK_CUDF]):
          logger.debug("==== events: %s", events.compute())
  
      entities = format_entities(events, entity_types, defs, direct, drop_na, engine_resolved, npartitions, chunksize, debug)  # type: ignore
  
      event_entities = None
      edges = None
      if direct:
          edge_shape = direct_edgelist_shape(entity_types, defs)
          event_entities = df_coercion(
              mt_nodes(
                  defs, events, entity_types, direct, engine_resolved
              ),
              engine_resolved,
              npartitions=1,
          )
          if debug:
              logger.debug(
                  "mt event_entities: %s", event_entities.dtypes
              )
          edges = format_direct_edges(
              engine_resolved,
              events,
              entity_types,
              defs,
              edge_shape,
              drop_na,
              drop_edge_attrs,
              debug,
          )
      else:
          event_entities = format_hypernodes(events, defs, drop_na)
          edges = format_hyperedges(
              engine_resolved,
              events,
              entity_types,
              defs,
              drop_na,
              drop_edge_attrs,
              debug,
          )
  
      if debug:
          logger.debug(
              "==== edges: %s",
              edges.compute()
              if engine_resolved in [Engine.DASK, Engine.DASK_CUDF]
              else edges,
          )
  
      if verbose:
          print("# links", len(edges))
          print("# events", len(events))
          print("# attrib entities", len(entities))
      return Hypergraph(
          g,
          defs,
          entities,
          event_entities,
          edges,
          defs.source if direct else defs.attrib_id,
          defs.destination if direct else defs.event_id,
          engine_resolved,
          debug,
      )
  
imports: from typing import TYPE_CHECKING, Any, Dict, List, Optional
  from .Engine import Engine, DataframeLike, DataframeLocalLike
  import numpy, pandas, pyarrow, sys
  from .util import setup_logger
label_desc: Use image node_id 22 for calling a global function with example usage: hypergraph(g, raw_events, entity_types, opts, drop_na, drop_edge_attrs, verbose, direct, engine, npartitions, chunksize, debug) and returns: Hypergraph