8954c29282f84de8f41c183a4cbb2817fbbb87c5 max Mon Sep 28 13:53:57 2026 -0700 uniprot otto: an empty cached mapping means nothing aligned, not a broken file, refs #38300 diff --git src/hg/utils/otto/uniprot/doUniprot src/hg/utils/otto/uniprot/doUniprot index e0b65d36ad3..b0a0b4b6b8b 100755 --- src/hg/utils/otto/uniprot/doUniprot +++ src/hg/utils/otto/uniprot/doUniprot @@ -2350,31 +2350,39 @@ allMd5s.append(pairMd5) stats["pairMd5"] = pairMd5[:10] stats["pairFname"] = selectFname # if either the protein sequences, the transcripts, their alignment, the # protein/transcript mapping or the alignment threshold changes -> create a new PSL # mapping file. minAli belongs in here: it decides which alignments survive, so a # mapping built at one threshold must not be silently reused at another. That is # exactly what happened after the MINALI global leaked across threads. refs #38300 fullMd5 = listMd5(allMd5s)[:10] mapFname = join(mapDir, "%(geneTable)s_%(fullMd5)s.psl" % locals()) if isfile(mapFname) and not doForce: logging.info("%s already exists, not rebuilding the protein -> genome mapping PSL" % mapFname) - assert(os.path.getsize(mapFname)!=0) + # An empty mapping is a real answer, not a broken file: an organism UniProt has two + # proteins for, neither of which aligns, produces one. The caller already treats a + # freshly built empty mapping that way and carries on, but reusing a cached one used to + # assert here, so such an assembly failed on every run after the first. The golden + # eagle did, until this. refs #38300 + if os.path.getsize(mapFname) == 0: + logging.warning("%s: the cached protein -> genome mapping is empty, nothing aligns " + "for this assembly" % db) + return mapFname, geneTable, fullMd5, protMapSource, protToTrans, False # The lift info describes the mapping, so it has to exist wherever the mapping # does. A run that was interrupted between building the PSL and writing this file # leaves the PSL behind on its own, and the next run then reuses the PSL and falls # over copying the file that was never written. Write it here too. refs #38300 if not isfile(mapDescFname): logging.info("%s is missing next to the reused mapping, writing it" % mapDescFname) writeMapDesc(stats, db, geneTable, mapDescFname) # careful: if you modify this, also modify the other return statement below return mapFname, geneTable, fullMd5, protMapSource, protToTrans, False stats["protMd5"] = protMd5[:10] stats["metaMd5"] = metaMd5[:10] stats["transMd5"] = transMd5[:10] stats["fullMd5"] = fullMd5[:10] stats["mapFname"] = basename(mapFname)