Repository navigation
Conversation
anth-volk
added this pull request to stack #3917
October 14, 2026 15:08
2 tasks done
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
2 times, most recently
from
October 14, 2026 16:59
7b5a851 to
d89b4b5
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
from
October 14, 2026 18:08
d89b4b5 to
24a3be7
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
2 times, most recently
from
October 14, 2026 20:04
1d0d644 to
6ad4b2c
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
7 times, most recently
from
October 15, 2026 15:21
29808ba to
aae6fe4
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
from
October 15, 2026 15:45
aae6fe4 to
bc3381a
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
from
October 15, 2026 17:21
bc3381a to
0ae1220
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
from
October 16, 2026 05:40
0ae1220 to
cbac3c2
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
2 times, most recently
from
October 16, 2026 06:40
1827772 to
a4541ae
Compare
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
from
October 20, 2026 18:00
869fee2 to
5791dc2
Compare
anth-volk
added a commit
that referenced
this pull request
Oct 20, 2026
#3924 moved the payload file read out of the async _run() into main(), so _run() now takes the parsed payload as its second argument. The test reads the same payload file and passes it in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
from
October 20, 2026 18:29
5791dc2 to
d8a153b
Compare
anth-volk
added a commit
that referenced
this pull request
Oct 20, 2026
#3924 moved the payload file read out of the async _run() into main(), so _run() now takes the parsed payload as its second argument. The test reads the same payload file and passes it in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shared rules tool needs only the standard library, so its tests use unittest on purpose. Registered as api.quality.unittest-ruff-exemptions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rewrite keyword dict() calls as dict literals, generators passed to set() as set comprehensions and a constant-valued dict comprehension as dict.fromkeys. Replace append loops with list.extend or a comprehension, and the two conditional bundle-merging loops with dict.update. Key order, values and messages are unchanged. Two lists that mypy inferred from their first append are now annotated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Combine nested with statements into one statement with the same contexts in the same order, collapse nested ifs whose inner condition has no side effects, drop .keys() from dict membership and iteration, put constants on the right of comparisons, and open the smoke test's temporary log files in context managers. The two try/except/pass blocks that catch specific exceptions become contextlib.suppress. Groups 5 and 6 already gave the best-effort telemetry and logging blocks that form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Annotate mutable class attributes with ClassVar, make the implicit Optional defaults explicit, sort __all__, use unpacking instead of list concatenation and conversion flags instead of str() in f-strings, parenthesize a mixed and/or, write regex match patterns as raw strings (escaping the two dots that are literal), prefix unused unpacked names with an underscore, and drop the E402 suppressions that ruff no longer needs after an os.environ assignment. compare_economic_outputs already defaulted country_id to None, so the three helpers it passes country_id to, which only compare it with "uk", are annotated to accept None too. The fullwidth and Arabic-Indic digits in the identity tests are the inputs under test, so their lines keep them with a RUF001 suppression. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pass parametrize names as tuples and values as lists, split composite assertions, return from the fixture that has no teardown, and give every broad pytest.raises a match on the message the code really raises. Where a test only asserted that a literal appeared in the message, the match replaces that assertion; stricter assertions stay. The two tests that raise inside a transaction to prove it rolls back now do the work in a local helper, so pytest.raises wraps a single call. The forecast test asserts on the exception from pytest.raises instead of in an except block, and the Alembic test enters pytest.warns around the lookup that emits the warning rather than around the script load as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prefix the ignored *args and **kwargs of the cache-key callbacks and the disabled cache backend with an underscore, and the parameters of the rules tool's no-op resolver lambda, which is only called positionally. Drop the unused job_indent parameter of the rules tool's private _parse_job and its two call sites. Keep the named parameters that callers may pass by keyword, with a reason: Flask passes the <country_id> URL variable to the views, the disabled cache backend overrides InMemoryCacheBackend (typing.override needs Python 3.12 and typing_extensions is not a declared dependency), and RegistryCapability implements the SPMCapabilitySource protocol. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Request fixtures that a test needs only for their side effects through pytest.mark.usefixtures instead of unused parameters. The collected test IDs are unchanged, and the moved fixtures patch independent targets, so setting them up before the remaining arguments changes nothing. Prefix unused parameters of stand-in lambdas and callbacks with an underscore where every caller passes them positionally (checked against the code under test), including every ignored *args and **kwargs. Keep, with a reason, the parameters that callers may pass by keyword or that a framework passes: fixtures that depend on another fixture for its side effect (marks don't apply to fixtures), methods of stand-in classes that implement or override the interface the code under test calls, a SQLAlchemy event listener, and stand-ins for callables that EconomyService, the migration target or importlib callers call with keyword arguments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every caller already passes these flags by keyword, so they become keyword-only: spm_requested (and prepared) on PolicyEngineCountry's calculate and prepare_calculation, include_cliffs and the options after it on EconomyService._setup_sim_options, and transaction on the cache backend protocol's pipeline and the in-memory fake. The test helpers and stand-ins get the same treatment, and the test inspector is built with table_exists by keyword. sa.literal receives its value by keyword. The FastAPI current query parameter and the _reflected argument of Alembic's positional include_object hook keep their shape, with a reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- B904: re-raise the BadRequest of the simulation and report-output routes from the caught validation error, keeping it as the cause. - B905: zip strictly where the lengths are fixed by literals (the country tuples and the income-change bounds and labels), and say strict=False in the contract helper, which compares a prefix. - B023: bind the loop values that the rules tool's adapter check and a dual-write test's mock side effects close over, as default arguments. Each closure runs only within its own iteration. - B009: read the region attributes directly instead of through getattr with a constant name. - PLW1510: pass check=False to the rules tool's subprocess calls, which inspect the return code themselves. - PLW2901: give the float-converted reform value and the bracketed parameter name their own variables instead of reusing the loop names. - PLW0603: keep the global statements for the process-owned database state and readiness flag, with a reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Open the bundle manifest and GITHUB_ENV through Path.open, which opens them the same way as open(). Keep the remaining calls, with a reason: MicroSeries overrides .values and its .to_numpy() emits a different warning, the dashboard experiment reads a string column that pandas 3 stores in an extension array, and the runtime measurement script reads its payload file once before any request starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Select ARG, ASYNC, B, C4, FBT, PD, PERF, PGH, PLW, PT, PTH, RUF and SIM. The earlier commits in this branch fix or explain every finding, so ruff reports none. Complexity (C901 and PLR) is left for group 8b. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
api.quality.ruff-lint now lists ARG, ASYNC, B, C4, FBT, PD, PERF, PGH, PLW, PT, PTH, RUF and SIM. The rendered rules page also picks up the rules tool's new hash. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- FBT001: require_not_mirror_owned and require_owned_user_policy take their boolean flag by keyword, and their three callers pass it so. - B008: the default account authenticator declares its bearer and unauthenticated-user security dependencies with Annotated instead of as parameter defaults. - ARG001: DELETE /v2/me needs its country query only for validation, so the parameter is named _query, like the _size request-size check. The OpenAPI documents, with the injected test authenticator and with the default one, are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fects The five run-progress polling tests and the two run-progress economy service tests took mock_modal_logger or mock_logger without using it (ARG002). They now request it through pytest.mark.usefixtures, as the neighbouring tests do; the collected test IDs are unchanged. These were the ruff group 8a findings in the code #3916 added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- PT018: split the 12 composite assertions, so a failure names the part that failed. - SIM117: the three pytest.raises blocks that open a transaction enter both contexts in one with statement, in the same order. - PT011, PT007: the update-input validation tests match the message each ValueError really carries, and the user-service guard's parametrize values are a list. - ARG: the qualification test and the signed-out header test request the sessions and configured_auth fixtures through pytest.mark.usefixtures; stand-in lambdas and result callbacks that are only called positionally prefix their unused parameters with an underscore, as does the Alembic test's unused loop name; and the deferred reference service test's stand-in keeps its keyword parameters with a reason. - FBT001: the signed-out header test takes auth_configured by keyword, which pytest already does. - SIM118, RUF005: drop a .keys() membership check and unpack a list instead of concatenating it. The collected test IDs are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test fakes and stand-ins mirror the signatures of what they replace, because callers pass those arguments by keyword. Each one carried an inline ARG001, ARG002 or ARG005 suppression with that reason. Tests may take file-level exceptions, so the **/tests/** entry and api.quality.tests-ruff-exemptions now include the three codes, and the 32 inline codes in 16 test files are removed. Application code keeps its unused-argument suppressions and reasons. Comments and configuration only: no code changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…W0603) Remove the 11 PLW0603 suppressions without changing behaviour: - readiness: the lock and boolean pair becomes one threading.Event, set at import because the default is ready. mark_not_ready clears it, mark_ready sets it, and is_ready still runs the configuration check only when it is set. - data/orm: the Cloud SQL connector, engine and session factory are fields of one private _CloudSqlState instance. - data/v2/database: the engine, its process ID, its URL fingerprint and the session factory are fields of one private _V2EngineState instance. _state_lock and the fork handling are unchanged. The two tests that read or patch these names now use the state objects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ruff does not report unused arguments of a method decorated with @OverRide, so this removes the 9 ARG002 suppressions: - runtime_cache/fake.py: every DisabledCacheBackend method overrides InMemoryCacheBackend and is decorated with @OverRide. - worker_spm_release.py: RegistryCapability now subclasses the SPMCapabilitySource protocol explicitly, and get_spm_capability is decorated with @OverRide. typing.override needs Python 3.12; typing_extensions.override also works on 3.11, the oldest version the project supports. typing-extensions was already installed as an indirect dependency (4.15.0) and is now declared directly as typing-extensions>=4.4,<5, the release series that has override. uv.lock records the new direct dependency only; no package version changes. The lock was written with uv 0.12.1, the version CI pins, so its format revision is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tests that check numeric identity use Arabic-Indic and full-width
digits as inputs. Writing them as escape sequences instead of literal
characters removes the 6 RUF001 suppressions: single digits use named
escapes such as "\N{FULLWIDTH DIGIT ONE}", and the two ten-digit
translation tables use \u escapes, with a comment naming them.
The parsed ASTs of all four files, and so every string constant and test
parameter, are identical to the previous version.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…NC240) main() now reads and parses the calculate payload file before asyncio.run(), and passes the parsed payload to _run(). The file is still read once, before any request, so the requests and output are unchanged. This removes the ASYNC240 suppression for a blocking read inside an async function. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The privilege reconciliation appends its GitHub step summary through Path.open, the annotation scan in privilege_requirements extends its list from one generator, and the manifest proof test builds its no-access map with dict.fromkeys. Behaviour is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
ruff-idioms-arguments
branch
from
October 20, 2026 22:05
d8a153b to
5ae76f9
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #3924 +/- ##
===========================================
+ Coverage 49.20% 84.74% +35.53%
===========================================
Files 242 258 +16
Lines 14307 15676 +1369
Branches 2357 2640 +283
===========================================
+ Hits 7040 13284 +6244
+ Misses 6637 1623 -5014
- Partials 630 769 +139 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3923
Summary
Phase 1 step 1.8, group 8a: arguments, idioms and pytest style. Stacked on #3920. Group 8b follows with the complexity refactors and the switch to
select = ["ALL"].ARG001,ARG002andARG005join the**/tests/**file-level exceptions (api.quality.tests-ruff-exemptions). That removes 32 inline codes from 16 test files here and 37 by Register weighted-microdata rules, with AST guards and #767 proofs #3938.scripts/rules/tests/**is exempt from ruff's pytest-style rules (PT), registered asapi.quality.unittest-ruff-exemptions.selectgainsARG,ASYNC,B,C4,FBT,PD,PERF,PGH,PLW,PT,PTH,RUFandSIM. All 912 findings are fixed, covered by the tests' file-level exceptions, or kept with one of the 8 inline suppressions listed below. There's one commit per family.@pytest.mark.usefixtures; the collected test IDs are identical.*args/**kwargsbecame*_args/**_kwargs. A named lambda or callback parameter is underscored only where every caller passes it positionally, as in the v2 Alembic environment'sinclude_objecthook.@overridefromtyping_extensions, which works on Python 3.11 (typing.overrideneeds 3.12). Ruff doesn't report unused arguments of an@overridemethod. This covers everyDisabledCacheBackendmethod inruntime_cache/fake.py, andRegistryCapability.get_spm_capabilityinworker_spm_release.py, which now subclasses theSPMCapabilitySourceprotocol explicitly.typing-extensionsis now a direct dependency (>=4.4,<5;overridewas added in 4.4). It was already installed indirectly at 4.15.0. Theuv.lockdiff only records the new direct dependency: no package version changes, and the lock was written with uv 0.12.1, the version CI pins, so its format revision is unchanged.<country_id>URL variable by keyword keep an inline reason (see "Inline suppressions").PolicyEngineCountry.calculateandprepare_calculation(spm_requested,prepared),EconomyService._setup_sim_options, and the cache backend protocol'spipeline(*, transaction=True). Every caller already passed these by keyword. The FastAPIcurrentquery parameter and Alembic's positionalinclude_objecthook are kept, with reasons.BadRequest(...) from e. The 400 responses are unchanged; only the traceback's chaining text changes.zip(..., strict=True)where the lengths are fixed by literals.readiness.py: the lock and boolean pair is onethreading.Event, set at import because the default is ready.mark_not_readyclears it andmark_readysets it.is_readystill returnsFalsewithout running the configuration check when the event is clear, and runs the check otherwise.data/orm.py: the Cloud SQL connector, engine and session factory are fields of one private_CloudSqlStateinstance.data/v2/database.py: the engine, the ID of the process that created it, its URL fingerprint and the session factory are fields of one private_V2EngineStateinstance._state_lockand the fork handling are unchanged.tests/unit/data/test_sqlalchemy_v2.pypatches theormstate, andtests/unit/v2/test_database.pyreads the v2 engine's process ID. Both now use the state objects. No test patches the readiness state.try: … except Exception: passaround a telemetry or logging call intowith contextlib.suppress(Exception):, with the reason in a comment above it. HereSIM105converts the two remainingtry/except/passblocks, which catch specific exceptions:country.py(TypeError,ValueError,OverflowError) andreform_impacts_service.py(CacheCoordinationError). No suppression changes.dict()calls become literals, plus comprehensions (C4, PERF), simplified conditions and combinedwithstatements in the same order (SIM),ClassVarannotations, explicitOptionaltypes, raw regex patterns and sorted__all__(RUF),Path.open(PTH) andcheck=Falseonsubprocess.run(PLW1510)."\N{FULLWIDTH DIGIT ONE}"for single digits, and\uescapes, with a comment, for the two ten-digit translation tables.scripts/measure_cloud_run_runtime.pyreads and parses the payload file inmain()beforeasyncio.run(...), and passes the parsed payload to_run().pytest.raisesgainmatch=with the real message; where a test only asserted that text separately, the match replaces that assertion. Parametrize names and values use tuples and lists, and composite assertions are split.api.quality.ruff-lintnow lists the 13 families. The rules tool changed (comprehensions,check=False, a bound loop variable and an unused parser parameter removed); sim takes the same changes in Enable ruff argument, idiom and pytest-style rules (ARG, B, C4, FBT, PERF, PLW, PT, PTH, RUF, SIM and others) policyengine-sim-api#802.Inline suppressions
This PR adds 8 inline suppressions; it adds no file-level exception for application code.
policyengine_api/routes/household_routes.py,get_calculateandget_calculate_fullARG001<country_id>URL variable by keyword;validate_countrychecks it.policyengine_api/routes/user_profile_routes.py,get_user_profileandupdate_user_profileARG001<country_id>URL variable, also checked byvalidate_country.migrations/v2/env.py,_include_application_object(..., _reflected, ...)FBT001include_objecthook with positional arguments.policyengine_api/fastapi_routes/v2/metadata/parameter_routes.py,current: bool = FalseFBT001,FBT002ParameterValueListingQuerydependency, which removes this suppression.policyengine_api/services/economy_comparison.py, twoMicroSeries(...).valuesreadsPD011MicroSeriesoverrides.values, and.to_numpy()emits a different warning.Suppression counts
Counted as lines containing
# noqain Python files (git grep -c '# noqa' -- '*.py', summed). The counts are one lower than before, because #3959 merged twoBLE001suppressions onmaster:# noqaE402removed)E402removed)2026-10-20: rebased onto #3985
#3985 (v2 table privileges) added new application code. This PR's rules found three findings in it, and commit
d8a153beffixes them with code changes, adding no suppressions:PTH123: the privilege reconciliation appends its GitHub step summary throughPath.open.PERF401: the annotation scan inprivilege_requirements.pyextends its list from one generator.C420: the manifest proof test builds its no-access map withdict.fromkeys.Behaviour is unchanged, and #3985's 70 privilege tests pass. The only environment variable the changed code reads is
GITHUB_STEP_SUMMARY, which the GitHub Actions runner sets for every step; how it is read is unchanged. The suppression counts are unchanged too.2026-10-20 update: 27 fewer suppressions
Four commits on top of the branch remove 27 of the 35 inline suppressions this PR added. The earlier commits are unchanged.
023b02420Keep process state in objects instead of rebinding module globals (PLW0603): removes 11. See "Module-level state" above.14f29aeabMark method overrides withtyping_extensions.override(ARG002): removes 9, and adds thetyping-extensionsdirect dependency.e319ee6d6Write the non-ASCII test digits as escape sequences (RUF001): removes 6. The parsed ASTs of all four test files are identical to the previous version, so every string constant and test parameter is unchanged.f6d25ebb6Read the load generator's payload before starting the event loop (ASYNC240): removes 1.Testing
2026-10-20 update. At this tip (
f6d25ebb6), on Python 3.12 with theuv.lockdependencies (uv sync --frozen --extra dev --python 3.12):ruff format --check .andruff check .(ruff 0.15.12, withRUF100) are clean.python scripts/run_quality_guards.pyandpython -m scripts.rules guard --base-ref origin/ruff-structure-importspass, andpython -m scripts.rules renderleaves no diff.mypy(the configured files): no issues in 167 source files. mypy ondata/orm.py,data/v2/database.py,readiness.py,runtime_cache/fake.pyandworker_spm_release.pyreports nothing new.pytest tests/unit: 2,686 passed.data/orm.py,data/v2/database.pyandreadiness.pyadd, remove and rename none, and each is read in the same place and way as before.orm.pyreadsPOLICYENGINE_DB_INSTANCE_CONNECTION_NAMEandPOLICYENGINE_DB_PASSWORD(both required), andPOLICYENGINE_DB_USERandPOLICYENGINE_DB_NAME(both default topolicyengine), when the engine is first built. It still callsload_dotenv()at import.database.pyandreadiness.pyread none directly. They call the same settings loaders under the same conditions.2026-10-19 update. The stack was restacked onto #3915, which now converts the last best-effort blocks and removes the dashboard experiment, so this PR's
contextlib.suppresscommit was dropped and itsSIM105change shrank to the two blocks above. At that tip (7e92040),ruff check(withRUF100) andruff format --checkwere clean and the quality guards passed. At the top of the stack (#3938, 7b23281), themake testset passed: 3,197 tests on Python 3.12 with theuv.lockdependencies. The earlier notes below describe the previous tips.make testset (tests/unit,tests/contract, to_refactor and the dedupe integration test): 2,416 passed, 4 failed, the same as the base today.master.tests/unit/v2/test_stage12_comparison_models.pyfixesretention_expires_atat 2026-10-14 but leavescreated_aton the real clock, so its inserts fail the retention check since that date. It's unrelated to this PR and needs its own fix againstmaster.make typecheck-v2is clean. mypy on the 128 changed files outside its file list shows no new errors.ruff checkandruff format --check(0.15.12) are clean repo-wide./v2/openapi.jsonpreview and the legacy spec are byte-identical to the base.ruff check(includingRUF100) andruff format --checkare clean, and so are the guards and the rules tool unittests.noqacomments, apart from:contextlib.suppressrewrites;ruff formatre-wrapped once its comment was gone..github/find-api-model-versions.pychanged only in idioms; it reads onlyGITHUB_ENV, which the Actions runner provides, and only when run without--shell, which its CI caller always passes.CI complete, which fails and says why. Its full run starts once the PRs below it merge.🤖 Generated with Claude Code