Skip to content

sotanengel/python-fp-checker

fp-checker

Sponsor

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.

English Summary

  • 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

Where To Start

Support

If fp-checker helps your work, you can support ongoing maintenance on GitHub Sponsors:

日本語

Python コードを解析し、関数型プログラミングのルールに反した関数を検査する Rust 製ツールです。CLI と Python API の両方を提供し、結果は text / JSON / SARIF の各形式で出力できます。組み込みルールに加えて、設定ファイルだけで custom rule を追加できます。

どこを見れば何が分かるか

スポンサー

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

クイックスタート

PyPI からインストール

pip install fp-checker
fp-checker --help
fp-checker check path/to/project
python -m fp_checker --help

CLI

cargo run -p fp_checker_cli -- check tests/fixtures/sample_project
cargo run -p fp_checker_cli -- check tests/fixtures/sample_project --format json
cargo run -p fp_checker_cli -- check tests/fixtures/sample_project --format sarif

Python API

maturin 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 items

CLI での実行例

fp-checker check tests/fixtures/sample_project

text 出力例(抜粋):

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."
        }
      ]
    }
  ]
}

Python API での実装例

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

About

Pythonのコードにおいて関数が関数型かをチェックするリポジトリです。

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors