Skip to content

fix(lint): tune pylintrc and fix violations across core modules#1793

Open
ppradyoth wants to merge 1 commit into
NVIDIA:mainfrom
ppradyoth:fix/pylint-config-and-violations
Open

fix(lint): tune pylintrc and fix violations across core modules#1793
ppradyoth wants to merge 1 commit into
NVIDIA:mainfrom
ppradyoth:fix/pylint-config-and-violations

Conversation

@ppradyoth
Copy link
Copy Markdown

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-mode option — 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

pylintrc

  • Remove suggestion-mode=yes — removed in pylint 3.x, caused E0015 on every run
  • Add too-many-positional-arguments to disable list (consistent with existing too-many-arguments exemption)
  • Add Director to ignored-classespayload_list is dynamic and cannot be inferred at static-analysis time

garak/exception.py — add module docstring

garak/command.py

  • Add docstrings to all public functions
  • Remove unused plugin_info as get_plugin_info import alias inside print_plugins
  • Suppress broad-exception-caught in end_run — report failures must not crash the CLI
  • Suppress no-member on cli_args — set dynamically by argparse

garak/configurable.py

  • Add module and class docstrings; class docstring explains the ENV_VAR dynamic attribute pattern
  • Fix logging f-strings to %s lazy formatting
  • Suppress no-member on self.ENV_VAR — defined by subclasses (as confirmed in Linting CI fails on main due to pre-existing pylint violations #1792)
  • Suppress unsupported-membership-test on _supported_params — guarded by isinstance above
  • Suppress access-member-before-definition on api_key — intentional lazy-set pattern

garak/interactive.py

  • Add module docstring, class docstring, and missing function docstrings
  • Replace list comprehension with set comprehension
  • Fix logging f-strings
  • Make return statements consistent in do_probe
  • Remove f-string without interpolation
  • Rename unused cmd2 interface params to _command/_line/_args
  • Suppress no-member on self.settings — set dynamically by cmd2.Cmd

garak/payloads.py

  • Fix import order: stdlib before third-party
  • Add docstrings to module-level search() and load()
  • Suppress not-an-iterable/unsubscriptable-object in Directorpayload_list is None at class level but always a dict after _refresh_payloads()

garak/_config.py

  • Add missing docstrings
  • Fix logging f-strings
  • Rename dummy_dummy in _garak_user_agent (required by requests UA callback signature)
  • Remove unnecessary elif after raise
  • Use generator in any() instead of list
  • Add # pylint: disable=global-statement with explanations — _config is a module-level singleton by design

garak/report.py

  • Fix import order: stdlib (datetime) before third-party
  • Replace range(len(evals)) with direct iteration
  • Suppress comparison-with-itself on all_tags == all_tags — standard pandas NaN sentinel

Test plan

  • pylint --rcfile=pylintrc garak/ — no new errors on changed files
  • pytest tests/ passes — no behaviour changes, docstrings/style only
  • Linting CI workflow passes on this branch

Open questions for maintainers

  1. Are there other intentional dynamic-attribute patterns we should add to generated-members or ignored-classes?
  2. Preferred CI gate: minimum pylint score threshold or just exit code 0?
  3. Should enabling the linting workflow for PRs be part of this PR or a follow-up?

Closes #1792

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>
@ppradyoth
Copy link
Copy Markdown
Author

Remaining violations after this PR

Running pylint --rcfile=pylintrc garak on this branch shows 1,068 remaining violations across 106 files (excluding import-error and cyclic-import which are environment/architecture issues unrelated to lint style).

Here's the breakdown by type to help prioritise the next passes:

Count Message Notes
640 no-member Dominant issue — almost entirely the plugin system's dynamic attribute loading (generators, probes, detectors, buffs). The generated-members or ignored-classes config is the right fix rather than 640 inline suppresses.
86 logging-fstring-interpolation Mechanical fix — f"..."%s lazy format throughout probes/generators.
63 missing-function-docstring Spread across probe, generator, detector, and harness modules.
35 no-else-return / 12 no-else-raise Style fixes, safe to automate.
35 broad-exception-caught Needs case-by-case review — some may be intentional (network calls, plugin loading).
32 use-list-literal Mechanical: list()[].
25 wrong-import-order Stdlib before third-party — mechanical.
18 access-member-before-definition Likely the same lazy-set pattern as configurable.py.
15 undefined-variable Worth reviewing individually — could be real bugs or inference failures.
14 missing-class-docstring Mechanical.
13 missing-module-docstring Mechanical.
12 unused-argument Mix of interface callbacks (suppress with _param) and real dead args.
5 inconsistent-return-statements Small, safe fixes.

The 640 no-member violations are the blocker. Most come from garak's plugin system where attributes are set dynamically (e.g. self.generations, self.name, self.tags on probe/generator instances). The cleanest fix is probably extending generated-members in pylintrc with the known dynamic attribute names, or adding the base plugin classes to ignored-classes. Happy to take a pass at this if you can confirm which attribute names are set dynamically by the framework.

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.

@ppradyoth
Copy link
Copy Markdown
Author

Suggested next steps after this draft

I 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 pylint --rcfile=pylintrc --disable=import-error,cyclic-import garak shows:

Scope Before this PR After this PR Delta
Whole repo 1,144 1,068 -76
Files touched by this PR 69 0 -69

The biggest remaining bucket is no-member at 640 violations. Most of those look like false positives from garak's dynamic plugin/config loading, so I would avoid scattering hundreds of inline suppressions. Better follow-up options are:

  1. Extend generated-members with known dynamic attribute names set by the framework.
  2. Add narrowly scoped ignored-classes where a class is intentionally dynamic and static inference is not useful.
  3. Declare common dynamic attributes on shared base classes where doing so improves readability and type clarity.
  4. Reserve inline # pylint: disable=... comments for exceptional cases that are local and intentional.

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 jmartin-tech changed the title fix(lint): tune pylintrc and fix violations across core modules (closes #1792) fix(lint): tune pylintrc and fix violations across core modules May 27, 2026
@ppradyoth ppradyoth marked this pull request as ready for review May 27, 2026 21:18
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.

Linting CI fails on main due to pre-existing pylint violations

1 participant