fp-checker is a Rust-powered checker for Python codebases that reports functions which violate functional-programming-oriented rules. It provides both a CLI and a Python API, and can output results in text, JSON, or SARIF. In addition to built-in rules, you can add custom rules through configuration only.
- What it does: checks Python functions for side effects, hidden mutation, non-determinism, deprecated APIs, and other patterns that make code less functional
- Interfaces: CLI and Python API
- Output formats:
text,json,sarif - Extensibility: built-in rules plus config-driven custom rules
- Package:
pip install fp-checker
- Feature overview: docs/features.md
- Rule reference: docs/rules.md
- CLI / Python API usage: docs/usage.md
- Configuration: docs/configuration.md
- Development setup: docs/development.md
- CI / security: docs/quality-and-security.md
If fp-checker helps your work, you can support ongoing maintenance on GitHub Sponsors:
Python コードを解析し、関数型プログラミングのルールに反した関数を検査する Rust 製ツールです。CLI と Python API の両方を提供し、結果は text / JSON / SARIF の各形式で出力できます。組み込みルールに加えて、設定ファイルだけで custom rule を追加できます。
- 機能概要: docs/features.md
- ルール仕様: docs/rules.md
- CLI / Python API の使い方: docs/usage.md
- 設定ファイル仕様: docs/configuration.md
- 開発方法と Dev Container: docs/development.md
- CI / セキュリティ方針: docs/quality-and-security.md
fp-checker の継続開発を支援する場合は、GitHub Sponsors からお願いします。
- Rust workspace:
fp_checker_core,fp_checker_cli,fp_checker_py - Python 構文解析:
rustpython-parserベースの adapter - ignore デコレータ:
@fp_ignoreを既定値としてサポート - MVP ルール:
- 可変グローバル状態
- 代入の多用
- 直接 I/O
- 非決定的呼び出し
- 外部状態への副作用
- ミュータブルなデフォルト引数
- 直接的な effectful call
global/nonlocal
- 追加ルール:
- hidden mutation
- loop 内副作用
- 例外制御フロー
- class method 内副作用
- 参照透過性を壊す暗黙依存
- 非推奨 API 使用
- 出力形式: text / JSON / SARIF
- AI 向けの structured
fix_hintを JSON に含める - CLI / Python API /
pyproject.toml設定対応 - 設定スキーマ: unknown key を reject する strict TOML
- config 駆動の custom rule:
call/name/attribute_write - サポート方針: Rust 1.94+, Python 3.12+
- CI 上の Python smoke test: 3.12 / 3.13 / 3.14
- JSON schema 検証:
tests/fixtures/report.schema.json - リリース自動化: tag push で GitHub Release と PyPI publish
- benchmark:
cargo bench -p fp_checker_core - pre-commit:
.pre-commit-config.yaml
pip install fp-checkerfp-checker --helpfp-checker check path/to/projectpython -m fp_checker --helpcargo run -p fp_checker_cli -- check tests/fixtures/sample_projectcargo run -p fp_checker_cli -- check tests/fixtures/sample_project --format jsoncargo run -p fp_checker_cli -- check tests/fixtures/sample_project --format sarifmaturin develop --manifest-path crates/fp_checker_py/Cargo.toml
python3 -c "import fp_checker; print(fp_checker.available_rules())"import fp_checker
print(fp_checker.check_code("def f(items=[]):\n return items", format="json"))このリポジトリには、すぐ試せるサンプルとして tests/fixtures/sample_project が含まれています。origin/main の現在内容もこの fixture と期待値 JSON を前提にしているため、README の例もこれに合わせています。
tests/fixtures/sample_project/sample.py
import random
import time
STATE = []
def pure_add(x, y):
return x + y
def uses_mutable_global():
return STATE
def mutates_global():
global STATE
STATE.append(1)
return STATE
def direct_io(path):
print(path)
return open(path)
def nondeterministic():
return random.random() + time.time()
def external_state(obj, items=[]):
obj.value = 10
obj.save()
return itemsfp-checker check tests/fixtures/sample_projecttext 出力例(抜粋):
fp-checker report
files=2 checked_functions=7 ignored_functions=1 diagnostics=4
tests/fixtures/sample_project/broken.py (checked=0, ignored=0, diagnostics=1)
[error] tests/fixtures/sample_project/broken.py:1:12 invalid syntax. Got unexpected token ':' at byte offset 11 (parse_error)
hint: Fix the syntax error and run the checker again.
tests/fixtures/sample_project/sample.py (checked=7, ignored=1, diagnostics=3)
function pure_add purity=pure[info] style=no_reassignment[info]
function uses_mutable_global purity=impure_reads_external_state[warning] style=no_reassignment[info]
function mutates_global purity=impure_writes_external_state[error] style=has_mutation[info]
function direct_io purity=impure_direct_io[error] style=no_reassignment[info]
function nondeterministic purity=impure_nondeterministic[error] style=no_reassignment[info]
function external_state purity=impure_writes_external_state[error] style=has_mutation[info]
[warning] tests/fixtures/sample_project/sample.py:18:12 References mutable global state `STATE`. (mutable_global_state)
function: uses_mutable_global
hint: Pass the value in as an argument and manage state outside the function.
JSON 出力例(抜粋):
fp-checker check tests/fixtures/sample_project --format json{
"summary": {
"files": 2,
"checked_functions": 7,
"ignored_functions": 1,
"diagnostics": 4
},
"files": [
{
"path": "tests/fixtures/sample_project/broken.py",
"diagnostics": [
{
"rule_id": "parse_error",
"severity": "error",
"message": "invalid syntax. Got unexpected token ':' at byte offset 11"
}
]
},
{
"path": "tests/fixtures/sample_project/sample.py",
"function_assessments": [
{
"qualified_name": "mutates_global",
"external_purity": {
"primary": "impure_writes_external_state",
"severity": "error"
},
"implementation_style": {
"primary": "has_mutation",
"severity": "info"
}
}
],
"diagnostics": [
{
"rule_id": "mutable_global_state",
"severity": "warning",
"function": "uses_mutable_global",
"message": "References mutable global state `STATE`."
},
{
"rule_id": "mutable_default_argument",
"severity": "warning",
"function": "external_state",
"message": "Parameter `items` has a mutable default value."
}
]
}
]
}import fp_checker
report = fp_checker.check_path("tests/fixtures/sample_project", format="json")
print(report)出力例(抜粋):
{
"summary": {
"files": 2,
"checked_functions": 7,
"ignored_functions": 1,
"diagnostics": 4
}
}cargo check
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test.
├── crates/
│ ├── fp_checker_cli/
│ ├── fp_checker_core/
│ └── fp_checker_py/
├── docs/
├── python/
│ └── examples/
├── tests/
│ └── fixtures/
├── .devcontainer/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
├── Cargo.toml
├── pyproject.toml
├── CONTRIBUTING.md
├── SECURITY.md
└── CHANGELOG.md