Registry / testing / icontract

icontract

JSON →
library2.7.3pypypi✓ verified 85d ago

icontract provides design-by-contract for Python, allowing developers to define preconditions, postconditions, and invariants for functions and classes using expressive lambda functions. It helps ensure correctness and provides informative violation messages, failing fast when contracts are broken. The current version is 2.7.3, and it maintains a steady release cadence with frequent patch updates addressing bugs and adding support for newer Python versions.

pip install icontract
INSTALL
IMPORT
SIG · ICONTRACT
I
icontract
testingpythonv2.7.3
Install
1.7s avg
Import
69ms
Disk
17MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v2.7.3 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.072s · 18.7MB
glibc
py 3.103.920 runs
installs and imports cleanly · install 1.7s · import 0.066s · 19MB
17MB installed
● package 17MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

require
from icontract import require
ensure
from icontract import ensure
invariant
from icontract import invariant
ViolationError
from icontract import ViolationError
from icontract.errors import ViolationError
ViolationError is directly exposed in the top-level package since icontract 2.x.

This quickstart demonstrates how to apply preconditions (`@require`), postconditions (`@ensure`), and class invariants (`@invariant`) to Python functions and classes. It shows basic usage with lambda expressions and how to catch `ViolationError` when contracts are broken. Note the use of `old` in `@ensure` to refer to the state before the function call.

import icontract @icontract.require(lambda x: x > 0, "Input must be positive") @icontract.ensure(lambda result: result > 0, "Result must be positive") def double(x: int) -> int: return x * 2 @icontract.invariant(lambda self: self.value >= 0, "Value must be non-negative") class Counter: def __init__(self, initial_value: int) -> None: self.value = initial_value @icontract.ensure(lambda old, self: self.value == old.value + 1) def increment(self) -> None: self.value += 1 # Example usage try: print(f"Doubling 5: {double(5)}") # This will raise a ViolationError # double(-1) except icontract.ViolationError as e: print(f"Contract violation caught: {e}") c = Counter(0) print(f"Initial counter value: {c.value}") c.increment() print(f"Counter after increment: {c.value}") try: # This would violate the invariant if direct assignment was not restricted # c.value = -5 # To see invariant violation on setattr, 'enforce_on_setattr' must be set pass except icontract.ViolationError as e: print(f"Invariant violation caught: {e}")
Debug
Known issues
gotchaInvariants on `super().__init__` calls in child classes were incorrectly checked in versions prior to 2.7.2, potentially leading to false negatives or unexpected behavior in inheritance hierarchies.
fix
Upgrade to icontract 2.7.2 or newer. Ensure your invariant logic correctly accounts for the superclass's state during its initialization phase.
affects: <2.7.2
gotchaA bug in version 2.7.0 caused invariants defined on derived classes to incorrectly 'leak' up to parent classes, leading to unintended invariant checks on base class instances or methods.
fix
Upgrade to icontract 2.7.1 or newer. This bug was a critical fix addressed in 2.7.1.
affects: 2.7.0
gotchaBy default, invariants are checked on method calls. As of 2.7.0, `icontract` allows enforcing invariants on attribute setting (`__setattr__`). If enabled via `enforce_on_setattr=True`, this can introduce significant performance overhead or unexpected `ViolationError`s if not carefully managed.
fix
Be mindful of performance implications when enabling `enforce_on_setattr`. Only enable it for critical attributes where immediate invariant validation on modification is required, and profile your application to ensure acceptable performance.
affects: >=2.7.0
gotchaWhen defining postconditions (`@ensure`), if you need to compare the state after the function execution with the state *before*, you must explicitly include `old` as an argument in your lambda expression (e.g., `lambda old, result: ...`). Failing to do so will result in a `NameError`.
fix
Always include `old` in your `@ensure` lambda signature if you intend to refer to the object's state or arguments' values before the function was called. For class methods, `old` will contain the instance before the call.
affects: All versions
Errors
Common errors & fixes
icontract.errors.ViolationError: ...
A contract (precondition, postcondition, or invariant) was violated during program execution.
fix
Review the contract condition that failed and the input values or object state that led to its violation. This often indicates a bug in the calling code or an incorrect assumption about the function's behavior.
NameError: name 'old' is not defined
You are trying to use `old` in an `@ensure` contract without declaring it as an argument in your lambda function.
fix
Modify your `@ensure` lambda to accept `old` as its first argument (e.g., `lambda old, result: ...` for a function returning a value, or `lambda old, self: ...` for a method to access the state before the call).
TypeError: <lambda>() missing 1 required positional argument: 'result'
Your `@ensure` contract lambda expects `result` (the return value of the function) but the decorated function is `None` or an argument is missing.
fix
Ensure the lambda signature for `@ensure` correctly matches the function's return type. If the function has no return value, use `lambda old, self: ...` or simply `lambda self: ...` for methods, or `lambda: ...` for functions without arguments.
TypeError: <lambda>() takes 1 positional argument but 2 were given
Your contract lambda's signature does not match the arguments provided by `icontract` (e.g., expecting only `self` but also receiving `old` or `result`).
fix
Adjust the lambda signature to accept all arguments `icontract` provides for that context (e.g., `lambda self: ...` for a simple invariant, `lambda self, old: ...` for invariant checking `old` state, `lambda x: ...` for a precondition on argument `x`).
Upgrade
Version history
2.7.3latest on PyPI · released Jan 29, 2026
Audit
Dependencies
typing_inspectrequiredUsed for introspection of type hints in contracts.
typeguardrequiredUsed for runtime type checking, integrated with contract enforcement.
asttokensrequiredRequired for extracting source code of contract expressions to provide informative violation messages.
dealoptionalAn older dependency for Python versions < 3.8, providing a similar contract-based approach. Modern Python users typically don't need it explicitly.
Agent activity
30 hits · last 30 days
node
28
OpenAI (training)
1
Resources
icontract — pip install icontract · libregistry