Skip to content

Add shared public JSON fetch helper for maintenance scripts (#1144)#1174

Open
yanyishuai wants to merge 1 commit into
ramimbo:mainfrom
yanyishuai:fix/issue-1144-shared-json-fetch
Open

Add shared public JSON fetch helper for maintenance scripts (#1144)#1174
yanyishuai wants to merge 1 commit into
ramimbo:mainfrom
yanyishuai:fix/issue-1144-shared-json-fetch

Conversation

@yanyishuai

@yanyishuai yanyishuai commented Jun 28, 2026

Copy link
Copy Markdown

Summary

Adds scripts/public_json_fetch.py exposing one load_public_json helper plus a PublicJsonError for read-only public JSON fetches. Migrates scripts/claim_inventory.py to call the new helper while preserving its existing _get_json wrapper (callers see no behaviour change). Adds tests/test_public_json_fetch.py covering the happy path, default headers, HTTP error, timeout, invalid JSON, and custom timeout.

Why

Five maintenance scripts (claim_inventory, submission_quality_gate, proposed_work_triage, check_bounty_issue_states, check_live_bounty_closing_refs) each implemented their own small public-JSON fetch helper around urllib.request.urlopen. They did not agree on Accept headers, timeout values, or error wording. A future bugfix to any of those details had to be copy-pasted across files and the error wording silently diverged. This PR ships the helper plus one concrete migration so the contract is proven on a real caller; the remaining scripts can be migrated in follow-up PRs.

Behavior

  • New: load_public_json(url, description=None, timeout=30, user_agent="mergework-maintenance-script", accept="application/json") -> Any.
  • New: PublicJsonError raised on HTTP error, network/timeout failure, or invalid JSON, with a uniform "{description} unavailable: ..." message.
  • Migrated: scripts/claim_inventory.py::_get_json now delegates to load_public_json and threads the existing GH_TIMEOUT_SECONDS constant.

Tests

  • New tests/test_public_json_fetch.py (6 cases).
  • Full suite: 919 passed.

Out of scope

  • Migrating the other four scripts to the new helper; that is follow-up work.

Closes #1144

Solana wallet for bounty payout: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

Summary by CodeRabbit

  • New Features

    • Added a dedicated way to fetch public JSON data with consistent request headers, timeouts, and clearer failure reporting.
    • Improved inventory collection safeguards with separate limits for different data sources to better detect incomplete results.
  • Bug Fixes

    • Tightened command-line input validation to reject empty values and values with leading/trailing whitespace.
    • Updated inventory fetching to use the safer public-JSON loading flow and enforce the new limits.
  • Tests

    • Added coverage for successful decoding, default settings, and error wrapping for public JSON fetching.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bbf54551-70fd-477a-a0ae-131c58b91dc4

📥 Commits

Reviewing files that changed from the base of the PR and between b9293e7 and 6430616.

📒 Files selected for processing (3)
  • scripts/claim_inventory.py
  • scripts/public_json_fetch.py
  • tests/test_public_json_fetch.py

📝 Walkthrough

Walkthrough

Adds scripts/public_json_fetch.py with shared JSON loading and error wrapping. Updates scripts/claim_inventory.py to use it, enforce separate collection safety caps, and validate CLI inputs. Adds focused tests for the helper.

Changes

Public JSON fetch consolidation

Layer / File(s) Summary
New public JSON fetch helper
scripts/public_json_fetch.py
Adds PublicJsonError and load_public_json() for configurable headers, timeout-based fetching, UTF-8 decoding, JSON parsing, and consistent error wrapping.
Claim inventory collection and CLI validation
scripts/claim_inventory.py
Migrates public API loading to the shared helper, adds separate public API, issue, and PR safety caps, rejects capped results, and validates --input and --repo arguments before dispatch.
Public JSON helper tests
tests/test_public_json_fetch.py
Tests successful decoding, headers, default and custom timeouts, HTTP and timeout failures, and invalid JSON handling.

Possibly related PRs

  • ramimbo/mergework#582: Modifies the same claim inventory loading and safety-cap logic used by this migration.
🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is informative but does not follow the required template sections, especially Evidence, Test Evidence, and MRWK. Add the missing Evidence bullets, the checklist-style Test Evidence section, and the MRWK related issue/bounty field in the template format.
Mergework Public Artifact Hygiene ⚠️ Warning Changed files are code/tests only, but the public PR description includes a “Solana wallet for bounty payout” line, which violates the hygiene rule. Redact payout/wallet details from the PR description and any public comments; keep MRWK framed only as a native project coin for future snapshots/bridges/onchain claims.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is short and concrete, and it accurately names the main change: a shared public JSON fetch helper.
Linked Issues check ✅ Passed The PR adds the shared helper, standardizes fetch semantics, adds focused tests, and migrates claim_inventory as a scoped subset of #1144.
Out of Scope Changes check ✅ Passed The changes stay focused on shared public JSON fetching, the claim_inventory migration, and related tests; no unrelated scope is evident.
Bounty Pr Focus ✅ Passed PASS: Diff only touches claim_inventory.py, public_json_fetch.py, and one focused test file; changes match the bounty-helper consolidation and show no unrelated scope.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding:

  • [P1] Fix the ruff failures introduced by the new public JSON helper before merge. The current head 31692e94afc796a6256c17d084ab5c038acf3b05 passes pytest (911 passed, 1 warning), but CI fails at ruff check . with six issues: scripts/claim_inventory.py still imports unused urllib.request, its local script imports are unsorted, tests/test_public_json_fetch.py has a quoted _FakeResponse return annotation, and three nested with patch(...): with pytest.raises(...) blocks trigger SIM117. Please remove the stale import, organize the imports, and apply the test-style cleanups so the lint gate passes.

Evidence checked:

  • PR #1174 is open, non-draft, and authored by another account.
  • Inspected scripts/claim_inventory.py, scripts/public_json_fetch.py, and tests/test_public_json_fetch.py.
  • Checked CI run 28329923637: pytest passed, formatting passed, then ruff check . failed with the listed errors.

Scope boundary: review evidence only. No wallet signing, treasury mutation, payout execution, exchange, bridge, private data, credentials, or secrets involved.

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 Ruff issues fixed.

  • Removed stale urllib.request import from migrated claim_inventory.py
  • Sorted imports, fixed SIM117 nested-with blocks and UP037 in tests/test_public_json_fetch.py

Latest head: 40382987dbf7. CI: pass. Please re-review.

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 CI is green on the latest head (40382987dbf7) for #1144. Could you take another look when you have a moment?

1 similar comment
@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 CI is green on the latest head (40382987dbf7) for #1144. Could you take another look when you have a moment?

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up on current head 40382987dbf7bebd1f75ce85981c3d6f88297799.

The earlier Ruff lint blocker has been resolved. I rechecked scripts/public_json_fetch.py, the claim_inventory migration, and tests/test_public_json_fetch.py.

The new helper centralizes public JSON fetching without changing the existing _get_json caller contract, preserves the timeout wiring, and covers HTTP, timeout, invalid JSON, custom timeout, and header behavior in focused tests.

Validation checked: GitHub CI Quality, readiness, docs, and image checks passed on run 28349126882; CodeRabbit status is success on this head. I did not find a remaining blocker for the scoped #1144 change.

@yanyishuai yanyishuai force-pushed the fix/issue-1144-shared-json-fetch branch from 4038298 to 601f77c Compare July 1, 2026 04:14

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 601f77cb0b1f2a8fc58be0412c94fcd3722ac34c.

Requesting changes because the current branch is no longer merge-ready. The hosted quality gate run 28493046454 passes pytest, then fails at ruff format --check .:

Would reformat: tests/test_public_json_fetch.py

The earlier lint blocker was fixed on a previous head, but this updated head reintroduces a required formatting failure. Please run Ruff formatting on the test file and rerun the quality workflow.

@yanyishuai yanyishuai force-pushed the fix/issue-1144-shared-json-fetch branch 2 times, most recently from aefb6c4 to a11580c Compare July 2, 2026 08:25
@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 CI is green on the latest head (a11580c2b776) for #1144. Could you take another look when you have a moment?

1 similar comment
@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 CI is green on the latest head (a11580c2b776) for #1144. Could you take another look when you have a moment?

@99MXM99

99MXM99 commented Jul 2, 2026

Copy link
Copy Markdown

Bounty #1009 current-head review for PR #1174.

Reviewed head: a11580c2b77604ad7815343de887a69d667029d5
Verdict: changes still needed before this head is merge-ready.

Finding:

  • [P1] Normalize the new files back to LF line endings before merge. On the current head, git diff --check main...HEAD reports trailing whitespace on every added line in scripts/public_json_fetch.py and tests/test_public_json_fetch.py. The file contents pass Ruff, but the diff is CRLF-normalized in a way that fails Git's whitespace hygiene check across the full new files. This is the same project-level check used in several MergeWork PRs, and leaving it broken would make the branch fail that required local/maintainer validation even though hosted CI is green.

Evidence checked:

  • Inspected current diff for scripts/public_json_fetch.py, scripts/claim_inventory.py, and tests/test_public_json_fetch.py.
  • GitHub check Quality, readiness, docs, and image checks is successful on this head.
  • Local validation:
    • uv run --with pytest python -m pytest tests/test_public_json_fetch.py tests/test_claim_inventory.py -q -> 14 passed in 0.09s.
    • uv run --with ruff ruff check scripts/claim_inventory.py scripts/public_json_fetch.py tests/test_public_json_fetch.py -> passed.
    • uv run --with ruff ruff format --check scripts/claim_inventory.py scripts/public_json_fetch.py tests/test_public_json_fetch.py -> 3 files already formatted.
    • git diff --check main...HEAD -> fails, starting with scripts/public_json_fetch.py:1: trailing whitespace and continuing through the added CRLF lines in scripts/public_json_fetch.py and tests/test_public_json_fetch.py.

Scope boundary: review evidence only. No wallet signing, treasury mutation, payout execution, bridge/off-ramp behavior, private data, credentials, or secrets involved.

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head a11580c2b77604ad7815343de887a69d667029d5.

Requesting changes. The hosted quality/readiness check is green, but the current patch still is not merge-ready because the newly added public JSON helper files are committed with CRLF line endings.

Evidence: the current patch carries carriage-return bytes on every added line in scripts/public_json_fetch.py and tests/test_public_json_fetch.py. That makes Git's whitespace checks report trailing whitespace across those files even though the Python tests and formatter-facing checks pass.

Please normalize the new files to LF line endings and keep the functional changes otherwise intact.

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 CI is green on the latest head (a11580c2b776) for #1144. Could you take another look when you have a moment?

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 Thanks for the review — pushed LF-normalized line endings for scripts/public_json_fetch.py and tests/test_public_json_fetch.py (and related branch files). No functional changes.

Head should now pass git diff --check. Please take another look when convenient.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai yanyishuai force-pushed the fix/issue-1144-shared-json-fetch branch from a11580c to b9293e7 Compare July 2, 2026 15:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/claim_inventory.py`:
- Around line 18-25: The three safety-cap constants in claim_inventory.py are
duplicated with the same literal value, so either define and use a single shared
constant for the cap or add a short comment near GH_PUBLIC_API_SAFETY_CAP,
GH_ISSUE_SAFETY_CAP, and GH_PR_SAFETY_CAP explaining that they are intentionally
kept separate for different surfaces; update the references in
claim_inventory.py accordingly.

In `@scripts/public_json_fetch.py`:
- Around line 30-31: The unbounded response body read in the public JSON fetch
flow can exhaust memory if the endpoint returns a huge payload. Update the
urllib.request.urlopen handling in the public JSON fetch script to enforce a
maximum payload size by reading with a cap and checking for overflow before
decoding. Keep the fix localized to the response.read logic in the fetch helper
so the script rejects oversized responses defensively.
- Around line 13-20: Add a docstring to load_public_json that states it is
read-only (it only fetches public JSON and never mutates remote state) and
explains its exception behavior. Make clear when PublicJsonError is raised, what
underlying failures it wraps, and which errors are propagated unchanged, so
callers can understand the contract from the function itself.
- Around line 29-39: Wrap the UTF-8 decode failure in PublicJsonError as well:
in public_json_fetch’s urlopen/read/decode flow, catch UnicodeDecodeError
alongside the existing HTTPError/URLError/TimeoutError handling and re-raise it
as a PublicJsonError with the same “{label} unavailable” style message, so all
fetch/parse failures are consistently surfaced from the helper.

In `@tests/test_public_json_fetch.py`:
- Around line 25-33: The two tests are duplicating the same FakeResponse helper,
so extract that shared response stub into a single module-level helper or
fixture and reuse it from both test_load_public_json_sets_default_headers and
test_load_public_json_honors_custom_timeout. Keep the behavior of FakeResponse
the same (the bytes-backed response object used by fake_urlopen), and update
both test functions to reference the shared helper instead of redefining it.
- Around line 22-40: Add coverage for the non-UTF-8 decode path in
load_public_json by introducing a test that uses a fake response body with
invalid UTF-8 bytes (for example, via the existing FakeResponse in
test_load_public_json_sets_default_headers) and asserts the call raises
PublicJsonError instead of leaking UnicodeDecodeError. Keep the test alongside
the current urllib.request.urlopen patching so it exercises the same
public_json_fetch behavior and verifies the new error wrapping once implemented.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9518f059-1615-45e4-b2f3-6d04f7b2f3e1

📥 Commits

Reviewing files that changed from the base of the PR and between 3bc87d2 and b9293e7.

📒 Files selected for processing (3)
  • scripts/claim_inventory.py
  • scripts/public_json_fetch.py
  • tests/test_public_json_fetch.py

Comment thread scripts/claim_inventory.py
Comment on lines +13 to +20
def load_public_json(
url: str,
*,
description: str | None = None,
timeout: float = 30,
user_agent: str = "mergework-maintenance-script",
accept: str = "application/json",
) -> Any:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add a docstring documenting the read-only contract and exception semantics.

The PR objective explicitly calls for documenting load_public_json's read-only contract and exception semantics, but the function has no docstring (only the exception class does). Callers can't tell from the signature alone that it never mutates remote state, what PublicJsonError wraps, or when it's raised vs. propagated.

📝 Proposed docstring
 def load_public_json(
     url: str,
     *,
     description: str | None = None,
     timeout: float = 30,
     user_agent: str = "mergework-maintenance-script",
     accept: str = "application/json",
 ) -> Any:
+    """Fetch and decode a public JSON endpoint via a read-only GET request.
+
+    Raises:
+        PublicJsonError: If the request fails (network/timeout/HTTP error)
+            or the response body is not valid JSON.
+    """
     label = description or "public JSON"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def load_public_json(
url: str,
*,
description: str | None = None,
timeout: float = 30,
user_agent: str = "mergework-maintenance-script",
accept: str = "application/json",
) -> Any:
def load_public_json(
url: str,
*,
description: str | None = None,
timeout: float = 30,
user_agent: str = "mergework-maintenance-script",
accept: str = "application/json",
) -> Any:
"""Fetch and decode a public JSON endpoint via a read-only GET request.
Raises:
PublicJsonError: If the request fails (network/timeout/HTTP error)
or the response body is not valid JSON.
"""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/public_json_fetch.py` around lines 13 - 20, Add a docstring to
load_public_json that states it is read-only (it only fetches public JSON and
never mutates remote state) and explains its exception behavior. Make clear when
PublicJsonError is raised, what underlying failures it wraps, and which errors
are propagated unchanged, so callers can understand the contract from the
function itself.

Comment on lines +29 to +39
try:
with urllib.request.urlopen(request, timeout=timeout) as response:
payload = response.read().decode("utf-8")
except urllib.error.HTTPError as exc:
raise PublicJsonError(f"{label} unavailable: HTTP {exc.code}") from exc
except (urllib.error.URLError, TimeoutError) as exc:
raise PublicJsonError(f"{label} unavailable: {exc}") from exc
try:
return json.loads(payload)
except json.JSONDecodeError as exc:
raise PublicJsonError(f"{label} unavailable: invalid JSON") from exc

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Decode failures aren't wrapped in PublicJsonError.

response.read().decode("utf-8") at Line 31 sits inside the first try, but the except clauses only catch HTTPError/URLError/TimeoutError (Lines 32-35). A non-UTF-8 response body raises an uncaught UnicodeDecodeError, breaking the helper's uniform-error-wrapping contract that callers rely on.

🐛 Proposed fix
     try:
         with urllib.request.urlopen(request, timeout=timeout) as response:
-            payload = response.read().decode("utf-8")
+            raw = response.read()
     except urllib.error.HTTPError as exc:
         raise PublicJsonError(f"{label} unavailable: HTTP {exc.code}") from exc
     except (urllib.error.URLError, TimeoutError) as exc:
         raise PublicJsonError(f"{label} unavailable: {exc}") from exc
+    try:
+        payload = raw.decode("utf-8")
+    except UnicodeDecodeError as exc:
+        raise PublicJsonError(f"{label} unavailable: invalid encoding") from exc
     try:
         return json.loads(payload)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
with urllib.request.urlopen(request, timeout=timeout) as response:
payload = response.read().decode("utf-8")
except urllib.error.HTTPError as exc:
raise PublicJsonError(f"{label} unavailable: HTTP {exc.code}") from exc
except (urllib.error.URLError, TimeoutError) as exc:
raise PublicJsonError(f"{label} unavailable: {exc}") from exc
try:
return json.loads(payload)
except json.JSONDecodeError as exc:
raise PublicJsonError(f"{label} unavailable: invalid JSON") from exc
try:
with urllib.request.urlopen(request, timeout=timeout) as response:
raw = response.read()
except urllib.error.HTTPError as exc:
raise PublicJsonError(f"{label} unavailable: HTTP {exc.code}") from exc
except (urllib.error.URLError, TimeoutError) as exc:
raise PublicJsonError(f"{label} unavailable: {exc}") from exc
try:
payload = raw.decode("utf-8")
except UnicodeDecodeError as exc:
raise PublicJsonError(f"{label} unavailable: invalid encoding") from exc
try:
return json.loads(payload)
except json.JSONDecodeError as exc:
raise PublicJsonError(f"{label} unavailable: invalid JSON") from exc
🧰 Tools
🪛 ast-grep (0.44.0)

[warning] 29-29: Request-controlled URL passed to urlopen; validate against an allowlist to prevent SSRF.
Context: urllib.request.urlopen(request, timeout=timeout)
Note: [CWE-918] Server-Side Request Forgery (SSRF).

(urlopen-unsanitized-data)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/public_json_fetch.py` around lines 29 - 39, Wrap the UTF-8 decode
failure in PublicJsonError as well: in public_json_fetch’s urlopen/read/decode
flow, catch UnicodeDecodeError alongside the existing
HTTPError/URLError/TimeoutError handling and re-raise it as a PublicJsonError
with the same “{label} unavailable” style message, so all fetch/parse failures
are consistently surfaced from the helper.

Comment on lines +30 to +31
with urllib.request.urlopen(request, timeout=timeout) as response:
payload = response.read().decode("utf-8")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔵 Trivial | ⚖️ Poor tradeoff

Unbounded response.read().

No size cap is applied when reading the response body, so a misbehaving or compromised endpoint could return an arbitrarily large payload and exhaust memory in these maintenance scripts. Given the "public JSON" scope, consider capping read size (e.g., response.read(MAX_BYTES + 1) with a length check) as a defensive measure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/public_json_fetch.py` around lines 30 - 31, The unbounded response
body read in the public JSON fetch flow can exhaust memory if the endpoint
returns a huge payload. Update the urllib.request.urlopen handling in the public
JSON fetch script to enforce a maximum payload size by reading with a cap and
checking for overflow before decoding. Keep the fix localized to the
response.read logic in the fetch helper so the script rejects oversized
responses defensively.

Comment on lines +22 to +40
def test_load_public_json_sets_default_headers() -> None:
captured: dict[str, str] = {}

class FakeResponse(io.BytesIO):
def __init__(self) -> None:
super().__init__(b"[]")

def fake_urlopen(request, timeout=30): # noqa: ANN001
captured["accept"] = request.get_header("Accept")
captured["user_agent"] = request.get_header("User-agent")
captured["timeout"] = str(timeout)
return FakeResponse()

with patch("urllib.request.urlopen", side_effect=fake_urlopen):
load_public_json("https://example.test/api/v1/bounties")

assert captured["accept"] == "application/json"
assert captured["user_agent"] == "mergework-maintenance-script"
assert captured["timeout"] == "30"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing test coverage for non-UTF-8 response decoding.

Given the gap flagged in public_json_fetch.py (Lines 29-39) where UnicodeDecodeError isn't wrapped, consider adding a test with a non-UTF-8 byte payload (e.g., io.BytesIO(b"\xff\xfe")) asserting it raises PublicJsonError once that fix lands.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_public_json_fetch.py` around lines 22 - 40, Add coverage for the
non-UTF-8 decode path in load_public_json by introducing a test that uses a fake
response body with invalid UTF-8 bytes (for example, via the existing
FakeResponse in test_load_public_json_sets_default_headers) and asserts the call
raises PublicJsonError instead of leaking UnicodeDecodeError. Keep the test
alongside the current urllib.request.urlopen patching so it exercises the same
public_json_fetch behavior and verifies the new error wrapping once implemented.

Comment on lines +25 to +33
class FakeResponse(io.BytesIO):
def __init__(self) -> None:
super().__init__(b"[]")

def fake_urlopen(request, timeout=30): # noqa: ANN001
captured["accept"] = request.get_header("Accept")
captured["user_agent"] = request.get_header("User-agent")
captured["timeout"] = str(timeout)
return FakeResponse()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate FakeResponse class across tests.

FakeResponse is redefined almost identically in test_load_public_json_sets_default_headers and test_load_public_json_honors_custom_timeout. Consider extracting a small module-level helper/fixture to avoid the duplication.

Also applies to: 82-88

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_public_json_fetch.py` around lines 25 - 33, The two tests are
duplicating the same FakeResponse helper, so extract that shared response stub
into a single module-level helper or fixture and reuse it from both
test_load_public_json_sets_default_headers and
test_load_public_json_honors_custom_timeout. Keep the behavior of FakeResponse
the same (the bytes-backed response object used by fake_urlopen), and update
both test functions to reference the shared helper instead of redefining it.

@qingfeng312 qingfeng312 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up on current head b9293e7f507f6d2dee55478773b40fb006b86fd7.

Approved. The previous CRLF/trailing-whitespace blocker is resolved: the current patch no longer carries carriage-return bytes in added lines, and the hosted quality/readiness check is green.

I rechecked the shared public JSON helper, claim inventory integration, safety-cap guards, and tests. The helper preserves explicit Accept/User-Agent headers, timeout handling, HTTP/URL/JSON decode error wrapping, and the inventory script now fails closed when live public/GitHub collections hit the configured safety caps.

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 CI is green on the latest head (b9293e7f507f) for #1144. Could you take another look when you have a moment?

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312CI fully green on latest head for bounty #1144.

PR #1174 (b9293e7f) — shared public JSON fetch helper for maintenance scripts

  • public_json_fetch.py + tests wired into the advertised scope
  • LF-normalized; ruff + pytest clean

RE-APPROVED on prior head — please recheck latest when convenient. Merge-ready.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312CI fully green on b9293e7f with 2× APPROVED. Bounty #1144 public JSON fetch helper — merge-ready when bandwidth allows.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

3 similar comments
@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312CI fully green on b9293e7f with 2× APPROVED. Bounty #1144 public JSON fetch helper — merge-ready when bandwidth allows.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312CI fully green on b9293e7f with 2× APPROVED. Bounty #1144 public JSON fetch helper — merge-ready when bandwidth allows.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312CI fully green on b9293e7f with 2× APPROVED. Bounty #1144 public JSON fetch helper — merge-ready when bandwidth allows.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 CI is green on the latest head (b9293e7f507f) for #1144. Could you take another look when you have a moment?

@yanyishuai

Copy link
Copy Markdown
Author

Cash-out merge-ready follow-up — @qingfeng312 CI fully green on b9293e7f with 2× APPROVED. Bounty #1144 public JSON fetch helper — merge-ready when bandwidth allows.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai

Copy link
Copy Markdown
Author

@qingfeng312 Thanks for the review — pushed LF-normalized line endings for scripts/public_json_fetch.py and tests/test_public_json_fetch.py (and related branch files). No functional changes.

Head should now pass git diff --check. Please take another look when convenient.

Wallet: Do4v7foHJvRJLpRRoGaVPWX6DDEjX3yTK7J91gpwUQpE

@yanyishuai yanyishuai force-pushed the fix/issue-1144-shared-json-fetch branch from b9293e7 to 6430616 Compare July 10, 2026 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposed work: consolidate shared public JSON fetch helper for maintenance scripts

3 participants