Skip to content

Replace pylint + autopep8 with ruff#1300

Draft
sbryngelson wants to merge 6 commits intoMFlowCode:masterfrom
sbryngelson:ruff
Draft

Replace pylint + autopep8 with ruff#1300
sbryngelson wants to merge 6 commits intoMFlowCode:masterfrom
sbryngelson:ruff

Conversation

@sbryngelson
Copy link
Member

Summary

Resolves #1281 — replaces pylint + autopep8 with ruff for all Python linting and formatting. Ruff is ~200-500x faster (under 0.2s vs 30-90s for the old pylint + autopep8 pipeline across 226 Python files).

What changed

  • Formatting: autopep8 → ruff format. Per-file find | xargs replaced with direct directory-level ruff format calls.
  • Linting: 3 separate pylint invocations → ruff check with rule sets E (pycodestyle), F (pyflakes), W (warnings), I (isort), PL (pylint-equivalent).
  • Auto-fix: ruff check --fix runs automatically in both ./mfc.sh format and ./mfc.sh lint to fix safe issues (import sorting, unused f-prefixes, etc.) before checking.
  • Config: New ruff.toml at repo root (centralized, replaces scattered pylint/autopep8 config). Only 6 rules ignored — all high-count structural/style rules (too-many-branches, magic-value-comparison, etc.).
  • Inline comments: Removed all ~229 # pylint: disable= comments. Added ~12 targeted # noqa: comments for intentional global statements.
  • Code fixes (not just suppression):
    • E731: lambda → named function
    • E741: ambiguous variable name lline
    • E721: !=is not for type comparison
    • PLW1641: added __hash__ to MFCConfig dataclass
    • PLR1722: exit()sys.exit()
    • F541: removed extraneous f prefix from 40 f-strings without placeholders
    • E501: wrapped 2 long lines
    • E702: split semicolon-separated statements
    • PLW2901: renamed 6 overwritten loop variables
  • Dependencies: Replaced pylint and autopep8 with ruff in pyproject.toml.
  • Bug fix: lint.sh used $(pwd)/toolchain/ which resolved symlinks and broke ruff config discovery; switched to relative paths.

Config details (ruff.toml)

line-length = 200
target-version = "py39"
select = ["E", "F", "W", "I", "PL"]
ignore = ["PLR0911", "PLR0912", "PLR0913", "PLR0915", "PLR2004", "PLC0415"]

Per-file ignores for examples/ and benchmarks/ (permissive for user-facing case files).

Test plan

  • ./mfc.sh lint passes (ruff check clean + 165 unit tests)
  • ./mfc.sh format runs without errors
  • ./mfc.sh precheck passes all 5 checks (formatting, spelling, toolchain lint, source lint, doc references)
  • CI passes on all compiler configurations

🤖 Generated with Claude Code

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@sbryngelson sbryngelson marked this pull request as ready for review March 11, 2026 19:09
Copilot AI review requested due to automatic review settings March 11, 2026 19:09
@MFlowCode MFlowCode deleted a comment from cursor bot Mar 11, 2026
@qodo-code-review

This comment has been minimized.

@qodo-code-review

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the Python toolchain’s linting/formatting workflow from pylint/autopep8 to ruff, and then applies ruff-driven cleanup (imports, formatting, some small refactors) across the toolchain plus example/benchmark case files.

Changes:

  • Replace pylint + autopep8 usage with ruff (new ruff.toml, updated bootstrap scripts, updated docs/CLI help text).
  • Apply broad import ordering / formatting updates across toolchain modules, viz utilities, params tooling, and docs generators.
  • Minor functional tweaks (e.g., sys.exit instead of exit, MFCConfig.__hash__ to allow hashing).

Reviewed changes

