From 2afd1934fe81ef0e2abd36d8f74468d3f320504a Mon Sep 17 00:00:00 2001 From: Charles Tapley Hoyt Date: Mon, 2 Dec 2024 12:22:20 +0100 Subject: [PATCH] Improve warning feedback (#52) Store warnings in a more detailed tuple to create a better failures summary page --- src/bioversions/resources/update.py | 21 +++++++++++++++------ src/bioversions/sources/__init__.py | 23 +++++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/bioversions/resources/update.py b/src/bioversions/resources/update.py index 9d2eca63..3957a92b 100644 --- a/src/bioversions/resources/update.py +++ b/src/bioversions/resources/update.py @@ -15,7 +15,7 @@ write_export, write_versions, ) -from bioversions.sources import _iter_versions +from bioversions.sources import FailureTuple, _iter_versions from bioversions.version import get_git_hash __all__ = [ @@ -48,10 +48,10 @@ def _update(force: bool): # noqa:C901 today = datetime.now().strftime("%Y-%m-%d") changes = False - errors = [] - for bv, error in _iter_versions(use_tqdm=True): - if error is not None or bv is None: - errors.append(error) + failure_tuples = [] + for bv in _iter_versions(use_tqdm=True): + if isinstance(bv, FailureTuple): + failure_tuples.append(bv) continue if bv.name in versions: @@ -97,7 +97,16 @@ def _update(force: bool): # noqa:C901 write_export(rv) write_versions(rv) - FAILURES_PATH.write_text("# Errors\n\n" + "\n".join(f"- {error}" for error in errors)) + if failure_tuples: + click.secho(f"Writing failure summary to {FAILURES_PATH}") + text = "# Summary of Errors\n\n" + for t in failure_tuples: + text += f"- {t.name} - {t.message}\n" + text += "\n" + for t in failure_tuples: + text += f"## {t.name}\n\nUsing class: `{t.clstype}`\n\n" + text += f"```python-traceback\n{t.trace}\n```\n\n" + FAILURES_PATH.write_text(text) def _log_update(bv) -> None: diff --git a/src/bioversions/sources/__init__.py b/src/bioversions/sources/__init__.py index 2e20aab5..2b23788c 100644 --- a/src/bioversions/sources/__init__.py +++ b/src/bioversions/sources/__init__.py @@ -4,8 +4,10 @@ import ftplib import logging +import traceback from collections.abc import Iterable, Mapping from functools import lru_cache +from typing import NamedTuple from tqdm import tqdm @@ -189,14 +191,23 @@ def get_rows(use_tqdm: bool | None = False) -> list[Bioversion]: """Get the rows, refreshing once per day.""" return [ bioversion - for bioversion, error in _iter_versions(use_tqdm=use_tqdm) - if error is None and bioversion is not None + for bioversion in _iter_versions(use_tqdm=use_tqdm) + if isinstance(bioversion, Bioversion) ] +class FailureTuple(NamedTuple): + """Holds information about failures.""" + + name: str + clstype: str + message: str + trace: str + + def _iter_versions( use_tqdm: bool | None = False, -) -> Iterable[tuple[Bioversion, None] | tuple[None, str]]: +) -> Iterable[Bioversion | FailureTuple]: it = tqdm(get_getters(), disable=not use_tqdm) for cls in it: @@ -206,10 +217,10 @@ def _iter_versions( except (OSError, AttributeError, ftplib.error_perm): msg = f"failed to resolve {cls.name}" tqdm.write(msg) - yield None, msg + yield FailureTuple(cls.name, cls.__name__, msg, traceback.format_exc()) except ValueError as e: msg = f"issue parsing {cls.name}: {e}" tqdm.write(msg) - yield None, msg + yield FailureTuple(cls.name, cls.__name__, msg, traceback.format_exc()) else: - yield yv, None + yield yv