You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Investigate adopting ruff in ITK's pre-commit configuration, for two related reasons:
A shebang gate — ruff's flake8-executable (EXE) rules would end the recurring manual shebang sweeps.
Tool consolidation — ruff can subsume black and pyupgrade, ITK's only two Python formatting/lint hooks.
This is a request to investigate and discuss, not a request to merge something. The second half in particular has a real cost and a governance dimension.
Why now: the shebang sweeps
check-shebang-scripts-are-executable verifies that a shebang and the executable bit agree. It does not check that the interpreter named actually resolves, and that gap has cost several PRs:
The same, plus #!python and #!/bin/env python (/bin/env does not exist)
Every one of those was found by hand or by an external reviewer. EXE003 flags a shebang that does not name python; EXE001/EXE002 cover the mode pairing on POSIX and Windows. Together they turn a periodic manual audit into a hook.
Current state of Python shebangs after #6842 / #6844
Both branches converge on #!/usr/bin/env python3. Before those PRs:
Shebang
main
release-5.4
#!/usr/bin/env python3
22
1
#!/usr/bin/env python
17
20
#!/usr/bin/python
4
4
#!python
0
1
#!/bin/env python
0
1
The drift was one-directional: main had been partially modernized while release-5.4 had not, and nothing detected the difference.
Why now: consolidation
ITK's Python hooks today are black (24.2.0) and pyupgrade (v3.21.2), across 180 first-party .py files. Ruff implements both: ruff format for the former, UP rules for the latter.
MONAI has been carrying out exactly this consolidation and has already folded in pyupgrade (Project-MONAI/MONAI#8606), yesqa (#8692), flake8 (#8694) and pycln (#9061). The remaining step — replacing black and isort — is under discussion in Project-MONAI/MONAI#9066, with parity and CI-consistency concerns in #8683.
ITK is a smaller case than MONAI: no isort, no flake8, 180 files rather than 1353. That makes it a cheaper experiment, and it means the decision here is genuinely optional rather than a maintenance necessity.
Caveats worth stating up front
ruff format is not byte-identical to black. It is intentionally close but documents known differences. A migration would produce a one-time reformatting diff that has to be reviewed, or accepted as mechanical.
Adding ruff for EXE alone still adds a dependency. If the EXE rules are the only motivation, the honest comparison is against a ten-line local hook that greps first lines — cheaper, but one more bespoke script to own.
Wrapping-generated Python is not in scope and would need exclusion, as black already handles today.
The two goals are separable. An EXE-only ruff configuration is a small, low-risk change; replacing black is a larger conversation. They should probably not be bundled into one PR.
Proposal
Investigate adopting
ruffin ITK's pre-commit configuration, for two related reasons:flake8-executable(EXE) rules would end the recurring manual shebang sweeps.blackandpyupgrade, ITK's only two Python formatting/lint hooks.This is a request to investigate and discuss, not a request to merge something. The second half in particular has a real cost and a governance dimension.
Why now: the shebang sweeps
check-shebang-scripts-are-executableverifies that a shebang and the executable bit agree. It does not check that the interpreter named actually resolves, and that gap has cost several PRs:VCL_ModernizeNaming.pyexecutable to satisfy the hook#!pythonstill cannot execute (mode 755,execve→ ENOENT)env python→env python3; 2 ×/usr/bin/python→env python3#!pythonand#!/bin/env python(/bin/envdoes not exist)Every one of those was found by hand or by an external reviewer.
EXE003flags a shebang that does not namepython;EXE001/EXE002cover the mode pairing on POSIX and Windows. Together they turn a periodic manual audit into a hook.Current state of Python shebangs after #6842 / #6844
Both branches converge on
#!/usr/bin/env python3. Before those PRs:#!/usr/bin/env python3#!/usr/bin/env python#!/usr/bin/python#!python#!/bin/env pythonThe drift was one-directional:
mainhad been partially modernized whilerelease-5.4had not, and nothing detected the difference.Why now: consolidation
ITK's Python hooks today are
black(24.2.0) andpyupgrade(v3.21.2), across 180 first-party.pyfiles. Ruff implements both:ruff formatfor the former,UPrules for the latter.MONAI has been carrying out exactly this consolidation and has already folded in
pyupgrade(Project-MONAI/MONAI#8606),yesqa(#8692),flake8(#8694) andpycln(#9061). The remaining step — replacingblackandisort— is under discussion in Project-MONAI/MONAI#9066, with parity and CI-consistency concerns in #8683.ITK is a smaller case than MONAI: no
isort, noflake8, 180 files rather than 1353. That makes it a cheaper experiment, and it means the decision here is genuinely optional rather than a maintenance necessity.Caveats worth stating up front
ruff formatis not byte-identical toblack. It is intentionally close but documents known differences. A migration would produce a one-time reformatting diff that has to be reviewed, or accepted as mechanical.EXEalone still adds a dependency. If theEXErules are the only motivation, the honest comparison is against a ten-line local hook that greps first lines — cheaper, but one more bespoke script to own.blackalready handles today.EXE-only ruff configuration is a small, low-risk change; replacingblackis a larger conversation. They should probably not be bundled into one PR.Suggested investigation
EXErules enabled and measure the finding count on both branches — likely zero after STYLE: Standardize Python shebangs on env python3 #6842/STYLE: Standardize Python shebangs on env python3 #6844, which would confirm the gate holds the line rather than creating work.ruff format --diffagainst ablack-clean tree and report the size of the delta.ruffversusblack+pyupgradeon the 180-file set.