Copilot reviewed 156 out of 158 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
toolchain/pyproject.toml Replace pylint/autopep8 dependencies with ruff.
toolchain/mfc/viz/viz.py Remove pylint pragmas; reorder imports.
toolchain/mfc/viz/tui.py Remove pylint pragmas; minor refactors/formatting.
toolchain/mfc/viz/test_viz.py Remove pylint pragmas; import/blank-line normalization.
toolchain/mfc/viz/silo_reader.py Replace pylint pragmas with ruff noqa; formatting.
toolchain/mfc/viz/renderer.py Replace pylint pragmas with ruff noqa; reorder imports.
toolchain/mfc/viz/reader.py Replace pylint pragmas with ruff noqa; formatting.
toolchain/mfc/viz/interactive.py Remove pylint pragmas; reorder imports; formatting.
toolchain/mfc/viz/_step_cache.py Replace pylint pragmas; formatting.
toolchain/mfc/validate.py Use sys.exit; reorder imports/strings.
toolchain/mfc/user_guide.py Reformat/normalize strings; minor readability tweaks.
toolchain/mfc/state.py Import normalization; add MFCConfig.__hash__; ruff-style noqa.
toolchain/mfc/sched.py Reformat; tighten conditionals; import normalization.
toolchain/mfc/run/run.py Import normalization; string normalization; formatting.
toolchain/mfc/run/queues.py Import formatting; string normalization.
toolchain/mfc/run/input.py Import normalization; formatting; small cleanup in clean().
toolchain/mfc/run/case_dicts.py Remove pylint pragmas; regex string normalization.
toolchain/mfc/printer.py Import formatting.
toolchain/mfc/params/validate.py Ensure registry population via definitions import; reorder imports.
toolchain/mfc/params/suggest.py Import ordering/formatting.
toolchain/mfc/params/schema.py Import ordering; remove pylint pragma.
toolchain/mfc/params/registry.py Import ordering; remove pylint pragma; lazy import cleanup.
toolchain/mfc/params/namelist_parser.py Remove stray blank line.
toolchain/mfc/params/generators/json_schema_gen.py Ensure definitions import for registry population; reorder imports.
toolchain/mfc/params/generators/docs_gen.py Ensure definitions import; reorder imports; remove pylint pragmas.
toolchain/mfc/params/generators/init.py Import ordering.
toolchain/mfc/params/descriptions.py Remove pylint pragmas; formatting.
toolchain/mfc/params/definitions.py Import ordering; remove pylint pragmas.
toolchain/mfc/params/ast_analyzer.py Import ordering; remove broad-except pylint pragmas.
toolchain/mfc/params/init.py Ensure definitions import occurs early; reorder exports.
toolchain/mfc/params_tests/test_validate.py Import ordering.
toolchain/mfc/params_tests/test_registry.py Remove pylint pragma; formatting.
toolchain/mfc/params_tests/test_integration.py Remove pylint pragma; formatting.
toolchain/mfc/params_tests/test_definitions.py Import ordering.
toolchain/mfc/params_tests/snapshot.py Import ordering.
toolchain/mfc/params_tests/runner.py Import ordering; collapse long imports; minor output tweak.
toolchain/mfc/params_tests/negative_tests.py Import ordering.
toolchain/mfc/params_tests/mutation_tests.py Import ordering; minor output tweak.
toolchain/mfc/params_tests/inventory.py Import ordering.
toolchain/mfc/params_tests/coverage.py Import ordering.
toolchain/mfc/params_cmd.py Remove pylint pragmas; import grouping; formatting.
toolchain/mfc/packer/tol.py Import ordering; signature formatting.
toolchain/mfc/packer/packer.py Import ordering.
toolchain/mfc/packer/pack.py Import ordering.
toolchain/mfc/packer/errors.py Import formatting.
toolchain/mfc/lock.py Replace pylint pragmas with ruff noqa; formatting.
toolchain/mfc/init.py String normalization; import ordering; formatting.
toolchain/mfc/ide.py Remove pylint pragmas; string normalization; formatting.
toolchain/mfc/generate.py Use sys.exit; import ordering; formatting.
toolchain/mfc/gen_physics_docs.py Replace pylint pragmas with ruff noqa; formatting.
toolchain/mfc/gen_case_constraints_docs.py Remove pylint pragmas; refactor long literals; formatting.
toolchain/mfc/count.py Import ordering; minor variable renames; formatting.
toolchain/mfc/completion.py Import ordering; minor output formatting.
toolchain/mfc/common.py Import ordering; replace pylint global pragmas with ruff noqa; formatting.
toolchain/mfc/cli/test_cli.py Remove pylint pragma; add tests for MFCConfig.__hash__.
toolchain/mfc/cli/schema.py Remove pylint pragmas; formatting/spacing normalization.
toolchain/mfc/cli/docs_gen.py Import ordering; collapse helper signature formatting.
toolchain/mfc/cli/commands.py Update lint command wording (pylint→ruff); formatting/indent normalization.
toolchain/mfc/cli/argparse_gen.py Remove pylint pragmas; small is not str fix; formatting.
toolchain/mfc/cli/init.py Import ordering.
toolchain/mfc/clean.py Import ordering.
toolchain/mfc/case_utils.py String normalization; formatting.
toolchain/mfc/bench.py Import ordering; minor print formatting; small refactor.
toolchain/mfc/args.py Import ordering; string normalization; formatting.
toolchain/main.py Remove pylint pragmas; import ordering; formatting; simplify some blocks.
toolchain/indenter.py Import ordering; string normalization; formatting.
toolchain/bootstrap/lint.sh Switch linting from pylint to ruff; add ruff auto-fix step; simplify test invocation.
toolchain/bootstrap/format.sh Switch Python formatting to ruff check --fix-only + ruff format; remove autopep8 pipeline.
toolchain/bootstrap/format_python.sh Remove autopep8-based formatter script.
ruff.toml Add ruff configuration (rules, ignores, per-file ignores, isort config).
examples/scaling/export.py Import ordering.
examples/scaling/benchmark.py Import ordering.
examples/scaling/analyze.py Import ordering.
examples/nD_perfect_reactor/case.py Import ordering; minor f-string spacing.
examples/nD_perfect_reactor/analyze.py Import ordering; string normalization; formatting.
examples/3D_turb_mixing/case.py Import ordering.
examples/3D_TaylorGreenVortex/case.py Import ordering.
examples/3D_TaylorGreenVortex_analytical/case.py Import ordering.
examples/3D_shockdroplet/case.py Import ordering.
examples/3D_shockdroplet_muscl/case.py Import ordering.
examples/3D_recovering_sphere/case.py Import ordering.
examples/3D_rayleigh_taylor/case.py Import ordering.
examples/3D_rayleigh_taylor_muscl/case.py Import ordering.
examples/3D_phasechange_bubble/case.py Import ordering.
examples/3D_lagrange_shbubcollapse/case.py Import ordering.
examples/3D_lagrange_bubblescreen/case.py Import ordering.
examples/3D_IGR_TaylorGreenVortex/case.py Import ordering.
examples/3D_IGR_TaylorGreenVortex_nvidia/case.py Import ordering.
examples/3D_IGR_jet/case.py Import ordering.
examples/3D_IGR_33jet/case.py Import ordering.
examples/2D_zero_circ_vortex/case.py Import ordering.
examples/2D_zero_circ_vortex_analytical/case.py Import ordering.
examples/2D_whale_bubble_annulus/case.py Import ordering.
examples/2D_viscous/case.py Import ordering.
examples/2D_triple_point/case.py Import ordering.
examples/2D_TaylorGreenVortex/case.py Import ordering.
examples/2D_shocktube_phasechange/case.py Import ordering.
examples/2D_shockdroplet/case.py Import ordering.
examples/2D_shockdroplet_muscl/case.py Import ordering.
examples/2D_shockbubble/case.py Import ordering.
examples/2D_rayleigh_taylor/case.py Import ordering.
examples/2D_phasechange_bubble/case.py Import ordering.
examples/2D_mixing_artificial_Ma/case.py Import ordering.
examples/2D_lungwave/case.py Import ordering.
examples/2D_lungwave_horizontal/case.py Import ordering.
examples/2D_laplace_pressure_jump/case.py Import ordering.
examples/2D_lagrange_bubblescreen/case.py Import ordering.
examples/2D_jet/case.py Import ordering.
examples/2D_isentropicvortex/case.py Import ordering; remove unnecessary f-string prefixes.
examples/2D_isentropicvortex_analytical/case.py Import ordering; remove unnecessary f-string prefixes.
examples/2D_IGR_triple_point/case.py Import ordering.
examples/2D_IGR_2fluid/case.py Import ordering.
examples/2D_GreshoVortex/case.py Import ordering.
examples/2D_axisym_shockwatercavity/case.py Import ordering.
examples/2D_axisym_shockbubble/case.py Import ordering.
examples/2D_acoustic_pulse/case.py Import ordering.
examples/2D_acoustic_pulse_analytical/case.py Import ordering.
examples/2D_5wave_quasi1D/case.py Import ordering.
examples/1D_titarevtorro/case.py Import ordering.
examples/1D_titarevtorro_analytical/case.py Import ordering.
examples/1D_sodshocktube/case.py Import ordering.
examples/1D_sodshocktube_muscl/case.py Import ordering.
examples/1D_sodHypo/case.py Import ordering.
examples/1D_shuosher_wenoz5/case.py Import ordering.
examples/1D_shuosher_wenom5/case.py Import ordering.
examples/1D_shuosher_wenojs5/case.py Import ordering.
examples/1D_shuosher_teno7/case.py Import ordering.
examples/1D_shuosher_teno5/case.py Import ordering.
examples/1D_shuosher_old/case.py Import ordering.
examples/1D_shuosher_analytical/case.py Import ordering.
examples/1D_reactive_shocktube/case.py Import ordering; minor f-string spacing.
examples/1D_qbmm/case.py Import ordering; remove stray comment marker.
examples/1D_poly_bubscreen/case.py Import ordering; remove stray comment marker.
examples/1D_multispecies_diffusion/case.py Import ordering; minor f-string spacing.
examples/1D_laxshocktube/case.py Import ordering.
examples/1D_inert_shocktube/case.py Import ordering; minor f-string spacing.
examples/1D_impact/case.py Import ordering.
examples/1D_hypo_2materials/case.py Import ordering.
examples/1D_exp_tube_phasechange/case.py Import ordering.
examples/1D_exp_bubscreen/case.py Import ordering.
examples/1D_convergence/case.py Import ordering; simplify constant strings.
examples/1D_bubblescreen/case.py Import ordering; remove stray comment marker.
examples/0D_bubblecollapse_adap/case.py Import ordering.
docs/documentation/contributing.md Update lint gate description for ruff-based linting.
CLAUDE.md Update developer instructions: ./mfc.sh lint now uses ruff.
benchmarks/viscous_weno5_sgb_acoustic/case.py Import ordering.
benchmarks/igr/case.py Import ordering.
benchmarks/ibm/case.py Import ordering.
benchmarks/hypo_hll/case.py Import ordering.
benchmarks/5eq_rk3_weno3_hllc/case.py Import ordering.

