Skip to content

Repository files navigation

Sable logo
Code style: Sable PyPI version Python 3.10 through 3.15-dev License: MIT

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.

Installation

pip install sable-fortran

Quick Start

# 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/

Formatting

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 if

Checking

check 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
  • --select takes precedence over --rule-set
  • --fix applies safe fixes
  • --unsafe-fixes enables unsafe fixes (only with --fix)

Current lint rules:

  • SBL101: Program/module is missing implicit none
  • SBL102: Procedure is missing implicit none
  • SBL103: Dummy argument is missing intent(in|out|inout)

Suppressions

Inline:

if (a .eq. b) then ! sable: ignore SBL001
end if

File-wide:

! sable: ignore-file SBL001,SBL004

Configuration

Formatter 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 = false

For check, CLI flags override pyproject.toml defaults.

Badge

[![Code style: Sable](https://raw.githubusercontent.com/eirik-kjonstad/sable/main/assets/sable-badge.svg)](https://github.com/eirik-kjonstad/sable)

License

MIT

About

An uncompromising Fortran formatter

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages