docs: def dump_metadata(filename, show_row_group_metadata, out=sys.stdout):
      """Dump metadata about the parquet object with the given filename.
  
      Dump human-readable metadata to specified `out`. Optionally dump the row group metadata as well.
      """
      def println(value):
          """Write a new line containing `value` to `out`."""
          out.write(value + "\n")
      footer = read_footer(filename)
      println("File Metadata: {0}".format(filename))
      println("  Version: {0}".format(footer.version))
      println("  Num Rows: {0}".format(footer.num_rows))
      println("  k/v metadata: ")
      if footer.key_value_metadata:
          for item in footer.key_value_metadata:
              println("    {0}={1}".format(item.key, item.value))
      else:
          println("    (none)")
      println("  schema: ")
      for element in footer.schema:
          println("    {name} ({type}): length={type_length}, "
                  "repetition={repetition_type}, "
                  "children={num_children}, "
                  "converted_type={converted_type}".format(
                      name=element.name,
                      type=parquet_thrift.Type._VALUES_TO_NAMES[element.type]  # pylint: disable=protected-access
                      if element.type else None,
                      type_length=element.type_length,
                      repetition_type=_get_name(parquet_thrift.FieldRepetitionType,
                                                element.repetition_type),
                      num_children=element.num_children,
                      converted_type=element.converted_type))
      if show_row_group_metadata:
          println("  row groups: ")
          for row_group in footer.row_groups:
              num_rows = row_group.num_rows
              size_bytes = row_group.total_byte_size
              println(
                  "  rows={num_rows}, bytes={bytes}".format(num_rows=num_rows,
                                                            bytes=size_bytes))
              println("    chunks:")
              for col_group in row_group.columns:
                  cmd = col_group.meta_data
                  println("      type={type} file_offset={offset} "
                          "compression={codec} "
                          "encodings={encodings} path_in_schema={path_in_schema} "
                          "num_values={num_values} uncompressed_bytes={raw_bytes} "
                          "compressed_bytes={compressed_bytes} "
                          "data_page_offset={data_page_offset} "
                          "dictionary_page_offset={dictionary_page_offset}".format(
                              type=_get_name(parquet_thrift.Type, cmd.type),
                              offset=col_group.file_offset,
                              codec=_get_name(parquet_thrift.CompressionCodec, cmd.codec),
                              encodings=",".join(
                                  [_get_name(
                                      parquet_thrift.Encoding, s) for s in cmd.encodings]),
                              path_in_schema=cmd.path_in_schema,
                              num_values=cmd.num_values,
                              raw_bytes=cmd.total_uncompressed_size,
                              compressed_bytes=cmd.total_compressed_size,
                              data_page_offset=cmd.data_page_offset,
                              dictionary_page_offset=cmd.dictionary_page_offset))
                  with open(filename, 'rb') as file_obj:
                      offset = _get_offset(cmd)
                      file_obj.seek(offset, 0)
                      values_read = 0
                      println("      pages: ")
                      while values_read < num_rows:
                          page_header = _read_page_header(file_obj)
                          # seek past current page.
                          file_obj.seek(page_header.compressed_page_size, 1)
                          daph = page_header.data_page_header
                          type_ = _get_name(parquet_thrift.PageType, page_header.type)
                          raw_bytes = page_header.uncompressed_page_size
                          num_values = None
                          if page_header.type == parquet_thrift.PageType.DATA_PAGE:
                              num_values = daph.num_values
                              values_read += num_values
                          if page_header.type == parquet_thrift.PageType.DICTIONARY_PAGE:
                              pass
  
                          encoding_type = None
                          def_level_encoding = None
                          rep_level_encoding = None
                          if daph:
                              encoding_type = _get_name(parquet_thrift.Encoding, daph.encoding)
                              def_level_encoding = _get_name(
                                  parquet_thrift.Encoding, daph.definition_level_encoding)
                              rep_level_encoding = _get_name(
                                  parquet_thrift.Encoding, daph.repetition_level_encoding)
  
                          println("        page header: type={type} "
                                  "uncompressed_size={raw_bytes} "
                                  "num_values={num_values} encoding={encoding} "
                                  "def_level_encoding={def_level_encoding} "
                                  "rep_level_encoding={rep_level_encoding}".format(
                                      type=type_,
                                      raw_bytes=raw_bytes,
                                      num_values=num_values,
                                      encoding=encoding_type,
                                      def_level_encoding=def_level_encoding,
                                      rep_level_encoding=rep_level_encoding))