provably
Z3-backed formal verification for Python -- via decorators and refinement types
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)
| File | Size | Uploaded | |
|---|---|---|---|
| provably-0.3.0.tar.gz | 86.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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