{"id":7300,"library":"icontract","title":"Icontract: Design-by-Contract for Python","description":"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.","status":"active","version":"2.7.3","language":"en","source_language":"en","source_url":"https://github.com/Parquery/icontract","tags":["design by contract","contracts","preconditions","postconditions","invariants","validation","runtime checks","type checking"],"install":[{"cmd":"pip install icontract","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Used for introspection of type hints in contracts.","package":"typing_inspect","optional":false},{"reason":"Used for runtime type checking, integrated with contract enforcement.","package":"typeguard","optional":false},{"reason":"Required for extracting source code of contract expressions to provide informative violation messages.","package":"asttokens","optional":false},{"reason":"An older dependency for Python versions < 3.8, providing a similar contract-based approach. Modern Python users typically don't need it explicitly.","package":"deal","optional":true}],"imports":[{"symbol":"require","correct":"from icontract import require"},{"symbol":"ensure","correct":"from icontract import ensure"},{"symbol":"invariant","correct":"from icontract import invariant"},{"note":"ViolationError is directly exposed in the top-level package since icontract 2.x.","wrong":"from icontract.errors import ViolationError","symbol":"ViolationError","correct":"from icontract import ViolationError"}],"quickstart":{"code":"import icontract\n\n@icontract.require(lambda x: x > 0, \"Input must be positive\")\n@icontract.ensure(lambda result: result > 0, \"Result must be positive\")\ndef double(x: int) -> int:\n    return x * 2\n\n@icontract.invariant(lambda self: self.value >= 0, \"Value must be non-negative\")\nclass Counter:\n    def __init__(self, initial_value: int) -> None:\n        self.value = initial_value\n\n    @icontract.ensure(lambda old, self: self.value == old.value + 1)\n    def increment(self) -> None:\n        self.value += 1\n\n# Example usage\ntry:\n    print(f\"Doubling 5: {double(5)}\")\n    # This will raise a ViolationError\n    # double(-1)\nexcept icontract.ViolationError as e:\n    print(f\"Contract violation caught: {e}\")\n\nc = Counter(0)\nprint(f\"Initial counter value: {c.value}\")\nc.increment()\nprint(f\"Counter after increment: {c.value}\")\n\ntry:\n    # This would violate the invariant if direct assignment was not restricted\n    # c.value = -5 \n    # To see invariant violation on setattr, 'enforce_on_setattr' must be set\n    pass\nexcept icontract.ViolationError as e:\n    print(f\"Invariant violation caught: {e}\")","lang":"python","description":"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."},"warnings":[{"fix":"Upgrade to icontract 2.7.2 or newer. Ensure your invariant logic correctly accounts for the superclass's state during its initialization phase.","message":"Invariants 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.","severity":"gotcha","affected_versions":"<2.7.2"},{"fix":"Upgrade to icontract 2.7.1 or newer. This bug was a critical fix addressed in 2.7.1.","message":"A 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.","severity":"gotcha","affected_versions":"2.7.0"},{"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.","message":"By 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.","severity":"gotcha","affected_versions":">=2.7.0"},{"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.","message":"When 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`.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"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.","cause":"A contract (precondition, postcondition, or invariant) was violated during program execution.","error":"icontract.errors.ViolationError: ..."},{"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).","cause":"You are trying to use `old` in an `@ensure` contract without declaring it as an argument in your lambda function.","error":"NameError: name 'old' is not defined"},{"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.","cause":"Your `@ensure` contract lambda expects `result` (the return value of the function) but the decorated function is `None` or an argument is missing.","error":"TypeError: <lambda>() missing 1 required positional argument: '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`).","cause":"Your contract lambda's signature does not match the arguments provided by `icontract` (e.g., expecting only `self` but also receiving `old` or `result`).","error":"TypeError: <lambda>() takes 1 positional argument but 2 were given"}]}