Skip to main content

Design-by-contract library for Python, implemented in Rust.

Project description

contract-check

Sponsor

This is a design-by-contract library for Python, implemented in Rust.

contract-check は、Python 向けの契約プログラミングライブラリです。公開 API は Python の decorator 中心で設計し、内部の構造化違反情報と実行時基盤を Rust で実装します。 思想面では life4/deal を参考にしつつ、配布、監査性、 AI 補助開発、Python/Rust 混成運用を前提に再設計しています。

クイックスタート

pip install contract-check

PyPI wheel 配布対象:

  • macOS
  • Linux
  • Windows

macOS wheel は universal2 を使い、Apple Silicon と Intel の両方を対象にします。

from __future__ import annotations

import asyncio

from contract_check import (
    ContractViolationError,
    ViolationDetail,
    contract,
    invariant,
    invariant_class,
    post,
    pre,
    pure,
    raises,
    read_only,
)


def divisor_is_not_zero(divisor: int) -> bool:
    return divisor != 0


def quotient_matches_dividend(result: int, dividend: int, divisor: int) -> bool:
    return result * divisor == dividend


def value_is_positive(value: int) -> ViolationDetail | None:
    if value > 0:
        return None
    return ViolationDetail(
        code="value.non_positive",
        message="value must be positive",
        field_path="/value",
        actual=value,
        expected="value > 0",
    )


def result_is_incremented(result: int, value: int) -> bool:
    return result == value + 1


def balance_is_non_negative(self: "Wallet") -> bool:
    return self.balance >= 0


@contract(
    pre(divisor_is_not_zero),
    post(quotient_matches_dividend),
    raises(ZeroDivisionError),
    pure(),
)
def divide(dividend: int, divisor: int) -> int:
    if divisor == 0:
        raise ZeroDivisionError("division by zero")
    return dividend // divisor


@contract(
    pre(value_is_positive),
    post(result_is_incremented),
)
async def async_increment(value: int) -> int:
    await asyncio.sleep(0)
    return value + 1


@invariant_class(
    invariant(balance_is_non_negative, policy="mutating_only"),
)
class Wallet:
    def __init__(self, balance: int) -> None:
        self.balance = balance

    def debit(self, amount: int) -> None:
        self.balance -= amount

    @read_only
    def current_balance(self) -> int:
        return self.balance


assert divide(12, 3) == 4
assert asyncio.run(async_increment(2)) == 3

配布名と import 名:

  • PyPI distribution 名は contract-check です
  • 公式 Python import 名は contract_check です
  • 既存の python_contracts_rs も後方互換 alias として継続サポートします
  • python_contracts_rs を削除する場合は 1.x より前に silent break しません

標準挙動:

  • 契約は sync / async 関数の両方で有効です
  • PYTHON_CONTRACTS_RS=0 で実行時に無効化できます
  • 契約違反は ContractViolationError として送出され、code / message / field_path / actual / expected / contract_phase / predicate_name を含む構造化出力を返せます
  • predicate は bool だけでなく ViolationDetail | None も返せます
  • pre(...) / post(...) / invariant(...) / error(...) は callable を受け取り、手書きの条件文字列は受け取りません
  • condition には callable 名または例外型名のような導出ラベルが入ります

提供機能

機能 Python API 補足
前提条件 pre(...) sync / async / async generator の実行前に検証
事後条件 post(...) 戻り値は result / ret で参照
不変条件 invariant(...) / @invariant_class(...) policy= / cost=@read_only / @mutating で粒度制御
期待例外 raises(...) / error(...) 許可された例外のみ通過
純粋性 pure(...) 現段階では意図表明
panic 方針 panic_free(...) 予期しない例外を契約違反へ変換
rich violation ViolationDetail API 応答やログへ流しやすい詳細 payload
typed predicates PrePredicate / PostPredicate / InvariantPredicate / ErrorPredicate Protocol と mypy / pyright を前提にした型支援
テスト支援 collect_violations(...) / assert_valid(...) / validate_payload(...) decorator を通さず predicate を直接検証
runtime 制御 contract_runtime(...) debug_only / expensive invariant の有効化を文脈単位で切替
契約メタデータ get_contract_metadata(...) ドキュメント生成やテスト補助向け
構造化出力 violation_to_dict(...) / violation_to_json(...) CI や監査ログ向け
SARIF 出力 violation_to_sarif_result(...) / violations_to_sarif(...) GitHub code scanning 連携向け

