Skip to main content

A Rust-powered checker for Python functions that violate functional-programming-oriented rules

Project description

fp-checker

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

日本語

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

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

現在の実装範囲

  • 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fp_checker-0.1.7.tar.gz (60.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fp_checker-0.1.7-cp39-abi3-manylinux_2_34_x86_64.whl (2.6 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.34+ x86-64

File details

Details for the file fp_checker-0.1.7.tar.gz.

File metadata

  • Download URL: fp_checker-0.1.7.tar.gz
  • Upload date:
  • Size: 60.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fp_checker-0.1.7.tar.gz
Algorithm Hash digest
SHA256 47864c55d00121d996cc63ac9f15c9e9493b69725fa829a5016f414c6e948a1e
MD5 6d4404912d72bca3f225012c85647042
BLAKE2b-256 69bef80cc0d815e64419cca205574f393e32dd0e35832293656f04389304afe4

See more details on using hashes here.

Provenance

The following attestation bundles were made for fp_checker-0.1.7.tar.gz:

Publisher: release.yml on sotanengel/python-fp-checker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fp_checker-0.1.7-cp39-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for fp_checker-0.1.7-cp39-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 7d2b81836d07ec356c755a5fa62467a3bedbd17ab949bcdf6c85194d38251788
MD5 eb0b36135772838993f3bb8b7234fc4a
BLAKE2b-256 0f59330e4c53fc5ecdf399c22a91caf2a66d500a6d0f21cbb3f48a9ae8716906

See more details on using hashes here.

Provenance

The following attestation bundles were made for fp_checker-0.1.7-cp39-abi3-manylinux_2_34_x86_64.whl:

Publisher: release.yml on sotanengel/python-fp-checker

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page