From 9928c1241e1554ebb039f95758fc49fa1d0a77a5 Mon Sep 17 00:00:00 2001 From: Anuj Agarwal Date: Wed, 14 Jan 2026 20:54:58 +0530 Subject: [PATCH 1/3] fix: suppress GitHub API errors in info --versions (fixes #1519) --- bowtie/_core.py | 25 ++++++++++---------- bowtie/tests/test_info_versions.py | 38 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 bowtie/tests/test_info_versions.py diff --git a/bowtie/_core.py b/bowtie/_core.py index 83aeb2d85..70135c610 100644 --- a/bowtie/_core.py +++ b/bowtie/_core.py @@ -549,23 +549,22 @@ async def get_versions(self) -> Iterable[str]: url = CONTAINER_PACKAGES_API / self.id / "versions" gh = github() - pages: list[GitHubCore] = [] - with suppress(GitHubError): - pages = gh._iter(count=-1, url=str(url), cls=GitHubCore) # type: ignore[reportPrivateUsage] versions: Set[str] = ( {self.info.version} if self.info.version else set() ) - for page in pages: - try: - tags = cast( - "Iterable[str]", - page.as_dict()["metadata"]["container"]["tags"], - ) - except KeyError: - continue - else: - versions.update([tag for tag in tags if "." in tag]) + + with suppress(GitHubError): + for page in gh._iter(count=-1, url=str(url), cls=GitHubCore): # type: ignore[reportPrivateUsage] + try: + tags = cast( + "Iterable[str]", + page.as_dict()["metadata"]["container"]["tags"], + ) + except KeyError: + continue + else: + versions.update([tag for tag in tags if "." in tag]) return sorted(versions, key=sortable_version_key, reverse=True) diff --git a/bowtie/tests/test_info_versions.py b/bowtie/tests/test_info_versions.py new file mode 100644 index 000000000..23dcb7e56 --- /dev/null +++ b/bowtie/tests/test_info_versions.py @@ -0,0 +1,38 @@ +import pytest +from unittest.mock import Mock, patch +from github3.exceptions import GitHubError +from bowtie._core import Implementation, ImplementationInfo + +@pytest.mark.asyncio +async def test_get_versions_suppresses_github_error(): + """ + Test that get_versions() catches GitHub API errors (like rate limits) + and returns the local fallback version instead of crashing. + """ + + info = ImplementationInfo.from_dict( + name="fake-runner", + language="python", + homepage="https://example.com", + issues="https://example.com/issues", + source="https://example.com/source", + dialects=["http://json-schema.org/draft-07/schema#"], + version="1.2.3", + ) + + impl = Implementation( + id="python-fake-runner", + info=info, + harness=Mock(), + reporter=Mock(), + ) + + with patch("bowtie._core.github") as mock_github_func: + mock_gh_client = Mock() + mock_github_func.return_value = mock_gh_client + + mock_gh_client._iter.side_effect = GitHubError(resp=Mock()) + + versions = await impl.get_versions() + + assert versions == ["1.2.3"] \ No newline at end of file From 9cfcb12f6d774c0eda5e8fbcbc6eeb867d44dee6 Mon Sep 17 00:00:00 2001 From: Anuj Agarwal Date: Wed, 14 Jan 2026 21:16:34 +0530 Subject: [PATCH 2/3] fix: resolve linting and typing errors --- bowtie/_core.py | 2 +- bowtie/tests/test_info_versions.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bowtie/_core.py b/bowtie/_core.py index 70135c610..e46957fe0 100644 --- a/bowtie/_core.py +++ b/bowtie/_core.py @@ -559,7 +559,7 @@ async def get_versions(self) -> Iterable[str]: try: tags = cast( "Iterable[str]", - page.as_dict()["metadata"]["container"]["tags"], + page.as_dict()["metadata"]["container"]["tags"], # type: ignore[reportUnknownMemberType] ) except KeyError: continue diff --git a/bowtie/tests/test_info_versions.py b/bowtie/tests/test_info_versions.py index 23dcb7e56..042806880 100644 --- a/bowtie/tests/test_info_versions.py +++ b/bowtie/tests/test_info_versions.py @@ -1,15 +1,17 @@ -import pytest from unittest.mock import Mock, patch + +import pytest from github3.exceptions import GitHubError + from bowtie._core import Implementation, ImplementationInfo + @pytest.mark.asyncio async def test_get_versions_suppresses_github_error(): """ Test that get_versions() catches GitHub API errors (like rate limits) and returns the local fallback version instead of crashing. """ - info = ImplementationInfo.from_dict( name="fake-runner", language="python", @@ -30,9 +32,7 @@ async def test_get_versions_suppresses_github_error(): with patch("bowtie._core.github") as mock_github_func: mock_gh_client = Mock() mock_github_func.return_value = mock_gh_client - mock_gh_client._iter.side_effect = GitHubError(resp=Mock()) - versions = await impl.get_versions() assert versions == ["1.2.3"] \ No newline at end of file From 18f5f6cd7701b06bedd74faf57787b385624404c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 15:47:01 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- bowtie/tests/test_info_versions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bowtie/tests/test_info_versions.py b/bowtie/tests/test_info_versions.py index 042806880..845bdccf9 100644 --- a/bowtie/tests/test_info_versions.py +++ b/bowtie/tests/test_info_versions.py @@ -1,7 +1,7 @@ from unittest.mock import Mock, patch -import pytest from github3.exceptions import GitHubError +import pytest from bowtie._core import Implementation, ImplementationInfo @@ -35,4 +35,4 @@ async def test_get_versions_suppresses_github_error(): mock_gh_client._iter.side_effect = GitHubError(resp=Mock()) versions = await impl.get_versions() - assert versions == ["1.2.3"] \ No newline at end of file + assert versions == ["1.2.3"]