c2087cb0ed189d946439a090d43d2dba5d71a9eb
lrnassar
Wed Aug 5 17:28:22 2026 -0700
Fix error containment and a wasted retry sleep in the VCEP version notifier per CR feedback. refs #37795
ClinGen's version field is a free-form string, so an unparseable value raised
ValueError past the per-VCEP except RuntimeError in checkVcep. That aborted the
whole run, skipping the remaining VCEPs and mailing a traceback instead of the
report. normalizeVersion now reports the offending string as a RuntimeError, and
the version comparison moved inside the try so it is caught, keeping the damage
to a single failure line.
fetchUrl also slept 30 seconds after its final failed attempt, which could not
help. It now only sleeps between attempts.
diff --git src/hg/utils/otto/vcepVersions/checkVcepVersions.py src/hg/utils/otto/vcepVersions/checkVcepVersions.py
index be80d370ca2..8af0f3c687e 100755
--- src/hg/utils/otto/vcepVersions/checkVcepVersions.py
+++ src/hg/utils/otto/vcepVersions/checkVcepVersions.py
@@ -43,45 +43,53 @@
},
"InSiGHT Lynch Syndrome VCEP": {
"hubUrl": "https://hgdownload.soe.ucsc.edu/hubs/insight/insight.html",
"hubRegex": r"
InSiGHT specs\s+(\d+(?:\.\d+)+)
",
"affiliation": "50099",
"genes": ["MLH1", "MSH2", "MSH6", "PMS2"],
},
}
cspecUrl = "https://cspec.genome.network/cspec/ui/svi/affiliation/"
def fetchUrl(url):
"""Fetch url and return its text. Retries a few times so a transient network
blip does not turn into a false alarm, then raises."""
+ attempts = 5
lastErr = None
- for attempt in range(5):
+ for attempt in range(attempts):
try:
with urllib.request.urlopen(url, timeout=120) as resp:
return resp.read().decode("utf-8", "replace")
except (urllib.error.URLError, OSError) as e:
lastErr = e
+ if attempt < attempts - 1:
time.sleep(30)
- raise RuntimeError("could not fetch " + url + " after 5 attempts: " + str(lastErr))
+ raise RuntimeError("could not fetch " + url + " after " + str(attempts) +
+ " attempts: " + str(lastErr))
def normalizeVersion(version):
"""Turn a dotted version into a tuple for comparison, dropping trailing
- zeroes so ClinGen's '2.0' matches our page's '2.0.0'."""
+ zeroes so ClinGen's '2.0' matches our page's '2.0.0'. ClinGen's version is a
+ free-form string, so an unparseable one is reported rather than raising past
+ the per-VCEP error handling and killing the rest of the run."""
+ try:
parts = [int(p) for p in version.split(".")]
+ except ValueError:
+ raise RuntimeError("could not parse version string '" + version + "'")
while len(parts) > 1 and parts[-1] == 0:
parts.pop()
return tuple(parts)
def getOurVersion(config):
"""Scrape the version we publish from a hub description page."""
html = fetchUrl(config["hubUrl"])
match = re.search(config["hubRegex"], html)
if match is None:
raise RuntimeError("no version found on " + config["hubUrl"] +
" (page wording changed? regex: " + config["hubRegex"] + ")")
return match.group(1)
@@ -105,36 +113,36 @@
if gene.get("label") in config["genes"]:
versions[gene["label"]] = svi["version"]
missing = [g for g in config["genes"] if g not in versions]
if missing:
raise RuntimeError("no released CSpec spec for " + ", ".join(missing) + " at " + url)
return versions
def checkVcep(name, config, report):
"""Compare one VCEP and append any mismatch to report. Returns True on
success, False if the check itself could not be completed."""
try:
ourVersion = getOurVersion(config)
clinGenVersions = getClinGenVersions(config)
+ stale = {g: v for g, v in clinGenVersions.items()
+ if normalizeVersion(v) != normalizeVersion(ourVersion)}
except RuntimeError as e:
report.append(name + ": check failed: " + str(e))
return False
- stale = {g: v for g, v in clinGenVersions.items()
- if normalizeVersion(v) != normalizeVersion(ourVersion)}
if stale:
geneList = ", ".join(g + "=" + stale[g] for g in sorted(stale))
report.append(name + " is out of date.")
report.append(" our hub page: " + ourVersion + " (" + config["hubUrl"] + ")")
report.append(" ClinGen CSpec: " + geneList +
" (" + cspecUrl + config["affiliation"] + ")")
return True
def main():
report = []
ok = True
for name in sorted(vcepConfig):
if not checkVcep(name, vcepConfig[name], report):
ok = False