code: def construct_metadata(
      columns_to_convert,
      df,
      column_names,
      index_levels,
      index_descriptors,
      preserve_index,
      types,
  ):
      """Returns a dictionary containing enough metadata to reconstruct a pandas
      DataFrame as an Arrow Table, including index columns.
  
      Parameters
      ----------
      columns_to_convert : list[pd.Series]
      df : pandas.DataFrame
      index_levels : List[pd.Index]
      index_descriptors : List[Dict]
      preserve_index : bool
      types : List[pyarrow.DataType]
  
      Returns
      -------
      dict
      """
      num_serialized_index_levels = len(
          [
              descr
              for descr in index_descriptors
              if not isinstance(descr, dict)
          ]
      )
      # Use ntypes instead of Python shorthand notation [:-len(x)] as [:-0]
      # behaves differently to what we want.
      ntypes = len(types)
      df_types = types[: ntypes - num_serialized_index_levels]
      index_types = types[ntypes - num_serialized_index_levels :]
  
      column_metadata = []
      for col, sanitized_name, arrow_type in zip(
          columns_to_convert, column_names, df_types
      ):
          metadata = get_column_metadata(
              col,
              name=sanitized_name,
              arrow_type=arrow_type,
              field_name=sanitized_name,
          )
          column_metadata.append(metadata)
  
      index_column_metadata = []
      if preserve_index is not False:
          non_str_index_names = []
          for level, arrow_type, descriptor in zip(
              index_levels, index_types, index_descriptors
          ):
              if isinstance(descriptor, dict):
                  # The index is represented in a non-serialized fashion,
                  # e.g. RangeIndex
                  continue
  
              if level.name is not None and not isinstance(
                  level.name, str
              ):
                  non_str_index_names.append(level.name)
  
              metadata = get_column_metadata(
                  level,
                  name=_column_name_to_strings(level.name),
                  arrow_type=arrow_type,
                  field_name=descriptor,
              )
              index_column_metadata.append(metadata)
  
          if len(non_str_index_names) > 0:
              warnings.warn(
                  f"The DataFrame has non-str index name `{non_str_index_names}`"
                  " which will be converted to string"
                  " and not roundtrip correctly.",
                  UserWarning,
                  stacklevel=4,
              )
  
          column_indexes = []
  
          levels = getattr(df.columns, "levels", [df.columns])
          names = getattr(df.columns, "names", [df.columns.name])
          for level, name in zip(levels, names):
              metadata = _get_simple_index_descriptor(level, name)
              column_indexes.append(metadata)
      else:
          index_descriptors = (
              index_column_metadata
          ) = column_indexes = []
  
      return {
          b"pandas": json.dumps(
              {
                  "index_columns": index_descriptors,
                  "column_indexes": column_indexes,
                  "columns": column_metadata + index_column_metadata,
                  "creator": {
                      "library": "pyarrow",
                      "version": pa.__version__,
                  },
                  "pandas_version": _pandas_api.version,
              }
          ).encode("utf8")
      }
  
imports: import ast
  from collections.abc import Sequence
  from concurrent import futures
  import concurrent.futures.thread
  from copy import deepcopy
  from itertools import zip_longest
  import json
  import operator
  import re
  import warnings
  import numpy
  import pyarrow
  from pyarrow.lib import _pandas_api, frombytes
label_desc: Use image node_id 6 for calling a global function with example usage: construct_metadata(columns_to_convert, df, column_names, index_levels, index_descriptors, preserve_index, types) and returns: dict