Skip to content

Enable ruff argument, idiom and pytest-style rules (ARG, B, C4, FBT, PERF, PLW, PT, PTH, RUF, SIM and others) - #802

Merged
anth-volk merged 27 commits into
mainfrom
ruff-idioms-arguments
Oct 20, 2026
Merged

anth-volk merged 27 commits into
mainfrom
ruff-idioms-arguments

Conversation

@anth-volk

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

Copy link
Copy Markdown
Contributor

Fixes #801

Same-Repository Draft PR Check

  • This PR is a draft.
  • This PR is from a branch in PolicyEngine/policyengine-sim-api, not a personal fork.

Summary

Phase 1 step 1.8, group 8a: ruff's argument, idiom and pytest-style rules. Bottom of the stack since #799 merged. Group 8b (#804) follows with the complexity refactors and the switch to select = ["ALL"].

Suppression counts

Inline suppression comments Rule codes in them
main 231 244
This PR (85f690c) 221 225

Against main, this PR adds 2 suppression comments and removes 12:

  • Added (2):
    • libs/policyengine-stage12-persistence/src/policyengine_stage12_persistence/store.py:157, ARG001 ("the ConnectionOpener protocol passes it by keyword"). This one is new; see "Suppressions this PR still adds".
    • stage12_runtime/fanout.py:241, BLE001. This is not new: the existing suppression at fanout.py:236 moved into the new per-call helper _cancel_segment_call.
  • Removed (12):
    • 9 # noqa: BLE001, S110 comments on try: … except Exception: pass blocks, which now use contextlib.suppress(Exception) (see "Best-effort calls").
    • 2 BLE001 comments, in the JWT decoder and the gateway's job-status handler. These handlers now re-raise with from <caught error>, which BLE001 accepts.
    • The moved fanout.py:236.

