code: def vstack(data_frames: List["DataFrame"]) -> "DataFrame":
      frame_0 = data_frames[0]
      data_frames = list(filter(lambda df: df.shape[0], data_frames))
      if len(data_frames) <= 1:
          return frame_0 if not data_frames else data_frames[0]
  
      def _align_blocks(
          blocks,
          align_fields_loc=None,
          full_block_migrate_set=None,
          dst_dm: DataManager = None,
      ):
          ret_blocks, lines = [], None
          for dst_bid, block in enumerate(dst_dm.blocks):
              _field_indexes = block.field_indexes
              _src_bid = align_fields_loc[_field_indexes[0]][0]
              if _src_bid in full_block_migrate_set:
                  ret_blocks.append(blocks[_src_bid])
              else:
                  _align_block = []
                  lines = len(blocks[0]) if lines is None else lines
                  for lid in range(lines):
                      row = []
                      for _field_index in _field_indexes:
                          _src_bid, _offset = align_fields_loc[
                              _field_index
                          ]
                          row.append(
                              blocks[_src_bid][lid][_offset].item()
                              if isinstance(
                                  blocks[_src_bid], torch.Tensor
                              )
                              else blocks[_src_bid][lid][_offset]
                          )
  
                      _align_block.append(row)
  
                  ret_blocks.append(
                      dst_dm.blocks[dst_bid].convert_block(_align_block)
                  )
  
          return ret_blocks
  
      l_df = data_frames[0]
      data_manager = l_df.data_manager.duplicate()
      l_fields_loc = data_manager.get_fields_loc()
      l_field_names = data_manager.get_field_name_list()
      l_field_types = [
          data_manager.get_block(_bid).block_type
          for _bid, _ in l_fields_loc
      ]
      l_block_table = l_df.block_table
      type_change = False
      for r_df in data_frames[1:]:
          if set(l_df.schema.columns) != set(r_df.schema.columns):
              raise ValueError(
                  "vstack of dataframes should have same schemas"
              )
  
          for idx, field_name in enumerate(l_field_names):
              block_type = r_df.data_manager.get_block(
                  r_df.data_manager.loc_block(
                      field_name, with_offset=False
                  )
              ).block_type
              if block_type > l_field_types[idx]:
                  l_field_types[idx] = block_type
                  type_change = True
  
      if type_change:
          changed_fields, changed_block_types, changed_fields_loc = (
              [],
              [],
              [],
          )
          changed_block_types = []
          for idx in range(len(l_field_names)):
              field_name, block_type, (bid, offset) = (
                  l_field_names[idx],
                  l_field_types[idx],
                  l_fields_loc[idx],
              )
              if block_type != data_manager.get_block(bid).block_type:
                  changed_fields.append(field_name)
                  changed_block_types.append(block_type)
                  changed_fields_loc.append((bid, offset))
  
          narrow_blocks, dst_blocks = data_manager.split_columns(
              changed_fields, changed_block_types
          )
          l_block_table = promote_partial_block_types(
              l_block_table,
              narrow_blocks=narrow_blocks,
              dst_blocks=dst_blocks,
              data_manager=data_manager,
              dst_fields_loc=changed_fields_loc,
          )
  
      for r_df in data_frames[1:]:
          r_field_names = r_df.data_manager.get_field_name_list()
          r_fields_loc = r_df.data_manager.get_fields_loc()
          r_field_types = [
              data_manager.get_block(_bid).block_type
              for _bid, _ in r_fields_loc
          ]
          r_type_change = (
              False if l_field_types == r_field_types else True
          )
          r_block_table = r_df.block_table
          if l_field_names != r_field_names or r_type_change:
              shuffle_r_fields_loc, full_migrate_set = [
                  () for _ in range(len(r_field_names))
              ], set()
              for field_name, loc in zip(r_field_names, r_fields_loc):
                  l_offset = data_manager.get_field_offset(field_name)
                  shuffle_r_fields_loc[l_offset] = loc
  
              for bid in range(r_df.data_manager.block_num):
                  r_field_indexes = r_df.data_manager.get_block(
                      bid
                  ).field_indexes
                  field_indexes = [
                      data_manager.get_field_offset(r_field_names[idx])
                      for idx in r_field_indexes
                  ]
                  l_bid = data_manager.loc_block(
                      r_field_names[r_field_indexes[0]],
                      with_offset=False,
                  )
                  if (
                      field_indexes
                      == data_manager.get_block(l_bid).field_indexes
                  ):
                      full_migrate_set.add(bid)
  
              _align_func = functools.partial(
                  _align_blocks,
                  align_fields_loc=shuffle_r_fields_loc,
                  full_block_migrate_set=full_migrate_set,
                  dst_dm=data_manager,
              )
              r_block_table = r_block_table.mapValues(_align_func)
  
          l_block_table = l_block_table.union(
              r_block_table,
              lambda l_blocks, r_blocks: [
                  Block.vstack([l_block, r_block])
                  for l_block, r_block in zip(l_blocks, r_blocks)
              ],
          )
  
      partition_order_mappings = (
          get_partition_order_mappings_by_block_table(
              l_block_table, data_manager.block_row_size
          )
      )
      _balance_block_func = functools.partial(
          _balance_blocks,
          partition_order_mappings=partition_order_mappings,
          block_row_size=data_manager.block_row_size,
      )
      l_block_table = l_block_table.mapPartitions(
          _balance_block_func, use_previous_behavior=False
      )
      l_block_table, data_manager = compress_blocks(
          l_block_table, data_manager
      )
  
      return DataFrame(
          l_df._ctx,
          l_block_table,
          partition_order_mappings,
          data_manager,
      )
  
imports: import copy
  import functools
  from typing import List, Union
  import torch
  from sklearn.utils import resample
  from .._dataframe import DataFrame
  from ..manager.data_manager import DataManager
  from ..manager.block_manager import Block
  from ._compress_block import compress_blocks
  from ._indexer import get_partition_order_by_raw_table, get_partition_order_mappings_by_block_table
  from ._promote_types import promote_partial_block_types
  from ._set_item import set_item
  from fate.arch.tensor import DTensor
label_desc: Use image node_id 2 for calling a global function with example usage: vstack(data_frames) and returns: DataFrame, unknown, ret_blocks