Skip to content

Fix Ruff's exception-raising findings (EM, RSE, TRY) - #58

Merged
anth-volk merged 3 commits into
mainfrom
claude/ruff-exceptions
Nov 2, 2026
Merged

anth-volk merged 3 commits into
mainfrom
claude/ruff-exceptions

Conversation

@anth-volk

@anth-volk anth-volk commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #57

Part of #53.

What this does

The first of the pull requests stacked on #55 that fix the Ruff findings #55 leaves ignored: the 469 findings in EM, RSE and TRY, after which pyproject.toml no longer ignores those three families. Behaviour is unchanged.

  • EM101, EM102 (240): Ruff's fix assigns each exception's argument to a variable before the raise. The variable is named for what it holds, not Ruff's msg: startup_reason for the 19 startup reasons passed to EmitterStartupError and ServiceStartupError, refusal_code for the 38 refusal codes passed to RequestRefusedError and _refuse, and error_message for the other 181 messages. This also clears all 171 TRY003 findings, which flag a long message written in the raise.
  • RSE102 (2): no parentheses on a bare raise TimeoutError (Ruff's fix).
  • TRY301 (43): checks that raised inside a try block move into helper functions that the block calls, so each handler still catches the same exceptions in the same order:
    • the host's socket client (_encode_request, _check_response_size, _decode_response) and the interface's transport (the same three, the last named _complete_response);
    • the host runtime: _respond and _handle_request keep their catch-all handlers and call _answer and _run_request, with _read_request and _encode_reply as module functions;
    • the host entry point (_read_configurations, _load_modules);
    • both launchers (_configuration_payload, _send_configuration, _wait_for_readiness). The startup phase is still set before each step, so failures are classified as before;
    • the Orrery delivery (_check_unchanged, _upload_list, _check_listed_name, _check_upload_url, _check_publication_answer). Each helper takes only the values it checks, typed as the unchecked JSON values they are (object, or the SplitResult of the upload URL). The .get and urlsplit calls stay at the call sites, so every exception is raised where it was, and each upload's URL is still checked just before that upload;
    • the Hugging Face request parser (_file_entries), and one startup test, which raises from a local function.
  • TRY300 (2): the host entry point and the Orrery delivery return success from an else block.
  • TRY004 (11): a type check that raises something other than TypeError.
    • Four now raise TypeError, where no caller can tell the difference:

      • the runtime's request reader, whose caller answers every failure with the same error reply;
      • the entry point's module list, whose caller prints the same fixed startup reason for every failure;
      • the Orrery upload list, whose handler records ValueError and TypeError with one error code;
      • the telemetry block request. In the emitter it reaches the runtime's catch-all. It also reaches Microcosm's test support, whose fake telemetry emitter calls process_request directly, but there the branch can't be reached: the emitter's client always sends blocking_gate_ids as a list.

      One test now pins each caller's visible outcome (see the round 1 record below); the runtime's was already tested.

    • Seven keep their type, with # noqa: TRY004 and the reason in a comment above:

      • three in the interface's request objects, whose published constructors raise ValueError for every invalid value (two are tested with pytest.raises(ValueError));
      • the host client, which reports the exception's type name;
      • the JSON column type, which raises the same type as json.loads's JSONDecodeError for invalid JSON just above it;
      • the two Alembic environments, where the check is for a connection the emitter didn't supply.

      The last three were optional. Each could become TypeError without a suppression, but that would change the type a caller sees, which this pull request avoids.

Test-first record

There is no red step, since nothing changes behaviour.

Commit Result
abc82ff The fixes ruff check . and ruff format --check . pass with EM, RSE and TRY selected. All five guards pass with GITHUB_BASE_REF=main. The 25 test functions this commit changes (52 cases, by node ID) pass.

Review round 1:

Commit Result
e2d8cb6 Merge #55's round 2 ruff check ., ruff format --check . and the guards pass.
33b01b8 Tests of the three callers No red step, since they pin behaviour that doesn't change. They pass on this branch and, in a worktree of #55's head (bef4f36, where the three checks raised ValueError), with only the three test files copied in: 18 cases each time.
fa38ac1 Names, Orrery types, reasons ruff check ., ruff format --check . and the guards pass. The four changed test functions pass (19 cases).

No other test was run: the source refactors are left to CI's test jobs. The node IDs exclude tests/test_collector_contract.py::test_lost_ack_retries_same_event_after_restart_without_duplicates, which needs the pinned collector.

CI

No workflow, trigger or script changes, and no environment variable or secret is read differently.

Release

The fragment is changelog.d/ruff-exceptions.changed.md, a patch bump: merging releases the next patch version of both distributions, whose code changes without changing behaviour.

🤖 Generated with Claude Code

@anth-volk
anth-volk added this pull request to stack #46 October 30, 2026 17:30
anth-volk added a commit that referenced this pull request Oct 30, 2026
…stay

- The runtime's worker shutdown gets its dispatcher from a new
  _started_requests helper, which raises the same AssertionError, so the
  try block no longer holds a raise (TRY301). The sanitizer's invariant
  is an explicit check raising AssertionError, with `# noqa: TRY004`
  and its reason, as #58 handles type checks that keep their exception.
- SLF001 applies only to tools/installed-smoke.py and
  tools/installed-interface-smoke.py, under the new rule
  emitter.quality.installed-smoke-ruff-exemptions; check-installed.py
  needs it for nothing.
- The 14 copies of an inaccurate comment about print and a missing
  sys.stderr are replaced by one note per module: each print marked
  `# noqa: T201` writes one of its messages to standard error on
  purpose.
- The Ruff configuration comment includes modules that run as programs,
  and the changelog fragment says all 21 asserts are converted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk removed this pull request from stack #46 November 2, 2026 14:03
@anth-volk
anth-volk added this pull request to stack #72 November 2, 2026 14:04
Base automatically changed from claude/rules-ruff-all to main November 2, 2026 15:06
@anth-volk
anth-volk force-pushed the claude/ruff-exceptions branch from 395673e to 7c783f5 Compare November 2, 2026 15:06
anth-volk and others added 3 commits November 2, 2026 19:07
- EM101 and EM102: Ruff's fix assigns each message before the raise;
  the variable is named error_message rather than Ruff's msg.
- RSE102: no parentheses on a bare raise (Ruff's fix).
- TRY301: checks that raised inside a try block move into helper
  functions the block calls, in the host's client, runtime, launcher and
  entry point, the interface's launcher and transport, the Orrery
  delivery, the Hugging Face request parser, and one startup test.
- TRY300: the host entry point and the Orrery delivery return success
  from an else block.
- TRY004: TypeError where only a catch-all handler sees the exception
  (the runtime's request reader, the entry point's module list, the
  Orrery upload list, the telemetry block request). Elsewhere the type
  stays, with a reason: the interface README promises ValueError for an
  invalid request field, the client reports the exception's type name,
  the JSON column's readers handle ValueError, and the Alembic
  environments report a missing connection.
- Ruff no longer ignores EM, RSE and TRY.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The host entry point: module settings that are not an object end
  startup with exit code 1 and the fixed "startup_failure" text on
  stderr, and no module is loaded.
- The Orrery delivery: an upload answer whose uploads value is not a
  list keeps the job pending with the
  publication_invalid_evidence_or_response code, after one request.
- The telemetry block request: a blocking_gate_ids value that is not a
  list queues no event and leaves the lifecycle unchanged.

The tests pass on #55's code, where these checks raised ValueError, and
on this branch. The startup test's variable is named startup_reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The 57 variables that hold a startup reason (for EmitterStartupError
  and ServiceStartupError) are named startup_reason, and the ones that
  hold a refusal code (for RequestRefusedError and _refuse) are named
  refusal_code.
- The Orrery helpers take only the values they check, typed as the
  unchecked JSON they are: _upload_list(object), _check_listed_name
  (object), _check_upload_url(SplitResult) and _check_publication_answer
  with the two answered values. The .get and urlsplit calls stay at the
  call sites, so every exception is raised where it was.
- The suppression reasons say what the code does: the interface
  constructors raise ValueError for every invalid value, and the JSON
  column raises the same type as json.loads for invalid JSON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk force-pushed the claude/ruff-exceptions branch from 7c783f5 to ff7d34b Compare November 2, 2026 15:07
anth-volk added a commit that referenced this pull request Nov 2, 2026
#58 to #69 were rebased onto main after #55 merged, so this merge
conflicted in the 18 files this branch had changed on top of #69. Each
keeps this branch's side, plus the version commit's bump in
pyproject.toml; python -m scripts.rules render regenerated the rules
view. The tree differs from e0cfd8e exactly by main's version commit
d732aab (2b88444..d732aab).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk marked this pull request as ready for review November 2, 2026 16:49
@anth-volk
anth-volk merged commit 4f148b6 into main Nov 2, 2026
12 checks passed
@anth-volk
anth-volk deleted the claude/ruff-exceptions branch November 2, 2026 16:49
anth-volk added a commit that referenced this pull request Nov 2, 2026
#63 to #69 were rebased onto main after #58 merged, so this merge
conflicted in the 14 files this branch had changed on top of #69. Each
keeps this branch's side, plus the release's version bump in
pyproject.toml; python -m scripts.rules render left the rules views as
they were. The tree differs from 8776389 exactly by main's release
(ff7d34b..a837a06).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Fix Ruff's exception-raising findings (EM, RSE, TRY)

1 participant