Comment on lines +1 to +3
line-length = 200
target-version = "py39"
exclude = ["_version.py"]

This comment was marked as outdated.

Comment on lines +15 to +17
log "(venv) Auto-fixing safe lint issues with$MAGENTA ruff$COLOR_RESET..."

pylint -d R1722,W0718,C0301,C0116,C0115,C0114,C0410,W0622,W0640,C0103,W1309,C0411,W1514,R0401,W0511,C0321,C3001,R0801,R0911,R0912 "$(pwd)/toolchain/"
ruff check --fix-only toolchain/ examples/*/case.py benchmarks/*/case.py

This comment was marked as outdated.

Comment on lines +1 to +25
line-length = 200
target-version = "py39"
exclude = ["_version.py"]

[lint]
select = ["E", "F", "W", "I", "PL"]
ignore = [
# Complexity thresholds (project style)
"PLR0911", # too-many-return-statements
"PLR0912", # too-many-branches
"PLR0913", # too-many-arguments
"PLR0915", # too-many-statements
"PLR2004", # magic-value-comparison
# Import patterns (project style)
"PLC0415", # import-outside-toplevel
# Global variable reads (module-level singleton pattern)
"PLW0602", # global-variable-not-assigned
]

[lint.per-file-ignores]
"examples/**/*.py" = ["F401", "F403", "F405", "F811", "F821", "E402", "E722", "E741"]
"benchmarks/*/case.py" = ["F401", "F403", "F405", "F811", "F821", "E402", "E741"]