Suppressions this PR still adds

  • store.py:157 ARG001: open_connection_once is the default ConnectionOpener.
    • The store always passes operation_name= by keyword, and this implementation has no use for it.
    • Renaming the parameter would break that keyword.
    • The only signature ruff accepts is **_context: str, which accepts any keyword and so loosens the documented protocol.
    • Files under libs/*/src don't qualify for a file-level exception.

Changes

  • Unittest exemption (decided for this group): the shared rules tool's tests use unittest on purpose, because the tool needs only the standard library.
    • scripts/rules/tests/** is exempt from ruff's pytest-style rules (PT), registered as sim.quality.unittest-ruff-exemptions.
  • Rules: ruff.toml gains ARG, ASYNC, B, C4, FBT, PD, PERF, PGH, PLW, PT, PTH, RUF and SIM, one commit per project.
  • Executor target version: ruff doesn't read the projects' own requires-python. Every project and library file was therefore linted with ruff's default target version (below 3.11), although the executor requires Python 3.13.
    • per-file-target-version now lists projects/policyengine-simulation-executor/** as py313.
    • That makes the PERF203 suppression in database_retry.py unnecessary: ruff applies PERF203 only below Python 3.11.
    • It also reports 8 findings, all fixed: 5 I001 (tomllib now sorts with the standard library) and 3 UP017 (datetime.UTC).
    • Other projects keep the default target version.
  • Unused arguments (ARG):
    • Side-effect fixtures move to usefixtures, and unused *args/**kwargs become *_args/**_kwargs.
    • A named parameter is underscored only where every caller passes it positionally. That includes the executor's FastAPI lifespan(_app), which Starlette and FastAPI call positionally.
    • Tests take a file-level exception, decided 2026-10-16.
      • Test fakes and stubs mirror real signatures because callers pass by keyword: _build_simulation, _load_dataset, and stand-ins for Modal's FunctionCall.get(timeout=...) and JWTDecoder.__call__.
      • So ARG001, ARG002 and ARG005 join the file-level exceptions for tests and deployed-service tests.
      • At this head that covers 107 findings in 20 test files: ARG001 42, ARG002 34, ARG005 31.
    • Outside test directories, five former ARG suppressions are now code changes:
      • NoOpObservability subclasses the Observability protocol it implements, and span() is marked @override.
      • The executor's in-memory object store records each object's content type.
      • The gateway's mock FunctionCall records the timeout of each get().
      • The gateway's import_gateway_models fixture, which only requested the isolation fixture for its side effect, is gone. Its test uses usefixtures and imports the models module directly.
      • The executor lifespan's argument is underscored.
  • Signatures (FBT):
    • JWTDecoder.__init__'s auto_error is keyword-only; its only caller already passed it by keyword.
    • Test fakes now match their real signatures, for example modal.Dict.from_name(..., *, create_if_missing).
    • The precompute app's Modal local_entrypoint takes main(*, force=False).
      • Modal 1.4.2 builds a command-line option for every non-variadic parameter and calls the entrypoint with keyword arguments, so --force and --no-force are unchanged.
      • .github/scripts/modal-precompute.sh already passes --force as an option.
  • FastAPI auth (B008):
    • JWTDecoder.__call__ and the gateway's require_auth use Annotated[..., Depends(...)], so their token parameter no longer has a default; every caller passes one.
    • The entry app's CallerAuthenticator.__call__ keeps a module-level Depends marker, because FastAPI can't resolve Annotated on a callable instance in a module with postponed annotations.
    • Every OpenAPI document is byte-identical.
  • Re-raised errors (B904, 10): all use from <caught error>.
    • They're in the JWT decoder, the gateway's auth dependency and route handlers, and the legacy-dict resolver; none is in Stage 12 code.
    • Responses and messages are unchanged; tracebacks now say "The above exception was the direct cause…".
  • Idioms: comprehensions (C4, PERF401), pathlib (PTH), check=False on subprocess.run, function references instead of lambdas where nothing patches the target (PLW0108), ClassVar annotations and raw regex patterns (RUF), and pytest idioms (PT001, PT006, PT011 with match=, PT017, PT018).
    • Three findings are now code changes rather than suppressions:
      • SIM115: the executor's credentials temp file is entered on a contextlib.ExitStack held by a with statement around the yield.
        • It still stays open across the yield. The finally block still restores GOOGLE_APPLICATION_CREDENTIALS before the file is closed and deleted.
      • SIM118: the UK local-authority check calls HDFStore.keys(include="pandas"), which is the default call spelled out.
        • in store would also match HDF nodes that aren't pandas tables, so the explicit keys() call stays.
      • PT011: the native SPM test passes check= to pytest.raises (pytest 8.4), so the typed error code is part of the raises check.
  • Best-effort calls (SIM105): nine blocks that ran telemetry, or a Modal call cancel, and swallowed any error with try: … except Exception: pass now use with contextlib.suppress(Exception):. The old reason is a comment above each.
    • Same behaviour: they suppress the same exceptions around the same calls.
    • Suppression comments: this removes 9 # noqa: BLE001, S110 comments (18 rule codes) that exist on main. SIM105 was not selected on main, so no SIM105 suppressions existed to remove.
    • Still catch-all: each block still catches every Exception. Ruff's BLE001, S110 and SIM105 do not check contextlib.suppress, so these nine catch-all blocks are not counted as suppressions.
    • Where: the entry app (3) and its auth (1), the Modal app (2), segmented national cleanup (1), and the gateway's auth (1) and endpoints (1).
    • Coverage comment: the change had rewritten the gateway auth comment # pragma: no cover as # Pragma: no cover; the lower-case spelling is restored. The comment sits on its own line above the with statement, so coverage.py excludes no statement because of it.
  • Modal images:
    • Gateway and executor image files change, mostly in arguments and idioms.
    • In src/modal/app.py, two best-effort blocks become contextlib.suppress and import contextlib is added; it gains no __future__ import.
  • Registry: sim.quality.ruff-lint now lists the 13 families. The rules tool is synced from the Public API's group 8a (Enable ruff argument, idiom and pytest-style rules (ARG, B, C4, FBT, PERF, PLW, PT, PTH, RUF, SIM and others) policyengine-api#3924). Both test-exemption rules gain ARG001, ARG002 and ARG005.

Commits added on 2026-10-20 (85f690c)

  1. Lint the executor as Python 3.13, its required version: per-file-target-version, the PERF203 suppression removed, and the 8 I001/UP017 fixes.
  2. Use or underscore the arguments behind five ARG suppressions.
  3. Make the precompute entrypoint's force option keyword-only: removes FBT001/FBT002.
  4. Replace the SIM115, SIM118 and PT011 suppressions with code.
  5. Restore the lower-case coverage pragma comment in gateway auth.

Testing

At 85f690c, each project in an environment synced with uv sync --frozen --extra test --python 3.13:

Project Result
executor 1,292 passed, 22 skipped, 3 deselected
entry 534 passed
gateway 243 passed, 1 deselected
fastapi 14 passed
  • Not run: the three native SPM tests in test_canonical_spm_native.py are skipped without SPM_NATIVE_SMOKE_SOURCE, so the check= change there wasn't exercised. The integration tests need live services.
  • Lint: ruff 0.15.22 check --extend-select RUF100 . and format --check projects/*/src libs/*/src are clean.
  • Guards: the rules tool's unittests (80) and scripts/run_quality_guards.py, with the base main, pass. Rendering the rules leaves no diff.
  • Golden OpenAPI: the gateway golden OpenAPI test passes, and the golden file is unchanged.
  • CI/CD: no workflow changed.
    • No environment variable is added, renamed or rewired. The changed deployment code reads these:
      • setup_gcp_credentials reads GOOGLE_APPLICATION_CREDENTIALS, GOOGLE_APPLICATION_CREDENTIALS_JSON, GCP_CREDENTIALS_JSON, GOOGLE_CREDENTIALS and SERVICE_ACCOUNT_JSON, as before. The executor functions attach the gcp-credentials Modal secret, and Stage 12 workers attach stage12-evaluation-gcp-credentials. Both secrets exist; which keys they hold wasn't checked.
      • The precompute entrypoint reads POLICYENGINE_ARTIFACT_BUCKET, from the repository variable that the deploy workflow's "Run artifact precompute" step sets.
    • The other changed deployment files read no environment variable in the changed code: the executor's main.py, the two Modal utility programs, database_retry.py and the gateway auth comment.
  • CI: this is the lowest unmerged PR in the stack, so its full CI runs, including the Modal image smoke.

🤖 Generated with Claude Code

@anth-volk
anth-volk added this pull request to stack #755 October 14, 2026 15:08
@anth-volk anth-volk changed the title ruff idioms arguments Enable ruff argument, idiom and pytest-style rules (ARG, B, C4, FBT, PERF, PLW, PT, PTH, RUF, SIM and others) Oct 14, 2026
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch from cf4b8b2 to e25c130 Compare October 14, 2026 17:29
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch from e25c130 to 295754f Compare October 14, 2026 17:56
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch 3 times, most recently from 6c08e78 to 75eaed8 Compare October 14, 2026 21:06
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch 2 times, most recently from 3394d20 to ef914a0 Compare October 14, 2026 21:52
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch 2 times, most recently from 1a201e2 to 8023ea2 Compare October 15, 2026 15:09
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch from 8023ea2 to b672480 Compare October 15, 2026 16:06
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch 5 times, most recently from e238b8e to 6e33387 Compare October 16, 2026 05:12
@anth-volk
anth-volk force-pushed the ruff-idioms-arguments branch 3 times, most recently from 1168a56 to 9b13c69 Compare October 16, 2026 06:31
Base automatically changed from ruff-structure-imports to main October 16, 2026 06:39
anth-volk and others added 17 commits October 19, 2026 23:33
- Assign spm directly instead of through setattr (B010), use
  dict.fromkeys (C420), list unpacking (RUF005), one combined
  with-statement in the same enter/exit order (SIM117), a membership
  test (SIM109), merged upper-casing branches (SIM114), extend over an
  append loop (PERF401), and Path.open/Path.unlink (PTH).
- Keep, with reasons: the per-child and per-call try/except loops
  (PERF203), the credentials temp file that stays open across the
  yield (SIM115), HDFStore.keys(), which isn't a dict view (SIM118),
  the FastAPI lifespan hook's app parameter (ARG001), and the precompute
  local entrypoint's positional force flag, whose signature Modal turns
  into the CLI (FBT001/FBT002).
- Keep the telemetry and best-effort-cancel try/except blocks, whose
  except lines carry the BLE001/S110 reasons, and suppress SIM105 on
  their try lines.
- Fixtures: prefix the identity stubs' positional-only parameters and
  the fake local_entrypoint's **kwargs with an underscore (ARG).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Request side-effect fixtures with @pytest.mark.usefixtures, and drop
  an unused monkeypatch request (ARG001/ARG002).
- Prefix unused parameters of monkeypatched replacements with an
  underscore, after checking that every caller passes them positionally,
  and rename unused *args/**kwargs to *_args/**_kwargs (ARG001/ARG005).
- Keep, with reasons, parameters that callers pass by keyword: the
  _load_dataset and _reduce replacements, the fake _build_simulation and
  economic_impact_analysis keyword-only parameters, FunctionCall.get
  stand-ins' timeout, and the Stage 12 writer stand-ins' prefix. Fake
  model versions that duck-type .py's MicrosimulationModelVersion keep
  their parameters too.
- Mark the failing child store's create_or_resolve_simulation with
  @OverRide.
- Use tuples for parametrize names (PT006).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Pass booleans by keyword: DatasetSelection's is_default (FBT003), and
  keyword-only routed/accepted test parameters, the routed helper flag,
  the output-builder helper's options and the modal.Dict stand-ins'
  environment_name/create_if_missing, matching Modal (FBT001/FBT002).
- Match the real messages in pytest.raises (PT011); one native-only
  check keeps its broad ValueError, with a reason, because the
  rejecting layer's message varies. Make regex patterns raw or escaped
  (RUF043), give pytest.fail a message (PT016), and move the GCP
  credential cleanup check into a helper so pytest.raises wraps one call
  (PT012/SIM117).
- Use Path methods (PTH), literals and dict() (C408/C416), a list
  literal (SIM905), unpacking (RUF005), extend (PERF401), ClassVar
  annotations (RUF012), an underscore for an unused unpacked value
  (RUF059), explicit check=False (PLW1510) and an ASCII operator in a
  comment (RUF003).
- Pass regions.get, checks.append and nullcontext directly instead of
  through lambdas; nothing patches them (PLW0108).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The package update script stops overwriting its loop variable
  (PLW2901) and replaces the pyproject through Path.replace (PTH105).
- The integration conftest uses bare @pytest.fixture (PT001).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds ARG, ASYNC, B, C4, FBT, PD, PERF, PGH, PLW, PT, PTH, RUF and SIM to
the selected rule families. Every finding outside the shared rules tool
is fixed or carries an inline reason. Complexity (C90, PLR) is left for
group 8b.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sim.quality.ruff-lint now lists ARG, ASYNC, B, C4, FBT, PD, PERF, PGH,
PLW, PT, PTH, RUF and SIM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shared scripts/rules tool takes the Public API's group 8a fixes:
comprehensions, explicit check=False, bound loop variables and the
removed unused workflow-parser parameter. The rendered rules page picks
up the tool's new hash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#743 and #744 landed on main after this stack branched. Group 8a, which
this PR enables, flags their new code; each fix follows this PR's
conventions:

- F821: this PR's CI-script commit dropped the package updater's os
  import, but #744's verify-dispatch reads os.environ, so restore it.
- PTH123: the routing and sentinel CLIs open their files through Path.
- RUF100: the sentinel's report helper prints with an explicit file, so
  its T201 suppression is unused.
- ARG: tests request serialized_workflow through usefixtures (and the
  patched_modal fixture keeps it with a reason), drop unused monkeypatch
  requests, and prefix unused parameters of positional stand-ins.
- FBT002: the routing-plan test helper takes force by keyword.
- PT012/PT018/B905/RUF043: one call per pytest.raises, one condition per
  assert, an explicit non-strict zip over call chains of different
  lengths, and a raw match pattern.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#789 landed on main after this stack branched. Group 8a, which this PR
enables, flags its new code; each fix follows this PR's conventions:

- ARG001/ARG002: open_connection_once and the telemetry-recording test
  runtime keep keyword parameters their protocols pass, with reasons; the
  test's random.uniform stand-in prefixes its unused positional bound.
- PERF203: the connection retry loop catches each refused attempt by
  design, with a reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#787 landed on main after this stack branched. Group 8a, which this PR
enables, flags its new code; each fix follows this PR's conventions:

- ARG002: the shared in-memory object store keeps upload_bytes's
  content_type, which Stage12ArtifactStore passes by keyword, with the
  reason this PR gave the per-file fake it replaced.
- PT011: the invalid SPM provenance test expects pydantic's
  ValidationError, which every rejected value raises, not any ValueError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#795 landed on main after this stack branched. Group 8a, which this PR
enables, flags its new code; each fix follows this PR's conventions:

- ARG002: the child-deadline tests take the bare_country fixture through
  pytest.mark.usefixtures, like the runner tests.
- ARG005: their _reduce stand-ins keep country_module, which run() passes
  by keyword, with the same reason.
- ARG001: _crashing_call prefixes the clock it takes only to match
  _stuck_call's signature.
- PT006: the child-timeout telemetry test names its parameters in a tuple.
- SIM105: _cancel_call keeps its try/except, whose except line carries the
  BLE001/S110 reason, like the best-effort cancel it replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
enables, flags its new tests; each fix follows this PR's conventions:

- ARG002: its fake Modal calls, recording runtimes and rejecting
  aggregate writer keep the timeout, status_code and prefix keywords of
  the interfaces they stand in for, with the reasons this PR gave the
  other fakes.
- PT011: the stage-and-role summary test matches the message it raises
  rather than accepting any ValueError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#758 landed on main after this stack branched. Group 8a, which this PR
enables, flags its new code; each fix follows this PR's conventions:

- B008: CallerAuthorizer.require_permission builds the authenticate
  dependency marker once and reads it from the nested dependency's
  default. The Annotated form can't be used: the module postpones
  annotations, and FastAPI resolves them against the module's globals,
  which don't hold the authorizer's dependency. FastAPI sees the same
  dependency, so each route's permission check is unchanged.
- SIM105: the permission-missing event keeps its try/except, whose
  except line carries the BLE001/S110 reason, like the module's other
  telemetry.
- ARG: the permission tests' fake decoders explain their unused
  parameters and the _decoder replacements prefix theirs; each
  table-driven test underscores the PROTECTED_ROUTES column it doesn't
  read, so the test ids stay the same.
- ARG001: the deployed enforcement test requests permission_enforcement
  through pytest.mark.usefixtures; pytest still sets it up first, so the
  test skips before fetching a token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#781 landed on main after this stack branched. Group 8a, which this PR
enables, flags its new code; each fix follows this PR's conventions:

- ARG: stand-ins whose callers pass a parameter positionally prefix it
  with an underscore (the progress store's reads and writes, the patched
  Simulation.ensure, _country_module, get_region, Function.from_name, the
  preempted _set_modal_call_attributes, time.sleep and the
  on_first_ensure stand-ins), and unused *args/**kwargs become
  *_args/**_kwargs. Parameters callers pass by keyword keep a reason: the
  impact-analysis, _load_dataset, dispatch, run_simulation_impl and
  _configure_modal_observability stand-ins, the spawn stand-in's
  observability_context, the _reduce stand-in's country_module, the fake
  FunctionCall.get's timeout and the generated client's sync_detailed.
- ARG001/ARG002: the contract's missing-record test and the bundle
  manifest test request their fixtures through pytest.mark.usefixtures.
- B018: the failed-analysis test assigns the property it reads inside
  pytest.raises.
- SIM105: the Modal app's stage-duration telemetry keeps its try/except,
  whose except line carries the BLE001/S110 reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test fakes and stubs mirror real signatures, because callers pass those
arguments by keyword: run() passes country_module=, the runtime passes
keyword-only options, and stand-ins replace modal.FunctionCall.get and
JWTDecoder.__call__. Fixtures also request other fixtures only for their
side effects.

Tests are among the files allowed file-level exceptions, so ARG001,
ARG002 and ARG005 join the tests' and the deployed-service tests'
exemptions. That removes 72 inline suppressions from 16 test files.
Application code keeps its six unused-argument suppressions and their
reasons.

Comments and configuration only: no code changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nine blocks ran a best-effort call and swallowed any error with
try/except Exception: pass:
- telemetry context and events in the entry app, its auth, the Modal
  app and the gateway;
- a Modal call cancel during segmented national cleanup.

Each block carried three suppressions: SIM105 on the try, and BLE001
and S110 on the except.

Each is now with contextlib.suppress(Exception), with the old reason as
a comment above it. It suppresses the same exceptions and runs the same
calls, so behaviour is unchanged. That removes 18 suppression lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#712's segmentation and cache code raised 16 group 8a findings. Each is
fixed in the code, with no new suppression:

- PERF203: the policy-period parser and the segment-cancellation loop
  move their try/except into a helper called once per item. The parser's
  error helper is now typed NoReturn, since it always raises. The
  cancellation helper keeps #712's BLE001 reason.
- RUF022: stage12_runtime's __all__ is sorted.
- Tests: subprocess.run states check=False (PLW1510), match= patterns
  are raw or escape a literal dot (RUF043), compound asserts are split
  (PT018), the import guard extends its list from a generator (PERF401),
  boolean helper and parametrized arguments are keyword-only
  (FBT001/FBT002), and the segment-function stand-in is an instance
  whose spawn method takes Modal's observability_context by keyword
  (ARG004), as modal.Function.from_name returns an object.

The rebase onto #712 also dropped this branch's PERF203 suppression in
coordination.py, since #712 replaced the loop it was on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk and others added 5 commits October 20, 2026 16:22
Ruff reads no project's requires-python here, so it linted the executor
with its default target version. PERF203 applies only below Python 3.11,
so the retry loop in database_retry.py needed a suppression that the
executor's own Python (3.13) doesn't call for.

Add the executor to per-file-target-version as py313, remove that
suppression, and fix the eight findings the new target version reports:
tomllib is now sorted with the standard library (I001, five files), and
datetime.timezone.utc becomes datetime.UTC (UP017, three files).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- NoOpObservability now subclasses the Observability protocol it already
  implemented, and span() is marked @OverRide, which ruff exempts from
  ARG002.
- The executor's in-memory object store records each object's content
  type, and the gateway's mock FunctionCall records the timeout each get()
  was called with, so both fakes use the arguments they mirror.
- The gateway's import_gateway_models fixture only requested the module
  isolation fixture for its side effect. The test that used it now requests
  isolation with usefixtures and imports the models module itself, named
  in GatewayImportModuleNames.models.
- The executor's FastAPI lifespan takes _app: Starlette and FastAPI pass
  the app positionally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Modal 1.4.2 builds a command-line option for every non-variadic parameter
of a local entrypoint and calls it with keyword arguments, so a
keyword-only force still gives --force/--no-force. The test already calls
main(force=True). This removes the FBT001/FBT002 suppression.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- setup_gcp_credentials enters the credentials temp file on an ExitStack
  held by a with statement around the yield. The file still stays open
  across the yield; the finally block restores GOOGLE_APPLICATION_CREDENTIALS
  first, and the stack then closes, and so deletes, the file, the same order
  as before.
- The UK local-authority check calls HDFStore.keys(include="pandas"), the
  default spelled out, and keeps a comment on why `in store` differs.
- The native SPM test passes check= to pytest.raises (pytest 8.4), so the
  typed error code is part of the raises check instead of a later assert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The contextlib.suppress change rewrote "# pragma: no cover" as the prose
"# Pragma: no cover". Put back the original lower-case spelling. The
comment sits on its own line above the with statement, so coverage.py
excludes no statement because of it either way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk marked this pull request as ready for review October 20, 2026 14:08
@anth-volk
anth-volk requested a review from a team as a code owner October 20, 2026 14:08
@anth-volk
anth-volk merged commit be228a5 into main Oct 20, 2026
14 checks passed
@anth-volk
anth-volk deleted the ruff-idioms-arguments branch October 20, 2026 14:08
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.

Enable ruff argument, idiom and pytest-style rules (ARG, B, C4, FBT, PERF, PLW, PT, PTH, RUF, SIM and others)

1 participant