From ddf8199f7bea8690695e813b6780ee6af6d3f1a7 Mon Sep 17 00:00:00 2001 From: Jorge Rivera Date: Thu, 11 Jun 2026 15:42:23 +0200 Subject: [PATCH] fix(remote): download without tqdm; move benchmark report off PR comments (0.1.2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit download() crashed on a clean install: pooch's progress bar requires tqdm, which is not a resolvekit dependency. Downloads now show a progress bar when tqdm is installed and run silently when it isn't. benchmark.yml: the full benchmark report goes to the run's job summary and artifact instead of a PR comment — clean CI lacks the remote tiers, so the absolute numbers are misleading and add noise rather than review signal. --- .github/workflows/benchmark.yml | 20 ++++-------- CHANGELOG.md | 7 ++++ docs/getting-started/install.md | 2 +- docs/reference/resolver.md | 2 +- pyproject.toml | 2 +- src/resolvekit/core/remote.py | 12 ++++++- tests/core/test_remote.py | 58 +++++++++++++++++++++++++++++++++ uv.lock | 2 +- 8 files changed, 86 insertions(+), 19 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 150b180..43b741e 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -29,7 +29,6 @@ jobs: timeout-minutes: 30 permissions: contents: read - pull-requests: write steps: - name: Checkout uses: actions/checkout@v6 @@ -70,16 +69,9 @@ jobs: benchmarks/results/latest.md retention-days: 30 - - name: Post PR comment - if: github.event_name == 'pull_request' - uses: actions/github-script@v8 - with: - script: | - const fs = require('fs'); - const body = fs.readFileSync('benchmarks/results/latest.md', 'utf8'); - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: `
Benchmark results\n\n${body}\n
`, - }); + # The full report goes to the run's job summary (and the artifact above), + # not a PR comment: clean CI lacks the remote data tiers, so the absolute + # numbers are misleading for resolvekit and add noise rather than review + # signal in the PR thread. + - name: Publish job summary + run: cat benchmarks/results/latest.md >> "$GITHUB_STEP_SUMMARY" diff --git a/CHANGELOG.md b/CHANGELOG.md index 02c2a33..847e782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.1.2 (2026-06-11) + +**Fixed.** `download()` crashed on a clean install with "Missing package +'tqdm' required for progress bars": pooch's progress bar needs tqdm, which is +not a resolvekit dependency. Downloads now show a progress bar when tqdm is +installed and run silently when it isn't. + ## 0.1.1 (2026-06-11) **Fixed.** Partial remote caches no longer error: after downloading a single diff --git a/docs/getting-started/install.md b/docs/getting-started/install.md index 4bba8f8..8c31f5e 100644 --- a/docs/getting-started/install.md +++ b/docs/getting-started/install.md @@ -75,7 +75,7 @@ rk.download("geo.admin1") # ~12 MB; verifies checksum, then marks is_available ```python >>> import resolvekit as rk >>> rk.__version__ -'0.1.1' +'0.1.2' >>> rk.resolve_id("United States") 'country/USA' ``` diff --git a/docs/reference/resolver.md b/docs/reference/resolver.md index efb875a..be655b4 100644 --- a/docs/reference/resolver.md +++ b/docs/reference/resolver.md @@ -660,7 +660,7 @@ Resolver.lite().domains # ['geo'] ```python r.info.data_version # "2026.06" -r.info.resolvekit_version # "0.1.1" +r.info.resolvekit_version # "0.1.2" r.info.domains # ("geo", "org") r.info.routing_mode # "auto" r.info.closed # False diff --git a/pyproject.toml b/pyproject.toml index 821d843..449a281 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "resolvekit" -version = "0.1.1" +version = "0.1.2" description = "Entity and place resolution system that maps messy place/entity strings and codes to canonical entities" requires-python = ">=3.12" diff --git a/src/resolvekit/core/remote.py b/src/resolvekit/core/remote.py index 121b146..d6f9e42 100644 --- a/src/resolvekit/core/remote.py +++ b/src/resolvekit/core/remote.py @@ -221,6 +221,14 @@ def download_module_data( return cache_dir +def _progressbar_available() -> bool: + """Pooch's progress bar requires tqdm, which is not a resolvekit + dependency; downloads degrade to silent when it isn't installed.""" + import importlib.util + + return importlib.util.find_spec("tqdm") is not None + + def _download_one_artifact( metadata: DataPackMetadata, artifact_type: str, @@ -234,7 +242,9 @@ def _download_one_artifact( processor = pooch.Decompress() if fname.endswith(".gz") else None try: - downloaded_path = fetcher.fetch(fname, progressbar=True, processor=processor) + downloaded_path = fetcher.fetch( + fname, progressbar=_progressbar_available(), processor=processor + ) except Exception as exc: logger.error( "Download failed for %s/%s: %s", metadata.module_id, artifact_type, exc diff --git a/tests/core/test_remote.py b/tests/core/test_remote.py index 78632bb..d960dcb 100644 --- a/tests/core/test_remote.py +++ b/tests/core/test_remote.py @@ -468,3 +468,61 @@ def test_make_fetcher_adds_trailing_slash_to_override( ) fetcher = _make_fetcher(remote_metadata, _sqlite_spec(remote_metadata)) assert fetcher.base_url.endswith("/") + + +class TestProgressbarFallback: + """Pooch's progress bar requires tqdm, which resolvekit does not depend + on — downloads must work silently when tqdm is not installed.""" + + def test_progressbar_available_reflects_tqdm_presence( + self, monkeypatch: pytest.MonkeyPatch + ) -> None: + import importlib.util + + from resolvekit.core.remote import _progressbar_available + + real_find_spec = importlib.util.find_spec + + def fake_find_spec(name: str, *args: object, **kwargs: object) -> object: + if name == "tqdm": + return None + return real_find_spec(name, *args, **kwargs) + + monkeypatch.setattr(importlib.util, "find_spec", fake_find_spec) + assert _progressbar_available() is False + + def test_fetch_runs_without_progressbar_when_tqdm_missing( + self, + remote_metadata: DataPackMetadata, + package_dir: Path, + monkeypatch: pytest.MonkeyPatch, + ) -> None: + from resolvekit.core import remote + + monkeypatch.setattr(remote, "_progressbar_available", lambda: False) + sqlite_content = b"fake sqlite content for testing" + + def fake_fetch( + fname: str, progressbar: bool = False, processor: object = None + ) -> str: + assert progressbar is False + cache_dir = _module_cache_dir(remote_metadata.module_id) + cache_dir.mkdir(parents=True, exist_ok=True) + decompressed_name = ( + fname.removesuffix(".gz") if fname.endswith(".gz") else fname + ) + sqlite_path = cache_dir / decompressed_name + sqlite_path.write_bytes(sqlite_content) + return str(sqlite_path) + + with patch("resolvekit.core.remote._make_fetcher") as mock_fetcher: + fetcher = MagicMock() + fetcher.fetch.side_effect = fake_fetch + mock_fetcher.return_value = fetcher + + result = download_module_data(remote_metadata, package_dir) + + assert fetcher.fetch.call_count >= 1 + for call in fetcher.fetch.call_args_list: + assert call.kwargs["progressbar"] is False + assert (result / "entities.sqlite").exists() diff --git a/uv.lock b/uv.lock index 4b9fb3e..9a3deb6 100644 --- a/uv.lock +++ b/uv.lock @@ -1700,7 +1700,7 @@ wheels = [ [[package]] name = "resolvekit" -version = "0.1.1" +version = "0.1.2" source = { editable = "." } dependencies = [ { name = "packaging" },