[lint.isort]
known-first-party = ["mfc"]

This comment was marked as outdated.

Comment on lines +16 to +18
# Global variable reads (module-level singleton pattern)
"PLW0602", # global-variable-not-assigned
]

This comment was marked as outdated.

if ! find $SEARCH_PATHS -type f 2>/dev/null | grep -E '\.(py)$' \
| xargs --no-run-if-empty -L 1 -P ${JOBS:-1} $SHELL toolchain/bootstrap/format_python.sh; then
# Format Python files with ruff (auto-fix lint issues, then format)
ruff check --fix-only $SEARCH_PATHS

This comment was marked as outdated.

Comment on lines +56 to +58
# Format Python files with ruff (auto-fix lint issues, then format)
ruff check --fix-only $SEARCH_PATHS
if ! ruff format $SEARCH_PATHS; then

This comment was marked as outdated.

sbryngelson and others added 5 commits March 11, 2026 16:16
- Replace autopep8 with ruff format, pylint with ruff check
- Add ruff.toml config at repo root (E, F, W, I, PL rule sets)
- Enable ruff check --fix in format.sh and lint.sh for safe auto-fixes
- Remove all ~229 inline pylint: disable comments
- Fix code violations: E731 (lambda), E741 (ambiguous var), E721 (type
  comparison), PLW1641 (hash), PLR1722 (sys.exit), F541 (f-string),
  E501 (line length), E702 (semicolons), PLW2901 (loop var overwrite)
