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 is a Python-first design-by-contract library. The public API is built around Python decorators, while Rust provides the runtime core and structured violation payloads. The project is inspired by life4/deal, but is redesigned for distribution, observability, AI-assisted development, and mixed Python/Rust workflows.

Quick Start

pip install contract-check

PyPI wheels are published for:

  • macOS
  • Linux
  • Windows

macOS wheels use universal2 to support both Apple Silicon and 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

Distribution and import names:

  • The PyPI distribution name is contract-check
  • The primary Python import name is contract_check
  • The legacy python_contracts_rs import remains supported as a backwards-compatible alias
  • python_contracts_rs will not be silently removed before a future 1.x migration plan is documented

Default behavior:

  • Contracts work for both sync and async call paths
  • Set PYTHON_CONTRACTS_RS=0 to disable runtime checks
  • Contract violations are raised as ContractViolationError with structured fields such as code, message, field_path, actual, expected, contract_phase, and predicate_name
  • Predicates may return either bool or ViolationDetail | None
  • pre(...), post(...), invariant(...), and error(...) accept callables rather than handwritten condition strings
  • condition stores a derived label such as a callable name or exception type name

Features

Feature Python API Notes
  • Preconditions | pre(...) | Validated before sync, async, and async-generator execution |
  • Postconditions | post(...) | Return values are available as result or ret |
  • Invariants | invariant(...) / @invariant_class(...) | Controlled with policy=, cost=, @read_only, and @mutating |
  • Expected exceptions | raises(...) / error(...) | Only declared exceptions are allowed through |
  • Purity marker | pure(...) | Currently an intent marker |
  • Panic policy | panic_free(...) | Converts unexpected exceptions into contract violations |
  • Rich violations | ViolationDetail | Structured payloads for APIs and logs |
  • Typed predicates | PrePredicate / PostPredicate / InvariantPredicate / ErrorPredicate | Typing support for Protocol, mypy, and pyright |
  • Testing helpers | collect_violations(...) / assert_valid(...) / validate_payload(...) | Evaluate predicates directly without decorators |
  • Runtime controls | contract_runtime(...) | Toggle debug_only and expensive invariants per context |
  • Contract metadata | get_contract_metadata(...) | Useful for documentation and test helpers |
  • Structured output | violation_to_dict(...) / violation_to_json(...) | CI- and audit-log-friendly output |
  • SARIF output | violation_to_sarif_result(...) / violations_to_sarif(...) | Integration with GitHub code scanning |

Further reading:

Repository Layout

  • python/python_contracts_rs/ Python public API and decorator implementation.
  • python/contract_check/ Primary import alias that re-exports the legacy python_contracts_rs package.
  • bindings/python-contracts-rs/ PyO3-based Python/Rust bindings.
  • crates/rust-contract-checks/ Rust core for contract kinds, violation reporting, and runtime config.
  • examples/quickstart.py Minimal Python user example.
  • examples/typed_predicates.py Typed predicate and Protocol example.
  • tests/python/test_contracts.py Python API integration tests.
  • tests/contracts.rs Rust core regression tests.

生成 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.1.tar.gz (37.9 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.1-cp39-abi3-win_amd64.whl (167.9 kB view details)

Uploaded CPython 3.9+Windows x86-64

contract_check-0.4.1-cp39-abi3-manylinux_2_34_x86_64.whl (318.8 kB view details)

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

contract_check-0.4.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (535.7 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.1.tar.gz.

File metadata

  • Download URL: contract_check-0.4.1.tar.gz
  • Upload date:
  • Size: 37.9 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.1.tar.gz
Algorithm Hash digest
SHA256 62f88e34b33cd61ced9bbfc1aa0ee1cd0525ba69a5b46d46514041e99f25b77e
MD5 b288e38d01e34fccd77d5e13f94f5a8b
BLAKE2b-256 b46e77bce4bc78bec1ca7d8f6145919265dc947dcdc7cbbd1fa2cff44efc1ee9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for contract_check-0.4.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 09641a35fa16ea185877dc8d3bd910c141103cedfc3dd34ad5587a10ba000cef
MD5 78b2eee6449c186e1a7c5d3f6a99a9b8
BLAKE2b-256 baa437a764c109edcd748ffd11eeef4c9ccff0e6413a5448a5548573d50594cd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for contract_check-0.4.1-cp39-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 205faf8a7f5d0acb64bc757879164af54d52299c82fef186f896336383ee9e0c
MD5 0c1261f880d6c82bfb7d050ef149d6cb
BLAKE2b-256 d269d01feccd41bee72a43534a0558affe0e9809fa3f96c117ac128f1799451b

See more details on using hashes here.

File details

Details for the file contract_check-0.4.1-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.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 4b661f2e19f344463d926c4be92af1c7a1ed9c39e5a58f0f6fa7b3977da83a1e
MD5 18df199c1467d5d30bf240047faae79d
BLAKE2b-256 8009009293bd2353e9ac5bb7c8481283373947b2e2844fdd352ebfc0d97a2447

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