fix(lint): tune pylintrc and fix violations across core modules - #1793
fix(lint): tune pylintrc and fix violations across core modules#1793ppradyoth wants to merge 1 commit into
Conversation
Remaining violations after this PRRunning Here's the breakdown by type to help prioritise the next passes:
The 640 The remaining ~400 violations are largely mechanical and can be addressed file-by-file. I can batch them up as follow-on PRs once this draft standard is agreed. |
Suggested next steps after this draftI think the cleanest path is to keep this PR focused on establishing the linting baseline and fixing the concrete violations in the touched core files, then handle the larger remaining reduction as follow-up work once maintainers agree on policy. A local before/after count with
The biggest remaining bucket is
For the CI gate, my recommendation is to start with an agreed baseline/exit-code gate rather than a broad score threshold. A score threshold can still allow new important errors through if the aggregate score remains high enough. I would also suggest enabling the linting workflow in a follow-up PR after the dynamic-attribute policy is agreed, so this PR can stay reviewable and serve as the draft standard requested in #1792. |
|
@jmartin-tech pointed me here from a thread on #2006. Some context for @ppradyoth: I recently landed a small config_root fix in configurable.py, and the follow-up discussion was about whether a pylint rule could catch that class of bug in future — which led to "the lint standards need to settle first", which is this. So I have some interest in seeing it land. I pulled the branch and ran the suite plus a few pylint experiments rather than just reading the diff. I'm new to the repo and not a maintainer, so treat the opinions below as input rather than verdicts — the numbers are reproducible if you want to check them. Suite passes on the branch: One substantive finding.
Five runs on unmodified Diffing two runs' sorted output gives 19 differing lines, and all 19 are Nothing else varies — no
Options as I see them: keep Two smaller notes:
Also: the branch is 442 commits behind Deferring the dynamic (I used AI assistance analysing the diff; the commands and numbers above are from my own machine.) |
|
@anugram this is a useful review. You found a real problem. I reproduced all of it and acted on all three points. Rebased onto current main and force-pushed. The PR went from CONFLICTING to MERGEABLE. Two files conflicted.
Everything else applied clean. cyclic-import: confirmed. pylint 4.0.5, astroid 4.0.4, Python 3.13.5, macOS. Not your exact setup, but the behaviour matches. 12 runs of Then I diffed full runs against each other. Every varying line was R0401. Filter R0401 out and the runs are byte-identical at 1252 messages, same md5 across two separate sessions. So R0401 is the only unstable check in the whole run. Your read was right. I took your second option and disabled it, with the measurements written into pylintrc rather than left implicit. Reproducibility has to come before any gate. Happy to flip to "keep it enabled, exclude it from counts" if a maintainer prefers. One line either way. There is a second source of drift and it is not R0401. With R0401 disabled, main is stable at a fixed job count but not across job counts. All 7 differing lines are You said no This branch happens to remove it. The Numbers.
1252 to 1179, a drop of 73. 8 of that is the pylintrc change and 65 is code fixes. The old 1144 to 1068 figures were May's tree. Ignore them. One caveat on the branch row. The count is 1179 both ways and byte-identical within a job count. Across job counts, one R1705 on Director: fixed, now broad-exception-caught: agreed that a suppression should not be the thing that sets policy. I expanded the comment to state the reasoning and name it as a deliberate exception to the AGENTS.md rule. The JSONL log is flushed and closed before that call, so a digest failure costs the HTML summary and nothing else. @jmartin-tech your call on this one. Keep the carve-out, or make Test suite: my run was my machine running out of disk, not the branch. My full run on the rebased branch gave The errored tests are the HF-model-backed ones, A control run on unmodified main was clean through 18 percent before I stopped it to avoid filling my disk. So your Dynamic |
e82f4f0 to
08b62ce
Compare
|
Ran the rebased branch on Linux. Three things. Test suite is green. Since you're blocked on disk locally: pr1793 at Your cross-job Same count, same file, same check, same direction as your macOS run. And you're
right that my "no On the branch: The absolute counts are environment-dependent, and that may be the more useful result. Side by side:
Every absolute number differs by a consistent 85–88. Every internal delta is identical: +7 across job counts on main in both, zero across job counts on the branch in both. The branch rows are the interesting ones, since we're almost certainly on the same commit there — you force-pushed, I fetched after. Same code, 88 messages apart, on pylint 4.0.6 vs 4.0.5. Could you confirm which Nothing here argues against the pylintrc change you've made. If anything it supports writing the measurements in rather than leaving them implicit — though it might be worth noting the environment alongside the numbers, since they don't travel. The |
Addresses the issues catalogued in NVIDIA#1792. This is the draft standard requested by the maintainer — it fixes genuine violations, documents intentional exceptions with inline suppressions, and removes the unrecognized `suggestion-mode` option so the linting workflow can be enabled for CI runs. Changes by file: pylintrc - Remove `suggestion-mode=yes` (option removed in pylint 3.x; was causing E0015 "unrecognized-option" on every run) - Add `too-many-positional-arguments` to the disable list (consistent with the existing `too-many-arguments` exemption) - Add `Director` to `ignored-classes` (payload_list is a dynamic class attribute that pylint cannot infer as a dict at static-analysis time) garak/exception.py - Add missing module docstring (C0114) garak/command.py - Add docstrings to all public functions (C0116) - Remove unused `plugin_info as get_plugin_info` alias from the import inside `print_plugins` — it is imported again inside `_print_plugins_table` where it is actually used (W0611) - Suppress `broad-exception-caught` in `end_run` with explanation: report-building failures must not crash the CLI (W0718) - Suppress `no-member` on `cli_args` attribute access: `TransientConfig` sets these dynamically via argparse (E1101) garak/configurable.py - Add missing module and class docstrings (C0114, C0115); class docstring explains the ENV_VAR dynamic attribute pattern - Fix logging f-string to use %s lazy formatting (W1203) - Suppress `no-member` on `self.ENV_VAR` — defined by subclasses (E1101) - Suppress `unsupported-membership-test` on `_supported_params` — guarded by isinstance check above (E1135) - Suppress `access-member-before-definition` on `api_key` — intentional lazy-set pattern (E0203) garak/interactive.py - Add missing module docstring (C0114) - Add missing class docstring for GarakCommands (C0115) - Add docstrings to print_plugins, do_list, do_probe, do_quit (C0116) - Replace set-from-list-comprehension with set comprehension (R1718) - Fix logging f-string to use %s lazy formatting (W1203) - Make all return statements in do_probe consistent (R1710) - Remove f-string without interpolation in default() (W1309) - Rename unused cmd2 interface params to _command/_line/_args (W0613) - Suppress `no-member` on self.settings — cmd2.Cmd sets it dynamically garak/payloads.py - Fix import order: stdlib before third-party (C0411) - Add docstrings to module-level search() and load() (C0116) - Suppress `not-an-iterable` and `unsubscriptable-object` in Director.search/load — payload_list is None at class level but guaranteed to be a dict after _refresh_payloads() (E1133, E1136) garak/_config.py - Add missing class docstring for GarakSubConfig (C0115) - Add docstrings to _store_config, _garak_user_agent, set_all_http_lib_agents, set_http_lib_agents, get_http_lib_agents, load_base_config, load_config, parse_plugin_spec (C0116) - Fix all logging f-strings to use %s lazy formatting (W1203) - Rename dummy parameter to _dummy in _garak_user_agent (W0613) - Remove unnecessary else after raise in load_config (R1705) - Fix any() to use generator instead of list (R1729) - Add pylint: disable=global-statement comments on intentional global usage — _config is a module-level singleton and globals are by design garak/report.py - Fix import order: stdlib (datetime) before third-party (C0411) - Replace range(len(evals)) with direct iteration (C0200) - Suppress comparison-with-itself (all_tags == all_tags) — this is the standard pandas NaN sentinel check; NaN != NaN (R0124) Signed-off-by: ppradyoth <pradyoth0@gmail.com>
08b62ce to
35ced98
Compare
|
@anugram confirmed, Both my measurement sessions had Your conclusion is the right one and it is a better result than the thing I set out to measure. Gate on the delta, never the count. A contributor on a different pylint patch release would otherwise show an ~88 message regression having changed nothing at all. I took your suggestion and wrote the environment into pylintrc next to the numbers, plus the delta point so nobody has to rediscover it. Pushed as Two notes on that push. It is comment-only. Zero functional change, count still 1179 here. So your green suite run at I also corrected a number of my own while I was in there. The committed comment said 1266-1270 was 1267-1270. I had observed 1266 twice in my second measurement session and quoted the narrower range from the first. The range across all 12 runs is 1266-1270 and that is what is in there now. Thanks for running the suite. The branch is 5 commits behind main again as of now. Happy to rebase, but it is still MERGEABLE so I would rather not churn the SHA under your verification unless something actually conflicts. @jmartin-tech the |
|
Verified Agree on not rebasing. While it's MERGEABLE there's nothing to gain from churning the SHA, and it resets the verification for no benefit. If it goes CONFLICTING I'll re-run against the new head. One thing to fix in the new comment before this lands, and it's my error not yours — I mis-stated that range. "Scores 85-88 lower" is sitting right after the 1266-1270 figures, but those are unfiltered counts and 85-88 was the filtered gap. Against 1266-1270 my number is 1173, so that comparison is 93-97 lower.
The reason the two differ is itself worth a line: back out the R0401 counts and it's 14 cyclic-import messages on my setup against 22-26 on yours. So R0401's message count is environment-dependent, separately from which cycle paths each Simplest fix is probably to say 93-97 next to the unfiltered figures, since that's what they are. The deltas-reproduce/absolutes-don't conclusion is unaffected either way. |
Summary
This is the draft standard requested in #1792. It fixes genuine pylint violations, documents intentional exceptions with inline suppressions, and removes the unrecognised
suggestion-modeoption — so the Garak linting workflow can be enabled for CI runs.Every suppression has a comment explaining why it is intentional. Happy to iterate on any of these in review.
Changes
pylintrcsuggestion-mode=yes— removed in pylint 3.x, causedE0015on every runtoo-many-positional-argumentsto disable list (consistent with existingtoo-many-argumentsexemption)Directortoignored-classes—payload_listis dynamic and cannot be inferred at static-analysis timegarak/exception.py— add module docstringgarak/command.pyplugin_info as get_plugin_infoimport alias insideprint_pluginsbroad-exception-caughtinend_run— report failures must not crash the CLIno-memberoncli_args— set dynamically by argparsegarak/configurable.pyENV_VARdynamic attribute pattern%slazy formattingno-memberonself.ENV_VAR— defined by subclasses (as confirmed in Linting CI fails on main due to pre-existing pylint violations #1792)unsupported-membership-teston_supported_params— guarded byisinstanceaboveaccess-member-before-definitiononapi_key— intentional lazy-set patterngarak/interactive.pydo_probe_command/_line/_argsno-memberonself.settings— set dynamically bycmd2.Cmdgarak/payloads.pysearch()andload()not-an-iterable/unsubscriptable-objectinDirector—payload_listisNoneat class level but always a dict after_refresh_payloads()garak/_config.pydummy→_dummyin_garak_user_agent(required by requests UA callback signature)elifafterraiseany()instead of list# pylint: disable=global-statementwith explanations —_configis a module-level singleton by designgarak/report.pydatetime) before third-partyrange(len(evals))with direct iterationcomparison-with-itselfonall_tags == all_tags— standard pandas NaN sentinelTest plan
pylint --rcfile=pylintrc garak/— no new errors on changed filespytest tests/passes — no behaviour changes, docstrings/style onlyOpen questions for maintainers
generated-membersorignored-classes?Closes #1792