# ensures
[](https://github.com/brunodantas/ensures/actions/workflows/ci.yml)
[](https://badge.fury.io/py/ensures)
[](https://pypi.org/project/ensures/)
[](https://codecov.io/gh/brunodantas/ensures)
[](https://www.python.org/downloads/)
[](https://pypi.org/project/ensures/)
[](https://github.com/astral-sh/ruff)
[](https://mypy-lang.org/)
[](https://www.gnu.org/licenses/gpl-3.0)
`ensures` is a simple Python package that implements the idea of [Design by Contract](https://en.wikipedia.org/wiki/Design_by_contract) described in the *Pragmatic Paranoia* chapter of [The Pragmatic Programmer](https://en.wikipedia.org/wiki/The_Pragmatic_Programmer). That's the chapter where they say you should *trust nobody, not even yourself*.

## Main Features
- Verification of lists of pre/post condition and invariant functions.
- Usage of arbitrary functions for such verification.
- [Result-type](https://en.wikipedia.org/wiki/Result_type) return values.
## Installation
```bash
pip install ensures
```
## Usage
### `precondition` / `require`
Runs a list of functions on all args.
Returns `Error` if any of them fails.
```python
from ensures import precondition
def is_positive(x):
"""Check if a number is positive."""
return x > 0
@precondition(is_positive)
def square_root(x):
"""Calculate square root with precondition that x must be positive."""
return x**0.5
```
### `postcondition` / `ensure`
Runs a list of functions on the result.
Returns `Error` if any of them fails.
```python
from ensures import ensure
def result_is_even(result):
"""Check if result is even."""
return result % 2 == 0
@ensure(result_is_even) # Using the alias
def double_number(x):
"""Double a number with postcondition that result is even."""
return x * 2
```
### `invariant`
Runs a list of functions on all args.
Returns `Error` if any of them fails.
```python
from ensures import invariant
@invariant(lambda x: x >= 0) # Simple lambda invariant
def increment_counter(x):
"""Increment a counter with invariant that it stays non-negative."""
return x + 1
```
### Result Handling
Pattern matching is supported to unpack the `Return` value.
```python
from ensures import Error, Success
result1 = square_root(1)
result2 = square_root(-1) # This will return an Error instance
def handle_result(res):
match res:
case Success(value):
print(f"Square root calculated: {value}")
case Error(func, args):
print(f"Precondition failed in {func.__name__} with args {args}")
handle_result(result1)
handle_result(result2)
```
## More examples
Check [examples.py](/src/ensures/examples.py)
## 📊 Performance
Contract validation adds minimal overhead:
- **Precondition**: ~7x baseline function call
- **Postcondition**: ~8x baseline function call
- **Memory**: Constant memory usage, no leaks
See [performance benchmarks](/src/ensures/test_benchmarks.py) for detailed analysis.
## 🤝 Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
## 📝 Changelog
See [CHANGELOG.md](CHANGELOG.md) for a list of changes in each version.
## 📄 License
This project is licensed under the GPL-3.0-or-later License - see the [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "ensures",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "design-by-contract, precondition, postcondition, invariant, testing, validation",
"author": "Bruno Dantas",
"author_email": "Bruno Dantas <4422988+brunodantas@users.noreply.github.com>",
"download_url": "https://files.pythonhosted.org/packages/f2/8a/b0a59612bc6765df516939ff80453e7ef1c4530d3e199d4ef7f1d71720c0/ensures-0.3.0.tar.gz",
"platform": null,
"description": "# ensures\n\n[](https://github.com/brunodantas/ensures/actions/workflows/ci.yml)\n[](https://badge.fury.io/py/ensures)\n[](https://pypi.org/project/ensures/)\n[](https://codecov.io/gh/brunodantas/ensures)\n[](https://www.python.org/downloads/)\n[](https://pypi.org/project/ensures/)\n[](https://github.com/astral-sh/ruff)\n[](https://mypy-lang.org/)\n[](https://www.gnu.org/licenses/gpl-3.0)\n\n`ensures` is a simple Python package that implements the idea of [Design by Contract](https://en.wikipedia.org/wiki/Design_by_contract) described in the *Pragmatic Paranoia* chapter of [The Pragmatic Programmer](https://en.wikipedia.org/wiki/The_Pragmatic_Programmer). That's the chapter where they say you should *trust nobody, not even yourself*.\n\n\n\n## Main Features\n\n- Verification of lists of pre/post condition and invariant functions.\n- Usage of arbitrary functions for such verification.\n- [Result-type](https://en.wikipedia.org/wiki/Result_type) return values.\n\n\n## Installation\n\n```bash\npip install ensures\n```\n\n## Usage\n\n### `precondition` / `require`\n\nRuns a list of functions on all args.\n\nReturns `Error` if any of them fails.\n\n```python\nfrom ensures import precondition\n\n\ndef is_positive(x):\n \"\"\"Check if a number is positive.\"\"\"\n return x > 0\n\n\n@precondition(is_positive)\ndef square_root(x):\n \"\"\"Calculate square root with precondition that x must be positive.\"\"\"\n return x**0.5\n```\n\n### `postcondition` / `ensure`\n\nRuns a list of functions on the result.\n\nReturns `Error` if any of them fails.\n\n```python\nfrom ensures import ensure\n\n\ndef result_is_even(result):\n \"\"\"Check if result is even.\"\"\"\n return result % 2 == 0\n\n\n@ensure(result_is_even) # Using the alias\ndef double_number(x):\n \"\"\"Double a number with postcondition that result is even.\"\"\"\n return x * 2\n```\n\n\n### `invariant`\n\nRuns a list of functions on all args.\n\nReturns `Error` if any of them fails.\n\n```python\nfrom ensures import invariant\n\n\n@invariant(lambda x: x >= 0) # Simple lambda invariant\ndef increment_counter(x):\n \"\"\"Increment a counter with invariant that it stays non-negative.\"\"\"\n return x + 1\n```\n\n### Result Handling\n\nPattern matching is supported to unpack the `Return` value.\n\n```python\nfrom ensures import Error, Success\n\n\nresult1 = square_root(1)\nresult2 = square_root(-1) # This will return an Error instance\n\ndef handle_result(res):\n match res:\n case Success(value):\n print(f\"Square root calculated: {value}\")\n case Error(func, args):\n print(f\"Precondition failed in {func.__name__} with args {args}\")\n\nhandle_result(result1)\nhandle_result(result2)\n```\n\n\n## More examples\n\nCheck [examples.py](/src/ensures/examples.py)\n\n## \ud83d\udcca Performance\n\nContract validation adds minimal overhead:\n- **Precondition**: ~7x baseline function call\n- **Postcondition**: ~8x baseline function call\n- **Memory**: Constant memory usage, no leaks\n\nSee [performance benchmarks](/src/ensures/test_benchmarks.py) for detailed analysis.\n\n## \ud83e\udd1d Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n## \ud83d\udcdd Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for a list of changes in each version.\n\n## \ud83d\udcc4 License\n\nThis project is licensed under the GPL-3.0-or-later License - see the [LICENSE](LICENSE) file for details.",
"bugtrack_url": null,
"license": null,
"summary": "Design by Contract with Functional Programming",
"version": "0.3.0",
"project_urls": {
"Changelog": "https://github.com/brunodantas/ensures/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/brunodantas/ensures#readme",
"Homepage": "https://github.com/brunodantas/ensures",
"Issues": "https://github.com/brunodantas/ensures/issues",
"Repository": "https://github.com/brunodantas/ensures"
},
"split_keywords": [
"design-by-contract",
" precondition",
" postcondition",
" invariant",
" testing",
" validation"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "73c63c3b7edf647732849de54d1dc2629a80423c2441f7451a9773594f286a87",
"md5": "07a3535f61b5152231dd06d0d6707afd",
"sha256": "510c32145fe2ee7f25bac8d7c9c6e2123c24c381dacf84c2aed9144b8ac069ca"
},
"downloads": -1,
"filename": "ensures-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "07a3535f61b5152231dd06d0d6707afd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 29694,
"upload_time": "2025-09-10T00:13:49",
"upload_time_iso_8601": "2025-09-10T00:13:49.694975Z",
"url": "https://files.pythonhosted.org/packages/73/c6/3c3b7edf647732849de54d1dc2629a80423c2441f7451a9773594f286a87/ensures-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f28ab0a59612bc6765df516939ff80453e7ef1c4530d3e199d4ef7f1d71720c0",
"md5": "27d917806fc1d98e621943b2e992cf8a",
"sha256": "57620b48bc2a6e91d1ac766a82bb1df89cfa82830b7a6442845aa6f19737dd37"
},
"downloads": -1,
"filename": "ensures-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "27d917806fc1d98e621943b2e992cf8a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 28029,
"upload_time": "2025-09-10T00:13:51",
"upload_time_iso_8601": "2025-09-10T00:13:51.186894Z",
"url": "https://files.pythonhosted.org/packages/f2/8a/b0a59612bc6765df516939ff80453e7ef1c4530d3e199d4ef7f1d71720c0/ensures-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-10 00:13:51",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "brunodantas",
"github_project": "ensures",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "ensures"
}