An uncompromising Fortran formatter, inspired by Black.
"So it goes." — Kurt Vonnegut, Slaughterhouse-Five
Sable enforces one consistent style for modern free-form Fortran, so you can focus on code instead of formatting. It also supports code checks beyond formatting to identify code issues.
pip install sable-fortran# Format in place (default command)
sable src/
# Equivalent explicit form
sable format src/
# Check formatting only (no writes)
sable format --check src/
# Preview formatting diff
sable format --diff src/
# Safer migration pass (layout-focused)
sable format --safe src/Recommended CI formatting gate:
sable format --check src/format rewrites source into Sable's canonical style. This includes:
- Relational operator normalization (
.EQ.->==, etc.) - END keyword normalization (
endif->end if, configurable) - Declaration normalization (
integer x->integer :: x) - Deterministic spacing, indentation, wrapping, and trailing newline handling
Example:
! Before
IF(A .EQ. B)THEN
CALL compute(argument_alpha,argument_beta,argument_gamma)
ENDIF
! After
if (A == B) then
call compute(argument_alpha, &
argument_beta, &
argument_gamma)
end ifcheck reports rule diagnostics and can apply rule fixes.
# Run all rules (style + lint)
sable check src/
# Focus on policy/lint only
sable check --rule-set lint src/
# Formatter-adjacent style rules only
sable check --rule-set style src/
# Apply safe fixes, then re-check
sable check --fix src/
# Allow unsafe fixes too
sable check --fix --unsafe-fixes src/Rule-set notes:
--rule-set all(default): style + lint--selecttakes precedence over--rule-set--fixapplies safe fixes--unsafe-fixesenables unsafe fixes (only with--fix)
Current lint rules:
SBL101: Program/module is missingimplicit noneSBL102: Procedure is missingimplicit noneSBL103: Dummy argument is missingintent(in|out|inout)
Inline:
if (a .eq. b) then ! sable: ignore SBL001
end ifFile-wide:
! sable: ignore-file SBL001,SBL004Formatter options are CLI flags:
sable format --line-length 88 src/| Option | Default | Values | Applies to |
|---|---|---|---|
--line-length |
100 |
integer | format, check |
--indent-width |
3 |
integer | format, check |
--keyword-case |
lower |
lower, upper |
format, check |
--end-keyword-form |
spaced |
spaced, compact |
format, check |
--no-normalize-operators |
off | flag | format, check |
rule_set / --rule-set |
all |
style, lint, all |
check |
select / --select |
[] |
rule codes | check |
ignore / --ignore |
[] |
rule codes | check |
output_format / --output-format |
text |
text, json, sarif, gitlab-codequality |
check |
baseline / --baseline |
unset | path | check |
fix / --fix |
false |
boolean | check |
unsafe_fixes / --unsafe-fixes |
false |
boolean | check |
generate_baseline / --generate-baseline |
false |
boolean | check |
Example pyproject.toml:
[tool.sable.check]
rule_set = "all" # style | lint | all
select = []
ignore = []
output_format = "text" # text | json | sarif | gitlab-codequality
baseline = ".sable-baseline.json"
fix = false
unsafe_fixes = false
generate_baseline = falseFor check, CLI flags override pyproject.toml defaults.
[](https://github.com/eirik-kjonstad/sable)MIT