Skip to main content

provably

Z3-backed formal verification for Python -- via decorators and refinement types

PyPI Python License: MIT CI Typed Docs


from provably import verified

@verified(
    pre=lambda val, lo, hi: lo <= hi,
    post=lambda val, lo, hi, result: (result >= lo) & (result <= hi),
)
def clamp(val: float, lo: float, hi: float) -> float:
    if val < lo:
        return lo
    elif val > hi:
        return hi
    else:
        return val

clamp.__proof__.verified   # True — for ALL inputs where lo <= hi
str(clamp.__proof__)       # "[Q.E.D.] clamp"

verified=True is a mathematical proof. Z3 determined that no input satisfying the precondition can violate the postcondition.

Install

pip install provably
# or: uv add provably

Examples

Pre/post contracts

@verified(
    pre=lambda a, b: b > 0,
    post=lambda a, b, result: (result >= 0) & (result < b),
)
def modulo(a: int, b: int) -> int:
    return a % b

modulo.__proof__.verified        # True
modulo.__proof__.solver_time_ms  # ~2ms

Refinement types

from typing import Annotated
from provably.types import Between, Gt, NonNegative

@verified(post=lambda p, x, result: result >= 0)
def scale(
    p: Annotated[float, Between(0, 1)],
    x: Annotated[float, Gt(0)],
) -> NonNegative:
    return p * x

scale.__proof__.verified  # True

Counterexample extraction

@verified(
    pre=lambda n: n >= 0,
    post=lambda n, result: result * result == n,  # wrong
)
def bad_sqrt(n: int) -> int:
    return n // 2

bad_sqrt.__proof__.counterexample  # {'n': 3, '__return__': 1}

Compositionality

@verified(
    contracts={"my_abs": my_abs.__contract__},
    post=lambda x, y, result: result >= 0,
)
def manhattan(x: float, y: float) -> float:
    return my_abs(x) + my_abs(y)

manhattan.__proof__.verified  # True

While loops

Bounded while loops are unrolled (up to 256 iterations), just like for loops:

@verified(
    pre=lambda n: (n >= 0) & (n <= 10),
    post=lambda n, result: result == n * (n + 1) // 2,
)
def triangle(n: int) -> int:
    total = 0
    i = 0
    while i < n:  # variant: n - i
        i += 1
        total += i
    return total

triangle.__proof__.verified  # True

Walrus operator

The walrus operator (:=) is supported for inline assignments:

@verified(
    post=lambda x, result: (result >= 0) & ((result == x) | (result == -x)),
)
def my_abs(x: float) -> float:
    return (neg := -x) if x < 0 else x

my_abs.__proof__.verified  # True

Match/case (Python 3.10+)

match/case statements are desugared to if/elif/else for Z3:

@verified(
    pre=lambda code: (code >= 0) & (code <= 3),
    post=lambda code, result: (result >= 10) & (result <= 40),
)
def dispatch(code: int) -> int:
    match code:
        case 0: return 10
        case 1: return 20
        case 2: return 30
        case _: return 40

dispatch.__proof__.verified  # True

Tuple returns

Functions can return tuples. Each element is accessible via constant subscript:

@verified(
    post=lambda x, y, result: result >= 0,
)
def sum_and_diff(x: float, y: float) -> tuple:
    return (x + y, x - y)

Lean4 backend

Cross-check Z3 results with an independent proof assistant:

from provably import verify_with_lean4, export_lean4

# Verify with Lean4 type checker (requires Lean4 installed)
cert = verify_with_lean4(clamp, pre=lambda v, lo, hi: lo <= hi,
                         post=lambda v, lo, hi, r: (r >= lo) & (r <= hi))

# Export as .lean theorem file
lean_code = export_lean4(clamp, output_path="clamp.lean")

Supported constructs

Construct Supported
+, -, *, //, /, %, **n Yes
<, <=, >, >=, ==, != Yes
and, or, not, &, |, ~ Yes
if/elif/else/ternary Yes
match/case (Python 3.10+) Yes (desugared to if/elif/else)
min, max, abs Yes
pow, bool, int, float, len, round Yes
sum, any, all Yes
Annotated refinement types Yes
Calls via contracts= Yes
Walrus operator (:=) Yes
Tuple returns + constant subscript (t[0]) Yes
while loops (bounded, max 256 iterations) Yes (unrolled)
for i in range(N) (literal N, max 256) Yes (unrolled)
assert statements Yes (become proof obligations)
Lean4 backend (verify_with_lean4) Yes (requires Lean4)
Recursion No
str, list, dict No
Unbounded loops, generators, async No

Comparison

Library Approach Proof strength Call-site overhead
provably SMT / Z3 Mathematical proof Zero solver overhead
deal Runtime contracts Bug finding Per-call
icontract Runtime contracts Bug finding Per-call
CrossHair Symbolic execution Property testing Test-time
beartype Runtime types Type checking Per-call

Links

Metadata

Release files for provably 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for provably 0.3.0
File Size Uploaded
provably-0.3.0.tar.gz 86.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for provably 0.3.0
File Interpreter ABI Platform
provably-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 129.3 kB

Release files / provably-0.3.0.tar.gz

Download URL provably-0.3.0.tar.gz
Size 86.1 kB
Tags Source
SHA-256 checksum
How to use checksums
9f9e53d57719995046dc749a3973feedf6539207b0c5921c4b4c38bbfe825f1b
BLAKE2b-256 checksum
How to use checksums
58651466125a64e08ff503fc5f0c4d4f60ef70fb3c643b1c1eee7d5d2002ab91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 1, 2026.

Transparency log

Release files / provably-0.3.0-py3-none-any.whl

Download URL provably-0.3.0-py3-none-any.whl
Size 43.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c10e1697d5be2592e3329c0260a83eed0d50d50cfbd5c41286ae3a745d3d5288
BLAKE2b-256 checksum
How to use checksums
667bca445ebe5d855349fad294a0470f232e9ba265780d72f685a985b1f3f44b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page