- Add ~12 noqa comments for intentional global statements (PLW0603/PLW0602)
- Remove 8 zero-violation rules from ignore list to keep config minimal
- Fix lint.sh symlink path resolution breaking ruff config discovery
- Replace pylint and autopep8 deps with ruff in pyproject.toml

Resolves MFlowCode#1281

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-fix

- Add PLW0602 (global-variable-not-assigned) to ruff.toml ignore list
  instead of scattering noqa comments across ~19 call sites
- Change ruff check --fix to keep stderr visible (> /dev/null || true
  instead of > /dev/null 2>&1 || true) so config/invocation errors
  are not silently swallowed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use dataclasses.fields() instead of dataclasses.asdict() in
  MFCConfig.__hash__ to avoid issues with nested types and sorted()
- Delete format_python.sh which is no longer referenced by anything

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use ruff check --fix-only instead of --fix || true so genuine ruff
  failures propagate while still tolerating unfixable violations
- Update CLAUDE.md: Pylint -> Ruff in lint command description
- Add 4 unit tests for MFCConfig.__hash__ (hash/eq contract, set/dict usage)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap ruff check --fix-only in error checking in format.sh so a
missing or broken ruff installation does not silently succeed.

Add isinstance guard to MFCConfig.__eq__ so comparisons with
non-MFCConfig objects return NotImplemented instead of raising
AttributeError.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

