code: def _get_mgr_concatenation_plan(
      mgr: BlockManager, indexers: dict[int, np.ndarray]
  ):
      """
      Construct concatenation plan for given block manager and indexers.
  
      Parameters
      ----------
      mgr : BlockManager
      indexers : dict of {axis: indexer}
  
      Returns
      -------
      plan : list of (BlockPlacement, JoinUnit) tuples
  
      """
      assert len(indexers) == 0
  
      # Calculate post-reindex shape, save for item axis which will be separate
      # for each block anyway.
      mgr_shape_list = list(mgr.shape)
      for ax, indexer in indexers.items():
          mgr_shape_list[ax] = len(indexer)
      mgr_shape = tuple(mgr_shape_list)
  
      assert 0 not in indexers
  
      if mgr.is_single_block:
          blk = mgr.blocks[0]
          return [(blk.mgr_locs, JoinUnit(blk, mgr_shape, indexers))]
  
      blknos = mgr.blknos
      blklocs = mgr.blklocs
  
      plan = []
      for blkno, placements in libinternals.get_blkno_placements(
          blknos, group=False
      ):
          assert placements.is_slice_like
          assert blkno != -1
  
          join_unit_indexers = indexers.copy()
  
          shape_list = list(mgr_shape)
          shape_list[0] = len(placements)
          shape = tuple(shape_list)
  
          blk = mgr.blocks[blkno]
          ax0_blk_indexer = blklocs[placements.indexer]
  
          unit_no_ax0_reindexing = (
              len(placements) == len(blk.mgr_locs)
              and
              # Fastpath detection of join unit not
              # needing to reindex its block: no ax0
              # reindexing took place and block
              # placement was sequential before.
              (
                  (
                      blk.mgr_locs.is_slice_like
                      and blk.mgr_locs.as_slice.step == 1
                  )
                  or
                  # Slow-ish detection: all indexer locs
                  # are sequential (and length match is
                  # checked above).
                  (np.diff(ax0_blk_indexer) == 1).all()
              )
          )
  
          # Omit indexer if no item reindexing is required.
          if unit_no_ax0_reindexing:
              join_unit_indexers.pop(0, None)
          else:
              join_unit_indexers[0] = ax0_blk_indexer
  
          unit = JoinUnit(blk, shape, join_unit_indexers)
  
          plan.append((placements, unit))
  
      return plan
  
imports: from __future__ import annotations
  import copy
  import itertools
  from typing import TYPE_CHECKING, Sequence, cast
  import numpy
  from pandas._libs import NaT, internals
  from pandas._libs.missing import NA
  from pandas._typing import ArrayLike, AxisInt, DtypeObj, Manager, Shape
  from pandas.util._decorators import cache_readonly
  from pandas.core.dtypes.astype import astype_array
  from pandas.core.dtypes.cast import ensure_dtype_can_hold_na, find_common_type, np_find_common_type
  from pandas.core.dtypes.common import is_1d_only_ea_dtype, is_dtype_equal, is_scalar, needs_i8_conversion
  from pandas.core.dtypes.concat import concat_compat
  from pandas.core.dtypes.dtypes import DatetimeTZDtype, ExtensionDtype
  from pandas.core.dtypes.missing import is_valid_na_for_dtype, isna, isna_all
  import pandas.core.algorithms
  from pandas.core.arrays import DatetimeArray, ExtensionArray
  from pandas.core.arrays.sparse import SparseDtype
  from pandas.core.construction import ensure_wrapped_if_datetimelike
  from pandas.core.internals.array_manager import ArrayManager, NullArrayProxy
  from pandas.core.internals.blocks import ensure_block_shape, new_block_2d
  from pandas.core.internals.managers import BlockManager
label_desc: Use image node_id 6 for calling a global function with example usage: _get_mgr_concatenation_plan(mgr, indexers) and returns: plan, list