詳細ガイド:

リポジトリ構成

  • python/python_contracts_rs/ Python 公開 API と decorator 実装です。
  • python/contract_check/ 公式 import alias です。既存の python_contracts_rs を再エクスポートします。
  • bindings/python-contracts-rs/ PyO3 ベースの Python/Rust バインディングです。
  • crates/rust-contract-checks/ Rust 側の低レベルな契約種別・違反情報・設定判定です。
  • examples/quickstart.py Python 利用者向けの最短例です。
  • examples/typed_predicates.py typed predicate と Protocol を含む型支援サンプルです。
  • tests/python/test_contracts.py Python 公開 API の統合テストです。
  • tests/contracts.rs Rust コアの回帰テストです。

生成 AI 向け案内

このプロジェクトは Python library implemented in Rust です。Rust 単独ライブラリとして 読まないでください。読む順序は次を推奨します。

  1. この README.md
  2. docs/contracts.md
  3. examples/quickstart.py
  4. tests/python/test_contracts.py
  5. ARCHITECTURE.md
  6. AGENTS.md

AI 運用方針:

  • 主成果物は Python API として扱う
  • 内部推論を英語で行う運用は許容
  • 最終回答とコードコメントは日本語
  • 仕様変更時は README / examples / tests / docs を同時更新

開発

ローカル開発:

make setup
make ci

Docker:

docker build -t contract-check .
docker run --rm -it -v "$PWD:/workspace" contract-check make ci

Dev Container は .devcontainer/devcontainer.json を参照してください。

現状の制限

  • @invariant_class(...) は public instance method と __init__ を対象にします
  • private / dunder / staticmethod / classmethod への自動適用は明示設定または将来拡張の対象です
  • pure(...) は意図表明です
  • tracing backend は未実装です

ライセンス

Apache License 2.0。詳細は LICENSE を参照してください。

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

contract_check-0.4.0.tar.gz (38.5 kB view details)

Uploaded Source

Built Distributions

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

contract_check-0.4.0-cp39-abi3-win_amd64.whl (168.2 kB view details)

Uploaded CPython 3.9+Windows x86-64

contract_check-0.4.0-cp39-abi3-manylinux_2_34_x86_64.whl (319.2 kB view details)

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

contract_check-0.4.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (535.8 kB view details)

Uploaded CPython 3.9+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file contract_check-0.4.0.tar.gz.

File metadata

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

File hashes

Hashes for contract_check-0.4.0.tar.gz
Algorithm Hash digest
SHA256 d2a9eaaf09c2586fcdd01f1e6fbaf2797cdb47617012778acc904e306bc901b0
MD5 76211f4278a3f85f75045f24a173b018
BLAKE2b-256 a55d6b84831f1ea0dc5c4afc8428a31f6380016c144d96c631f7cc331d0c0a23

See more details on using hashes here.

File details

Details for the file contract_check-0.4.0-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for contract_check-0.4.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 22e8b3e20f8ac24b93b660369f59ac52404cb0abaa042a2666ae89a54211f92d
MD5 90065b2f15148804ffcc11c569c743be
BLAKE2b-256 efb7f9e93a96ab2cc24ba2a9385b9cdc2798459ea36c29ddf30ef8803acea050

See more details on using hashes here.

File details

Details for the file contract_check-0.4.0-cp39-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for contract_check-0.4.0-cp39-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 6558afbb52c249cb9993ce3363e0c1170d11fee4373b12646915422076cf7971
MD5 993612754c772382aed484e8c070f653
BLAKE2b-256 1403f146f7ddcccf74555045805ea39db2d93bf14c6f7ddc427d4fc076ad6f44

See more details on using hashes here.

File details

Details for the file contract_check-0.4.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for contract_check-0.4.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 d92b6d6ba19ceebb8d1a046881a5c83b457d82518d9389633033926be68bcd94
MD5 83ec2b9948abef914bf89951ab458309
BLAKE2b-256 6e59fe1b3d9fbc467b98f1a8a7f36bbd047197248e66bef2e28c4d107882f134

See more details on using hashes here.

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