Design-by-contract library for Python, implemented in Rust.
Project description
contract-check
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:
macOSLinuxWindows
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_rsimport remains supported as a backwards-compatible alias python_contracts_rswill not be silently removed before a future1.xmigration plan is documented
Default behavior:
- Contracts work for both sync and async call paths
- Set
PYTHON_CONTRACTS_RS=0to disable runtime checks - Contract violations are raised as
ContractViolationErrorwith structured fields such ascode,message,field_path,actual,expected,contract_phase, andpredicate_name - Predicates may return either
boolorViolationDetail | None pre(...),post(...),invariant(...), anderror(...)accept callables rather than handwritten condition stringsconditionstores 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 asresultorret| - Invariants |
invariant(...)/@invariant_class(...)| Controlled withpolicy=,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 forProtocol, mypy, and pyright | - Testing helpers |
collect_violations(...)/assert_valid(...)/validate_payload(...)| Evaluate predicates directly without decorators | - Runtime controls |
contract_runtime(...)| Toggledebug_onlyandexpensiveinvariants 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 legacypython_contracts_rspackage.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.pyMinimal Python user example.examples/typed_predicates.pyTyped predicate andProtocolexample.tests/python/test_contracts.pyPython API integration tests.tests/contracts.rsRust core regression tests.
生成 AI 向け案内
このプロジェクトは Python library implemented in Rust です。Rust 単独ライブラリとして 読まないでください。読む順序は次を推奨します。
- この
README.md - docs/contracts.md
- examples/quickstart.py
- tests/python/test_contracts.py
- ARCHITECTURE.md
- 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62f88e34b33cd61ced9bbfc1aa0ee1cd0525ba69a5b46d46514041e99f25b77e
|
|
| MD5 |
b288e38d01e34fccd77d5e13f94f5a8b
|
|
| BLAKE2b-256 |
b46e77bce4bc78bec1ca7d8f6145919265dc947dcdc7cbbd1fa2cff44efc1ee9
|
File details
Details for the file contract_check-0.4.1-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: contract_check-0.4.1-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 167.9 kB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09641a35fa16ea185877dc8d3bd910c141103cedfc3dd34ad5587a10ba000cef
|
|
| MD5 |
78b2eee6449c186e1a7c5d3f6a99a9b8
|
|
| BLAKE2b-256 |
baa437a764c109edcd748ffd11eeef4c9ccff0e6413a5448a5548573d50594cd
|
File details
Details for the file contract_check-0.4.1-cp39-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: contract_check-0.4.1-cp39-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 318.8 kB
- Tags: CPython 3.9+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
205faf8a7f5d0acb64bc757879164af54d52299c82fef186f896336383ee9e0c
|
|
| MD5 |
0c1261f880d6c82bfb7d050ef149d6cb
|
|
| BLAKE2b-256 |
d269d01feccd41bee72a43534a0558affe0e9809fa3f96c117ac128f1799451b
|
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
- Download URL: contract_check-0.4.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
- Upload date:
- Size: 535.7 kB
- Tags: CPython 3.9+, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b661f2e19f344463d926c4be92af1c7a1ed9c39e5a58f0f6fa7b3977da83a1e
|
|
| MD5 |
18df199c1467d5d30bf240047faae79d
|
|
| BLAKE2b-256 |
8009009293bd2353e9ac5bb7c8481283373947b2e2844fdd352ebfc0d97a2447
|