@sbryngelson sbryngelson marked this pull request as draft March 11, 2026 20:51
Kept upstream patch type 13 reclassification (3D->2D) with ruff formatting.
Auto-formatted new upstream example files for ruff import sorting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link

Claude Code Review

Head SHA: 977a213
Files changed: 161 (toolchain + 80+ examples/benchmarks case files + docs)

Summary

  • Replaces pylint + autopep8 with ruff for Python linting and formatting (~200–500× faster, resolves Replace pylint + autopep8 with ruff for Python linting and formatting #1281)
  • Adds ruff.toml at repo root with 6 ignored rules and per-file permissive overrides for examples/ and benchmarks/
  • Removes 229 # pylint: disable= comments; adds 12 targeted # noqa: PLW0603 comments for intentional global statements
  • Fixes real code issues: lambda → named function (E731), ambiguous lline (E741), exit()sys.exit() (PLR1722), and 40 extraneous f-string prefixes (F541)
  • Bulk import-order reordering across all example/benchmark case files (isort)

Findings

1. toolchain/bootstrap/lint.sh — auto-fix step missing error handling

# Current (new code, ~line 15):
ruff check --fix-only toolchain/ examples/*/case.py benchmarks/*/case.py

# Subsequent checks:
ruff check toolchain/

The ruff check --fix-only step has no if ! guard. If it fails (e.g., permission error, parse failure), the script continues silently and the subsequent ruff check may pass or produce confusing output. Compare with format.sh which correctly wraps both calls with if !. Recommend adding:

if ! ruff check --fix-only toolchain/ examples/*/case.py benchmarks/*/case.py; then
    error "Auto-fixing lint issues failed."
    exit 1
fi

2. toolchain/bootstrap/format.sh — unquoted $SEARCH_PATHS variable

# ~line 56–59:
if ! ruff check --fix-only $SEARCH_PATHS; then
...
if ! ruff format $SEARCH_PATHS; then

$SEARCH_PATHS is unquoted; paths with spaces would word-split. This pre-exists autopep8's usage too, but since ruff takes directory arguments directly (not via xargs), this is now more exposed. Low severity on typical HPC paths, but worth quoting consistently.

3. ruff.tomlPLW0602 silently suppressed globally

# ruff.toml, line 17:
"PLW0602",  # global-variable-not-assigned

This suppresses warnings for all global foo declarations where foo is only read (not assigned) in that scope — the module-level singleton pattern cited in the comment. However, globally ignoring this rule means legitimate bugs (unintended use of global on a variable that is never actually reassigned) will go undetected across the entire codebase. Consider scoping this to specific files or adding a comment pointing to the affected modules.

4. toolchain/mfc/case_validator.py — multiline strings collapsed to very long single lines

# New ~line 46:
"explanation": ("MFC uses the transformed stiffened gas parameter. A common mistake is entering the physical gamma (e.g., 1.4 for air) instead of the transformed value 1/(gamma-1) = 2.5."),

# New ~line 57:
"explanation": ("All initial patch pressures must be strictly positive. Partial densities must be non-negative. Volume fractions must be in [0,1]."),

These are well under the line-length = 200 limit so ruff won't flag them, but the previous multi-line style was more readable and documented the physics more clearly. Not a correctness issue — just a readability note.


Minor Observations

  • pyproject.toml dependency update (pylint + autopep8 → ruff) was not shown in the diff excerpt — confirm it's present in the PR.
  • The ruff.toml correctly sets target-version = "py39" matching MFC's documented minimum Python requirement.
  • The per-file ignores for examples/**/*.py (F401, F403, F821, etc.) are appropriate given user-facing case files intentionally use star imports and loose patterns.
  • All code fixes (E731, E741, F541, PLR1722, PLW2901, PLW1641) appear correct and are genuine improvements over suppression comments.

Overall a clean, well-scoped migration. The main actionable item is adding error handling to lint.sh for the auto-fix step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Replace pylint + autopep8 with ruff for Python linting and formatting

2 participants