fortitude
A Fortran linter, written in Rust and installable with Python.
Science Score: 44.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
✓CITATION.cff file
Found CITATION.cff file -
✓codemeta.json file
Found codemeta.json file -
✓.zenodo.json file
Found .zenodo.json file -
○DOI references
-
○Academic publication links
-
○Academic email domains
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (15.9%) to scientific vocabulary
Keywords
Repository
A Fortran linter, written in Rust and installable with Python.
Basic Info
- Host: GitHub
- Owner: PlasmaFAIR
- License: mit
- Language: Rust
- Default Branch: main
- Homepage: https://fortitude.readthedocs.io/en/stable/
- Size: 1.91 MB
Statistics
- Stars: 141
- Watchers: 3
- Forks: 14
- Open Issues: 99
- Releases: 0
Topics
Metadata Files
README.dev.md
Fortitude Development
Building and running from source
To build Fortitude from source, you must first have a working Rust environment (see rustup). An executable may then be built with the following command called from the project root directory:
bash
cargo build
This will build an executable in debug mode at ./target/debug/fortitude. To
test the release version:
bash
cargo build --release
This will instead build an executable at ./target/release/fortitude.
The project can also be run without prior building using the command:
bash
cargo run [--release]
For example, to test Fortitude over a local project:
bash
cargo run [--release] check /path/to/my/project
Installation from source
Normally during development it is preferable to use one of the above methods to
build and run Fortitude, but there are instances where you may wish to test
installing the project from source. The project may installed from the project
root directory using either pip:
```bash
Generate virtual environment (recommended!)
python -m venv .venv
Or better yet, for uv users:
uv venv
Activate virtual environment
source .venv/bin/activate
Install and include linting/formatting utilities
pip install .[lint]
Or for uv users...
uv pip install .[lint] ```
Or using cargo:
bash
cargo install --path fortitude
Testing
Unit tests can be run by calling:
bash
cargo test --workspace
You'll also need Insta to update snapshot tests:
shell
cargo install cargo-insta
Linting and Formatting
When contributing, please use cargo clippy for linting and cargo fmt for formatting.
If you edit any Python code, please also use ruff check and ruff format. To avoid
accidentally pushing unlinted/unformatted code to GitHub, we recommend using
pre-commit with the provided config file:
```bash pip install pre-commit; pre-commit install
Or, to avoid installing something to your environment...
pipx run pre-commit install
Or, even better yet for those using uv...
uvx pre-commit install ```
Adding Rules
We're always open to new rule suggestions, and would be very grateful for any assistance in implementing them. Before raising an issue to suggest a new rule, please check to see if it has already been suggested.
There are several steps required to add a new rule to Fortitude:
- Decide on a name and category following our naming rules.
- Create a new file
fortitude/src/rules/category/rule_name.rs, wherecategoryis your chosen rule category andrule_nameis its name. If there is already a file for a similar rule, you may also choose to add your rule there. - In that file, define a
Violationstruct. This defines the diagnostic messages raised when your rule is violated. - Implement one of
TextRule,AstRuleorPathRulefor yourViolation. These are, respectively, rules that check a file line-by-line, rules that analyse the AST, and rules that analyse the path to a Fortran file directly.- Most rules are
AstRules, which usetree_sitterto analyse the code. If you want to see howtree_sitterparses a given file, we recommended installingtree_sitter, cloningtree_sitter_fortran, and then running the following from thetree_sitter_fortranroot directory:bash tree-sitter build tree-sitter parse /path/to/fortran/file.f90
- Most rules are
- Map the
Violationstruct to a rule code infortitude/src/rules/mod.rs.code_to_ruleis never called directly, but the match statement within is analysed by the macrofortitude_macros::map_codesto define aRuleenum and many associated utilities.- The first two digits for a rule code normally define a subcategory, while the
last digit denotes the specific rule within that subcategory. The last digit
should not be zero. For example,
T04xdefines rules related to the use of assumed-size arrays and character strings. This isn't stringently enforced, but you may be asked to renumber the rule if other developers think it would better fit somewhere else. - New rules should be in
RuleGroup::Preview.
- Add a test for your rule. Try to consider edge cases and any scenarios where false positives could occur.
- Update the generated documentation using
cargo dev generate-all.
You can automatically add a lot of this boilerplate by running scripts/add_rule.py:
bash
python3 scripts/add_rule.py --name MyNewRule --prefix C --code 123 \
--category correctness
This runs steps 2-6 above for an AST rule. You can also use this for
other kinds of rules, you'll just need to manually change the impl
AstRule block to the correct one in the new rule file, and the new
line added in rules/mod.rs.
It can be very helpful to look at the AST for a sample file to know
what to look for when writing your rule: run cargo dev print-ast to
see a pretty-printed AST. You can add --cst to see a "concrete
syntax tree" that includes unnamed nodes.
For some rules, it may be possible to automatically apply a fix for the user,
though it isn't essential to include a fix when adding a new rule. These are
typically applied using
Fix
and
Edit
from Ruff. A fix may be one of:
- 'Safe': Applying the fix is guaranteed to not change the behaviour of the user's program. This will normally only apply to stylistic changes.
- 'Unsafe': Applying the fix may change the behaviour of the user's program in some edge cases.
- 'Display only': Fortitude can guess at a solution, but makes no guarantees to its correctness or safety.
If you help writing rules, we recommend checking the implementation of existing rules to see if anything similar already exists. You can also raise a draft pull request to ask for assistance from other developers.
Naming and Categorising Rules
Similarly to
Ruff, the name
of a rule should describe the pattern the rule is intended to fix. Words such as
'forbid' should be omitted. For example, the name for the rule that warns of
overly long lines is LineTooLong, and not something like AvoidLineTooLong or
KeepLinesShort.
Rules should also be categorised appropriately. For example, if a rule is
intended to discourage the use of outdated features, it may go under
Obsolescent, or perhaps a more specific category such as Modules or
Typing. If the rule only affects code readability, it should go under Style.
The boundaries between categories are not always clear, so the exact name and category of a rule is often determined following a discussion after a pull request has been raised.
Rule Testing: Fixtures and Snapshots
To test rules, Fortitude uses snapshots of Fortitude's output for a given file (fixture). Generally, there
will be one file per rule (e.g., E402.f90), and each file will contain all necessary examples of
both violations and non-violations. cargo insta review will generate a snapshot file containing
Fortitude's output for each fixture, which you can then commit alongside your changes.
Once you've completed the code for the rule itself, you can define tests with the following steps:
Add a Fortran file to
crates/fortitude_linter/resources/test/fixtures/[category]that contains the code you want to test. The file name should match the rule name (e.g.,E402.f90), and it should include examples of both violations and non-violations.Run Fortitude locally against your file and verify the output is as expected. Once you're satisfied with the output (you see the violations you expect, and no others), proceed to the next step. For example, if you're adding a new rule named
E402, you would run:shell cargo run -- check crates/fortitude_linter/resources/test/fixtures/typing/E402.f90 --select E402Note: Only a subset of rules are enabled by default. When testing a new rule, ensure that you activate it by adding
--select ${rule_code}to the command, and if the rule is in thePreviewcategory, add--previewas well.Add the test to the relevant
crates/fortitude_linter/src/rules/[category]/mod.rsfile. If you're contributing a rule to a pre-existing set, you should be able to find a similar example to pattern-match against. If you're adding a new category, you'll need to create a newmod.rsfile (see, e.g.,crates/fortitude_linter/src/rules/typing/mod.rs)Run
cargo test --workspace. Your test will fail, but you'll be prompted to follow-up withcargo insta review. Runcargo insta review, review and accept the generated snapshot, then commit the snapshot file alongside the rest of your changes.Run
cargo test --workspaceagain to ensure that your test passes.
Building Docs
The documentation can be built locally using:
bash
pip install -r requirements.docs.txt
cargo dev generate-all
mkdocs serve
Making New Releases
To make a new release, the following steps must be completed in order:
Move rules out of preview mode/into deprecated mode (if applicable).
Make sure the generated docs are up-to-date:
cargo dev generate-allInstall
uv:curl -LsSf https://astral.sh/uv/install.sh | shInstall
ghand login withgh auth loginRun
./scripts/release.sh; this command will:
- Generate a temporary virtual environment with `rooster`
- Generate a changelog entry in `CHANGELOG.md`
- Update versions in `pyproject.toml` and `Cargo.toml`
- Update references to versions in the `README.md` and documentation
- Display contributors for the release
roostercurrently doesn't updateCITATION.cff, so this needs to be done manually for nowSome sections of the docs also directly reference the version number and need to be manually updated. Use
grep <current_version> docs -rto find them.The changelog should then be editorialised for consistency
- Often labels will be missing from pull requests they will need
to be manually organized into the proper section
- Changes should be edited to be user-facing descriptions, avoiding internal details
Highlight any breaking changes in
BREAKING_CHANGES.mdRun
cargo check. This should update the lock file with new versions.Create a pull request with the changelog and version updates
Merge the PR
Update the tag on
mainRun the release workflow with:
- The new version number
The release workflow will do the following:
- Build all the assets. If this fails (even though we tested in step 4), we haven't tagged or uploaded anything, you can restart after pushing a fix. If you just need to rerun the build, make sure you're re-running all the failed jobs and not just a single failed job.
- Upload to PyPI.
- Create and push the Git tag (as extracted from
pyproject.toml). We create the Git tag only after building the wheels and uploading to PyPI, since we can't delete or modify the tag (#4468). - Attach artifacts to draft GitHub release
Verify the GitHub release:
- The Changelog should match the content of
CHANGELOG.md - Append the contributors from the
scripts/release.shscript
- The Changelog should match the content of
Pushing to crates.io is currently not possible as some of our dependencies point
to GitHub repositories. We'll be able to restart using crates.io if Ruff starts
publishing there.
Owner
- Name: PlasmaFAIR
- Login: PlasmaFAIR
- Kind: organization
- Repositories: 3
- Profile: https://github.com/PlasmaFAIR
Citation (CITATION.cff)
cff-version: 1.2.0 message: "If you use this software, please cite it as below." authors: - family-names: "Pattinson" given-names: "Liam" orcid: "https://orcid.org/0000-0001-8604-6904" - family-names: Hill given-names: Peter orcid: "https://orcid.org/0000-0003-3092-1858" title: "fortitude" version: 0.7.5 date-released: 2025-08-18 url: "https://github.com/PlasmaFAIR/fortitude"
Issues and Pull Requests
Last synced: 6 months ago
All Time
- Total issues: 103
- Total pull requests: 117
- Average time to close issues: 27 days
- Average time to close pull requests: 4 days
- Total issue authors: 25
- Total pull request authors: 13
- Average comments per issue: 0.91
- Average comments per pull request: 1.2
- Merged pull requests: 85
- Bot issues: 0
- Bot pull requests: 1
Past Year
- Issues: 103
- Pull requests: 117
- Average time to close issues: 27 days
- Average time to close pull requests: 4 days
- Issue authors: 25
- Pull request authors: 13
- Average comments per issue: 0.91
- Average comments per pull request: 1.2
- Merged pull requests: 85
- Bot issues: 0
- Bot pull requests: 1
Top Authors
Issue Authors
- LiamPattinson (54)
- ZedThree (54)
- Beliavsky (42)
- imciner2 (11)
- melven (3)
- MatthAlex (3)
- jatkinson1000 (3)
- nbehrnd (3)
- danielhollas (2)
- davidpfister (2)
- pmocz (2)
- rhdtownsend (2)
- kcooley-cvd (1)
- fbrechin (1)
- RJaBi (1)
Pull Request Authors
- ZedThree (107)
- LiamPattinson (94)
- imciner2 (10)
- jatkinson1000 (4)
- connoraird (4)
- wassup05 (2)
- Beliavsky (2)
- stigh (2)
- hansec (1)
- pmocz (1)
- danielhollas (1)
- dependabot[bot] (1)
- TomMelt (1)
- zbeekman (1)
Top Labels
Issue Labels
Pull Request Labels
Packages
- Total packages: 2
-
Total downloads:
- cargo 2,813 total
- pypi 24,245 last-month
-
Total dependent packages: 0
(may contain duplicates) -
Total dependent repositories: 0
(may contain duplicates) - Total versions: 18
- Total maintainers: 3
pypi.org: fortitude-lint
A Fortran linter, written in Rust and installable with Python
- Documentation: https://fortitude-lint.readthedocs.io/
- License: MIT License
-
Latest release: 0.7.5
published 6 months ago
Rankings
Maintainers (2)
crates.io: fortitude
A Fortran linter, written in Rust and installable with Python
- Documentation: https://docs.rs/fortitude/
- License: MIT
-
Latest release: 0.3.0
published over 1 year ago
Rankings
Maintainers (1)
Dependencies
- actions/checkout v4 composite
- actions/checkout v4 composite
- actions/checkout v4 composite