code: def import_matrix_table(
      paths,
      row_fields={},
      row_key=[],
      entry_type=tint32,
      missing="NA",
      min_partitions=None,
      no_header=False,
      force_bgz=False,
      sep=None,
      delimiter=None,
      comment=(),
  ) -> MatrixTable:
      """Import tab-delimited file(s) as a :class:`.MatrixTable`.
  
      Examples
      --------
  
          Consider the following file containing counts from a RNA sequencing
          dataset:
  
      .. code-block:: text
  
          $ cat data/matrix1.tsv
          Barcode Tissue  Days    GENE1   GENE2   GENE3   GENE4
          TTAGCCA brain   1.0     0       0       1       0
          ATCACTT kidney  5.5     3       0       2       0
          CTCTTCT kidney  2.5     0       0       0       1
          CTATATA brain   7.0     0       0       3       0
  
      The field ``Days`` contains floating-point numbers and each of the ``GENE`` fields contain integers.
      contains integers.
  
      To import this matrix:
  
      >>> matrix1 = hl.import_matrix_table('data/matrix1.tsv',
      ...                                  row_fields={'Barcode': hl.tstr, 'Tissue': hl.tstr, 'Days':hl.tfloat32},
      ...                                  row_key='Barcode')
      >>> matrix1.describe()  # doctest: +SKIP_OUTPUT_CHECK
      ----------------------------------------
      Global fields:
          None
      ----------------------------------------
      Column fields:
          'col_id': str
      ----------------------------------------
      Row fields:
          'Barcode': str
          'Tissue': str
          'Days': float32
      ----------------------------------------
      Entry fields:
          'x': int32
      ----------------------------------------
      Column key:
          'col_id': str
      Row key:
          'Barcode': str
      ----------------------------------------
  
      In this example, the header information is missing for the row fields, but
      the column IDs are still present:
  
      .. code-block:: text
  
          $ cat data/matrix2.tsv
          GENE1   GENE2   GENE3   GENE4
          TTAGCCA brain   1.0     0       0       1       0
          ATCACTT kidney  5.5     3       0       2       0
          CTCTTCT kidney  2.5     0       0       0       1
          CTATATA brain   7.0     0       0       3       0
  
      The row fields get imported as `f0`, `f1`, and `f2`, so we need to do:
  
      >>> matrix2 = hl.import_matrix_table('data/matrix2.tsv',
      ...                                  row_fields={'f0': hl.tstr, 'f1': hl.tstr, 'f2':hl.tfloat32},
      ...                                  row_key='f0')
      >>> matrix2.rename({'f0': 'Barcode', 'f1': 'Tissue', 'f2': 'Days'})
  
      Sometimes, the header and row information is missing completely:
  
      .. code-block:: text
  
          $ cat data/matrix3.tsv
          0       0       1       0
          3       0       2       0
          0       0       0       1
          0       0       3       0
  
      >>> matrix3 = hl.import_matrix_table('data/matrix3.tsv', no_header=True)
  
      In this case, the file has no row fields, so we use the default
      row index as a key for the imported matrix table.
  
      Notes
      -----
  
      The resulting matrix table has the following structure:
  
          * The row fields are named as specified in the column header. If they
            are missing from the header or ``no_header=True``, row field names are
            set to the strings `f0`, `f1`, ... (0-indexed) in column order. The types
            of all row fields must be specified in the `row_fields` argument.
          * The row key is taken from the `row_key` argument, and must be a
            subset of row fields. If left empty, the row key will be a new row field
            `row_id` of type :obj:`int`, whose values 0, 1, ... index the original
            rows of the matrix.
          * There is one column field, **col_id**, which is a key field of type
            :obj:str or :obj:int. By default, its values are the strings given by
            the corresponding column names in the header line. If ``no_header=True``,
            column IDs are set to integers 0, 1, ... (also 0-indexed) in column
            order.
          * There is one entry field, **x**, that contains the data from the imported
            matrix.
  
  
      All columns to be imported as row fields must be at the start of the row.
  
      Unlike :func:`import_table`, no type imputation is done so types must be specified
      for all columns that should be imported as row fields. (The other columns are
      imported as entries in the matrix.)
  
      The header information for row fields is allowed to be missing, if the
      column IDs are present, but the header must then consist only of tab-delimited
      column IDs (no row field names).
  
      The column IDs will never be missing, even if the `missing` string appears
      in the column IDs.
  
      Parameters
      ----------
      paths: :class:`str` or :obj:`list` of :obj:`str`
          Files to import.
      row_fields: :obj:`dict` of :class:`str` to :class:`.HailType`
          Columns to take as row fields in the MatrixTable. They must be located
          before all entry columns.
      row_key: :class:`str` or :obj:`list` of :obj:`str`
          Key fields(s). If empty, creates an index `row_id` to use as key.
      entry_type: :class:`.HailType`
          Type of entries in matrix table. Must be one of: :py:data:`.tint32`,
          :py:data:`.tint64`, :py:data:`.tfloat32`, :py:data:`.tfloat64`, or
          :py:data:`.tstr`. Default: :py:data:`.tint32`.
      missing: :class:`str`
          Identifier to be treated as missing. Default: NA
      min_partitions: :obj:`int` or :obj:`None`
          Minimum number of partitions.
      no_header: :obj:`bool`
          If ``True``, assume the file has no header and name the row fields `f0`,
          `f1`, ... `fK` (0-indexed) and the column keys 0, 1, ... N.
      force_bgz : :obj:`bool`
          If ``True``, load **.gz** files as blocked gzip files, assuming
          that they were actually compressed using the BGZ codec.
      sep : :class:`str`
          This parameter is a deprecated name for `delimiter`, please use that
          instead.
      delimiter : :class:`str`
          A single character string which separates values in the file.
      comment : :class:`str` or :obj:`list` of :obj:`str`
          Skip lines beginning with the given string if the string is a single
          character. Otherwise, skip lines that match the regex specified. Multiple
          comment characters or patterns should be passed as a list.
  
      Returns
      -------
      :class:`.MatrixTable`
          MatrixTable constructed from imported data.
      """
      row_key = wrap_to_list(row_key)
      comment = wrap_to_list(comment)
      paths = [
          hl.current_backend().fs.canonicalize_path(p)
          for p in wrap_to_list(paths)
      ]
      missing_list = wrap_to_list(missing)
  
      def comment_filter(table):
          return (
              hl.rbind(
                  hl.array(comment),
                  lambda hl_comment: hl_comment.any(
                      lambda com: hl.if_else(
                          hl.len(com) == 1,
                          table.text.startswith(com),
                          table.text.matches(com, False),
                      )
                  ),
              )
              if len(comment) > 0
              else False
          )
  
      def truncate(string_array, delim=", "):
          if len(string_array) > 10:
              string_array = string_array[:10]
              string_array.append("...")
          return delim.join(string_array)
  
      path_to_index = {path: idx for idx, path in enumerate(paths)}
  
      def format_file(file_name, hl_value=False):
          if hl_value:
              return hl.rbind(
                  file_name.split("/"),
                  lambda split_file: hl.if_else(
                      hl.len(split_file) <= 4,
                      hl.str("/").join(file_name.split("/")[-4:]),
                      hl.str("/")
                      + hl.str("/").join(file_name.split("/")[-4:]),
                  ),
              )
          else:
              return (
                  "/".join(file_name.split("/")[-3:])
                  if len(file_name) <= 4
                  else "/" + "/".join(file_name.split("/")[-3:])
              )
  
      file_start_array = None
  
      def get_file_start(row):
          nonlocal file_start_array
          if file_start_array is None:
              collect_expr = first_lines_table.collect(
                  _localize=False
              ).map(lambda line: (line.file, line.idx))
              file_start_array = hl.literal(
                  hl.eval(collect_expr), dtype=collect_expr.dtype
              )
          return hl.coalesce(
              file_start_array.filter(
                  lambda line_tuple: line_tuple[0] == row.file
              )
              .map(lambda line_tuple: line_tuple[1])
              .first(),
              0,
          )
  
      def validate_row_fields():
          unique_fields = {}
          duplicates = []
          header_idx = 0
          for header_rowf in header_dict["row_fields"]:
              rowf_type = row_fields.get(header_rowf)
              if rowf_type is None:
                  import itertools as it
  
                  row_fields_string = "\n".join(
                      list(
                          it.starmap(
                              lambda row_field, row_type: f"      '{row_field}': {str(row_type)}",
                              row_fields.items(),
                          )
                      )
                  )
                  header_fields_string = "\n      ".join(
                      map(
                          lambda field: f"'{field}'",
                          header_dict["row_fields"],
                      )
                  )
                  raise FatalError(
                      f"in file {format_file(header_dict['path'])} found row field '{header_rowf}' that's"
                      f" not in 'row fields'\nrow fields found in file:\n      {header_fields_string}"
                      f"\n'row fields':\n{row_fields_string}"
                  )
              if header_rowf in unique_fields:
                  duplicates.append(header_rowf)
              else:
                  unique_fields[header_rowf] = True
              header_idx += 1
          if len(duplicates) > 0:
              raise FatalError(
                  "Found following duplicate row fields in header:\n"
                  + "\n".join(duplicates)
              )
  
      def parse_entries(row):
          return hl.range(
              num_of_row_fields,
              len(header_dict["column_ids"]) + num_of_row_fields,
          ).map(
              lambda entry_idx: parse_type_or_error(
                  entry_type, row, entry_idx, not_entries=False
              )
          )
  
      def parse_rows(row):
          rows_list = list(row_fields.items())
          return {
              rows_list[idx][0]: parse_type_or_error(
                  rows_list[idx][1], row, idx
              )
              for idx in range(num_of_row_fields)
          }
  
      def error_msg(row, idx, msg):
          return (
              hl.str("in file ")
              + hl.str(format_file(row.file, True))
              + hl.str(" on line ")
              + hl.str(row.row_id - get_file_start(row) + 1)
              + hl.str(" at value '")
              + hl.str(row.split_array[idx])
              + hl.str("':\n")
              + hl.str(msg)
          )
  
      def parse_type_or_error(hail_type, row, idx, not_entries=True):
          value = row.split_array[idx]
          if hail_type == hl.tint32:
              parsed_type = hl.parse_int32(value)
          elif hail_type == hl.tint64:
              parsed_type = hl.parse_int64(value)
          elif hail_type == hl.tfloat32:
              parsed_type = hl.parse_float32(value)
          elif hail_type == hl.tfloat64:
              parsed_type = hl.parse_float64(value)
          else:
              parsed_type = value
  
          if not_entries:
              error_clarify_msg = (
                  hl.str(" at row field '")
                  + hl.str(hl_row_fields[idx])
                  + hl.str("'")
              )
          else:
              error_clarify_msg = (
                  hl.str(" at column id '")
                  + hl.str(hl_columns[idx - num_of_row_fields])
                  + hl.str("' for entry field 'x' ")
              )
  
          return hl.if_else(
              hl.is_missing(value),
              hl.missing(hail_type),
              hl.case()
              .when(~hl.is_missing(parsed_type), parsed_type)
              .or_error(
                  error_msg(
                      row,
                      idx,
                      f"error parsing value into {str(hail_type)}"
                      + error_clarify_msg,
                  )
              ),
          )
  
      num_of_row_fields = len(row_fields.keys())
      add_row_id = False
      if len(row_key) == 0:
          add_row_id = True
          row_key = ["row_id"]
  
      if sep is not None:
          if delimiter is not None:
              raise ValueError(
                  f"expecting either sep or delimiter but received both: "
                  f"{sep}, {delimiter}"
              )
          delimiter = sep
      del sep
  
      if delimiter is None:
          delimiter = "\t"
      if len(delimiter) != 1:
          raise FatalError(
              "delimiter or sep must be a single character"
          )
  
      if add_row_id:
          if "row_id" in row_fields:
              raise FatalError(
                  "import_matrix_table reserves the field name 'row_id' for"
                  "its own use, please use a different name"
              )
  
      for k, v in row_fields.items():
          if v not in {tint32, tint64, tfloat32, tfloat64, tstr}:
              raise FatalError(
                  f"import_matrix_table expects field types to be one of:"
                  f"'int32', 'int64', 'float32', 'float64', 'str': field {repr(k)} had type '{v}'"
              )
  
      if entry_type not in {tint32, tint64, tfloat32, tfloat64, tstr}:
          raise FatalError(
              """import_matrix_table expects entry types to be one of:
          'int32', 'int64', 'float32', 'float64', 'str': found '{}'""".format(
                  entry_type
              )
          )
  
      if missing in delimiter:
          raise FatalError(
              f"Missing value {missing} contains delimiter {delimiter}"
          )
  
      ht = import_lines(
          paths, min_partitions, force_bgz=force_bgz
      ).add_index(name="row_id")
      # for checking every header matches
      file_per_partition = import_lines(
          paths, force_bgz=force_bgz, file_per_partition=True
      )
      file_per_partition = file_per_partition.filter(
          hl.bool(hl.len(file_per_partition.text) == 0)
          | comment_filter(file_per_partition),
          False,
      )
      first_lines_table = file_per_partition._map_partitions(
          lambda rows: rows.take(1)
      )
      first_lines_table = first_lines_table.annotate(
          split_array=first_lines_table.text.split(delimiter)
      ).add_index()
  
      if not no_header:
  
          def validate_header_get_info_dict():
              two_first_lines = file_per_partition.head(2)
              two_first_lines = two_first_lines.annotate(
                  split_array=two_first_lines.text.split(delimiter)
              ).collect()
              header_line = (
                  two_first_lines[0] if two_first_lines else None
              )
              first_data_line = (
                  two_first_lines[1]
                  if len(two_first_lines) > 1
                  else None
              )
              num_of_data_line_values = (
                  len(first_data_line.split_array)
                  if len(two_first_lines) > 1
                  else 0
              )
              num_of_header_values = (
                  len(header_line.split_array) if two_first_lines else 0
              )
              if (
                  header_line is None
                  or path_to_index[header_line.file] != 0
              ):
                  raise ValueError(
                      f"Expected header in every file but found empty file: {format_file(paths[0])}"
                  )
              elif (
                  not first_data_line
                  or first_data_line.file != header_line.file
              ):
                  hl.utils.warning(
                      f"File {format_file(header_line.file)} contains a header, but no lines of data"
                  )
                  if num_of_header_values < num_of_data_line_values:
                      raise ValueError(
                          f"File {format_file(header_line.file)} contains one line assumed to be the header."
                          f"The header had a length of {num_of_header_values} while the number"
                          f"of row fields is {num_of_row_fields}"
                      )
                  user_row_fields = header_line.split_array[
                      :num_of_row_fields
                  ]
                  column_ids = header_line.split_array[
                      num_of_row_fields:
                  ]
              elif num_of_data_line_values != num_of_header_values:
                  if (
                      num_of_data_line_values
                      == num_of_header_values + num_of_row_fields
                  ):
                      user_row_fields = [
                          "f" + str(f_idx)
                          for f_idx in list(range(0, num_of_row_fields))
                      ]
                      column_ids = header_line.split_array
                  else:
                      raise ValueError(
                          f"In file {format_file(header_line.file)}, expected the header line to match either:\n"
                          f"rowField0 rowField1 ... rowField${num_of_row_fields} colId0 colId1 ...\nor\n"
                          f" colId0 colId1 ...\nInstead the first two lines were:\nInstead the first two lin"
                          f"es were:\n{header_line.text}\n{first_data_line.text}\nThe first line contained"
                          f" {num_of_header_values} separated values and the second line"
                          f" contained {num_of_data_line_values}"
                      )
              else:
                  user_row_fields = header_line.split_array[
                      :num_of_row_fields
                  ]
                  column_ids = header_line.split_array[
                      num_of_row_fields:
                  ]
              return {
                  "text": header_line.text,
                  "header_values": header_line.split_array,
                  "path": header_line.file,
                  "row_fields": user_row_fields,
                  "column_ids": column_ids,
              }
  
          def warn_if_duplicate_col_ids():
              time_col_id_encountered_dict = {}
              duplicate_cols = []
              for item in header_dict["column_ids"]:
                  if time_col_id_encountered_dict.get(item) is not None:
                      duplicate_cols.append(item)
                      time_col_id_encountered_dict[item] = (
                          time_col_id_encountered_dict[item] + 1
                      )
                  time_col_id_encountered_dict[item] = 1
              if len(duplicate_cols) == 0:
                  return
  
              import itertools as it
  
              duplicates_to_print = sorted(
                  [
                      (
                          '"' + dup_field + '"',
                          "("
                          + str(time_col_id_encountered_dict[dup_field])
                          + ")",
                      )
                      for dup_field in duplicate_cols
                  ],
                  key=lambda dup_values: dup_values[1],
              )
  
              duplicates_to_print = truncate(duplicates_to_print)
              duplicates_to_print_formatted = it.starmap(
                  lambda dup, time_found: time_found + " " + dup,
                  duplicates_to_print,
              )
              ht.utils.warning(
                  f"Found {len(duplicate_cols)} duplicate column id"
                  + f"{'s' if len(duplicate_cols) > 1 else ''}\n"
                  + "\n".join(duplicates_to_print_formatted)
              )
  
          def validate_all_headers():
              all_headers = first_lines_table.collect()
              for header in all_headers:
                  if header_dict["text"] != header.text:
                      if len(header_dict["header_values"]) == len(
                          header.split_array
                      ):
                          zipped_headers = list(
                              zip(
                                  header_dict["header_values"],
                                  header.split_array,
                              )
                          )
                          for header_idx, header_values in enumerate(
                              zipped_headers
                          ):
                              main_header_value = header_values[0]
                              error_header_value = header_values[1]
                              if (
                                  main_header_value
                                  != error_header_value
                              ):
                                  raise ValueError(
                                      "invalid header: expected elements to be identical for all input paths"
                                      f". Found different elements at position {header_idx + 1}"
                                      f"\n in file {format_file(header.file)} with value "
                                      f"'{error_header_value}' when expecting value '{main_header_value}'"
                                  )
                      else:
                          raise ValueError(
                              f"invalid header: lengths of headers differ. \n"
                              f"{len(header_dict['header_values'])} elements in "
                              f"{format_file(header_dict['path'])}:\n"
                              + truncate(
                                  [
                                      "'{}'".format(value)
                                      for value in header_dict[
                                          "header_values"
                                      ]
                                  ]
                              )
                              + f" {len(header.split_array)} elements in {format_file(header.file)}:\n"
                              + truncate(
                                  [
                                      "'{}'".format(value)
                                      for value in header.split_array
                                  ]
                              )
                          )
  
          header_dict = validate_header_get_info_dict()
          warn_if_duplicate_col_ids()
          validate_all_headers()
  
      else:
          first_line = first_lines_table.head(1).collect()
          if not first_line or path_to_index[first_line[0].file] != 0:
              hl.utils.warning(
                  f"File {format_file(paths[0])} is empty and has no header, so we assume no columns"
              )
              header_dict = {
                  "header_values": [],
                  "row_fields": [
                      "f" + str(f_idx)
                      for f_idx in list(range(0, num_of_row_fields))
                  ],
                  "column_ids": [],
              }
          else:
              first_line = first_line[0]
              header_dict = {
                  "header_values": [],
                  "row_fields": [
                      "f" + str(f_idx)
                      for f_idx in list(range(0, num_of_row_fields))
                  ],
                  "column_ids": [
                      col_id
                      for col_id in list(
                          range(
                              0,
                              len(first_line.split_array)
                              - num_of_row_fields,
                          )
                      )
                  ],
              }
  
      validate_row_fields()
      header_filter = (
          ht.text == header_dict["text"] if not no_header else False
      )
  
      ht = ht.filter(
          hl.bool(hl.len(ht.text) == 0)
          | comment_filter(ht)
          | header_filter,
          False,
      )
  
      hl_columns = (
          hl.array(header_dict["column_ids"])
          if len(header_dict["column_ids"]) > 0
          else hl.empty_array(hl.tstr)
      )
      hl_row_fields = (
          hl.array(header_dict["row_fields"])
          if len(header_dict["row_fields"]) > 0
          else hl.empty_array(hl.tstr)
      )
      ht = ht.annotate(
          split_array=ht.text._split_line(
              delimiter, missing_list, quote=None, regex=False
          )
      ).add_index("row_id")
  
      ht = ht.annotate(
          split_array=hl.case()
          .when(
              hl.len(ht.split_array) >= num_of_row_fields,
              ht.split_array,
          )
          .or_error(
              error_msg(
                  ht,
                  hl.len(ht.split_array) - 1,
                  " unexpected end of line while reading row field",
              )
          )
      )
  
      n_column_ids = len(header_dict["column_ids"])
      n_in_split_array = hl.len(
          ht.split_array[
              num_of_row_fields : (num_of_row_fields + n_column_ids)
          ]
      )
      ht = ht.annotate(
          split_array=hl.case()
          .when(n_column_ids <= n_in_split_array, ht.split_array)
          .or_error(
              error_msg(
                  ht,
                  hl.len(ht.split_array) - 1,
                  " unexpected end of line while reading entries",
              )
          )
      )
  
      ht = ht.annotate(
          **parse_rows(ht),
          entries=parse_entries(ht).map(
              lambda entry: hl.struct(x=entry)
          ),
      ).drop("text", "split_array", "file")
  
      ht = ht.annotate_globals(
          cols=hl.range(0, len(header_dict["column_ids"])).map(
              lambda col_idx: hl.struct(col_id=hl_columns[col_idx])
          )
      )
  
      if not add_row_id:
          ht = ht.drop("row_id")
  
      mt = ht._unlocalize_entries("entries", "cols", ["col_id"])
      mt = mt.key_rows_by(*row_key)
      return mt
  
imports: import os
  import re
  from collections import defaultdict
  import avro.schema
  from avro.datafile import DataFileReader
  from avro.io import DatumReader
  import hail
  from hail import ir
  from hail.expr import StructExpression, LocusExpression, expr_array, expr_float64, expr_str, expr_numeric, expr_call, expr_bool, expr_int32, to_expr, analyze
  from hail.expr.types import hail_type, tarray, tfloat64, tstr, tint32, tstruct, tcall, tbool, tint64, tfloat32
  from hail.genetics.reference_genome import reference_genome_type
  from hail.ir.utils import parse_type
  from hail.matrixtable import MatrixTable
  from hail.methods.misc import require_biallelic, require_row_key_variant, require_col_key_str
  from hail.table import Table
  from hail.typecheck import typecheck, nullable, oneof, dictof, anytype, sequenceof, enumeration, sized_tupleof, numeric, table_key_type, char
  from hail.utils import new_temp_file
  from hail.utils.deduplicate import deduplicate
  from hail.utils.java import Env, FatalError, jindexed_seq_args, warning
  from hail.utils.java import info
  from hail.utils.misc import wrap_to_list, plural
  from .import_lines_helpers import split_lines, should_remove_line
label_desc: Use image node_id 15 for calling a global function with example usage: import_matrix_table(paths, row_fields, row_key, entry_type, missing, min_partitions, no_header, force_bgz, sep, delimiter, comment) and returns: mt, unknown, delim, hl, hl, unknown, unknown, hl, hl, unknown, dict