Iterate over a DAVID result set and yeild GeneOntologyTerm objects
  representing each of the terms reported. The expected format for a DAVID
  result file is tab-seperated format. The following fields should be present:

  ===  ===============  ==========  ====================================
  Num  Field                 Type        Example
  ===  ===============  ==========  ====================================
  0    Category         string      GOTERM_BP_FAT
  1    Term             string      GO:0046907~intracellular transport
  2    Count            int         43
  3    Percent          float       11.345646437994723
  4    PValue           float       1.3232857694449546E-9
  5    Genes            string      ARSB, KPNA6, GNAS
  6    List Total       int         310
  7    Pop Hits         int         657
  8    Pop Total        int         13528
  9    Fold Enrichment  float       2.8561103746256196
  10   Bonferroni       float       2.6293654579179204E-6
  11   Benjamini        float       2.6293654579179204E-6
  12   FDR              float       2.2734203852792234E-6
  ===  ===============  ==========  ====================================

  The first line is a header giving the field names -- this is ignored though,
  and we expect them in the order given above.

  Most of the fields are ignored at present; we take fields 0,1, and 11 (as the
  significance/p-value). When parsing the term field, we try to extract a term
  ID by splitting on tilde, but if we can't then this is set to None.

  :param fn: the file to parse
  :param verbose: if True, output progress to stderr.

def david_results_iterator(fn, verbose=False):
  """
  Iterate over a DAVID result set and yeild GeneOntologyTerm objects
  representing each of the terms reported. The expected format for a DAVID
  result file is tab-seperated format. The following fields should be present:

  ===  ===============  ==========  ====================================
  Num  Field                 Type        Example
  ===  ===============  ==========  ====================================
  0    Category         string      GOTERM_BP_FAT
  1    Term             string      GO:0046907~intracellular transport
  2    Count            int         43
  3    Percent          float       11.345646437994723
  4    PValue           float       1.3232857694449546E-9
  5    Genes            string      ARSB, KPNA6, GNAS
  6    List Total       int         310
  7    Pop Hits         int         657
  8    Pop Total        int         13528
  9    Fold Enrichment  float       2.8561103746256196
  10   Bonferroni       float       2.6293654579179204E-6
  11   Benjamini        float       2.6293654579179204E-6
  12   FDR              float       2.2734203852792234E-6
  ===  ===============  ==========  ====================================

  The first line is a header giving the field names -- this is ignored though,
  and we expect them in the order given above.

  Most of the fields are ignored at present; we take fields 0,1, and 11 (as the
  significance/p-value). When parsing the term field, we try to extract a term
  ID by splitting on tilde, but if we can't then this is set to None.

  :param fn: the file to parse
  :param verbose: if True, output progress to stderr.
  """
  first = True
  for line in open(fn):
    line = line.strip()
    if line == "":
      continue
    if first:
      first = False
      continue

    parts = line.split("\t")
    if len(parts) != NUM_FIELDS_IN_DAVID_RECORD:
      raise IOError("failed to parse " + fn + " as DAVID result file. "
                    + "Expected " + str(NUM_FIELDS_IN_DAVID_RECORD) + " "
                    + "tab-separated fields, but found "
                    + str(len(parts)) + " instead")
    n_parts = parts[1].split("~")
    name = n_parts[-1].strip()
    identifier = n_parts[0] if len(n_parts) > 1 else None
    catagory = parts[0].strip()
    try:
      p_val = float(parts[PVAL_FIELD_NUM])
    except ValueError:
      raise IOError("Failed to parse " + fn + " as DAVID result file. "
                    + "Expected field " + str(PVAL_FIELD_NUM) + " "
                    + "to contain a floating point number "
                    + "(Benjamini), found this instead: "
                    + str(parts[PVAL_FIELD_NUM]))
    yield GeneOntologyEnrichmentResult(name, p_val, identifier, catagory)