Provide design-by-contract with informative violation messages
Project description
icontract
=========
icontract provides design-by-contract to Python3 with informative violation messages.
There exist a couple of contract libraries. However, at the time of this writing (July 2018), they all required the
programmer either to learn a new syntax (`PyContracts<https://pypi-hypernode.com/project/PyContracts/>`_) or to write
redundant condition descriptions (*e.g.*, `contracts<https://pypi-hypernode.com/project/contracts/>`_,
`covenant<https://github.com/kisielk/covenant>_`,
`dpcontracts<https://pypi-hypernode.com/project/dpcontracts/>`_,
`pyadbc<https://pypi-hypernode.com/project/pyadbc/>`_ and.
`pcd<https://pypi-hypernode.com/project/pcd>`_).
This library was strongly inspired by them, but we went a step further and use the
`meta<https://github.com/srossross/Meta>`_ programming library to infer violation messages from the code in order to
promote dont-repeat-yourself principle (`DRY<https://en.wikipedia.org/wiki/Don%27t_repeat_yourself`_) and spare the
programmer the tedious task of repeating the message that was already written in code.
We want this library to be used mainly in production code and let us spot both development and production bugs with
enough information. Therefore, we decided to implement only the pre-conditions and post-conditions which require
little overhead, and left out intentionally the class invariants. Class invariants seem to us tricky to grasp (
for example, depending on the design class invariants may hold only at the first call of the public function, but
not in the private functions; or they may hold only at the first call to a method of a class, but not in the sequent
calls to other class methods *etc.*). The invariants hence need to come with an overhead which is generally impractical
for production systems.
Usage
=====
icontract provides two decorators, ``pre`` and ``post`` for pre-conditions and post-conditions, respectively.
The ``condition`` argument specifies the contract and is usually written in lambda notation. In post-conditions,
condition function receives a reserved parameter ``result`` corresponding to the result of the function. The condition
can take as input a subset of arguments required by the wrapped function. This allows for very succinct conditions.
You can provide an optional description by passing in ``description`` argument.
Whenever a violation occurs, ``ViolationError`` is raised. Its message includes:
* the human-readable representation of the condition,
* description (if supplied) and
* representation of all the arguments.
You can provide a custom representation function with the argument ``repr_args`` that needs to cover all the input
arguments (including ``result`` in post-conditions) of the condition function and return a string. If no representation
function was specified, the input arguments are represented by concatenation of ``__repr__`` on each one of them.
.. code-block:: python
>>> import icontract
>>> @icontract.pre(lambda x: x > 3)
... def some_func(x: int, y: int = 5)->None:
... pass
...
>>> some_func(x=5)
# Pre-condition violation
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.ViolationError: Precondition violated: x > 3: x was 1
# Pre-condition violation with a description
>>> @icontract.pre(lambda x: x > 3, "x must not be small")
... def some_func(x: int, y: int = 5) -> None:
... pass
...
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.ViolationError: Precondition violated: x must not be small: x > 3: x was 1
# Pre-condition violation with a custom representation function
>>> @icontract.pre(lambda x: x > 3, repr_args=lambda x: "x was {:03}".format(x))
... def some_func(x: int, y: int = 5) -> None:
... pass
...
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.ViolationError: Precondition violated: x > 3: x was 001
# Post-condition
>>> @icontract.post(lambda result, x: result > x)
... def some_func(x: int, y: int = 5) -> int:
... return x - y
...
>>> some_func(x=10)
Traceback (most recent call last):
...
icontract.ViolationError: Post-condition violated: result > x: result was 5: x was 10
Installation
============
* Install icontract with pip:
.. code-block:: bash
pip3 install icontract
Development
===========
* Check out the repository.
* In the repository root, create the virtual environment:
.. code-block:: bash
python3 -m venv venv3
* Activate the virtual environment:
.. code-block:: bash
source venv3/bin/activate
* Install the development dependencies:
.. code-block:: bash
pip3 install -e .[dev]
* We use tox for testing and packaging the distribution. Run:
.. code-block:: bash
tox
* We also provide a set of pre-commit checks that lint and check code for formatting. Run them locally from an activated
virtual environment with development dependencies:
.. code-block:: bash
./precommit.py
* The pre-commit script can also automatically format the code:
.. code-block:: bash
./precommit.py --overwrite
Versioning
==========
We follow `Semantic Versioning <http://semver.org/spec/v1.0.0.html>`_. The version X.Y.Z indicates:
* X is the major version (backward-incompatible),
* Y is the minor version (backward-compatible), and
* Z is the patch version (backward-compatible bug fix).
=========
icontract provides design-by-contract to Python3 with informative violation messages.
There exist a couple of contract libraries. However, at the time of this writing (July 2018), they all required the
programmer either to learn a new syntax (`PyContracts<https://pypi-hypernode.com/project/PyContracts/>`_) or to write
redundant condition descriptions (*e.g.*, `contracts<https://pypi-hypernode.com/project/contracts/>`_,
`covenant<https://github.com/kisielk/covenant>_`,
`dpcontracts<https://pypi-hypernode.com/project/dpcontracts/>`_,
`pyadbc<https://pypi-hypernode.com/project/pyadbc/>`_ and.
`pcd<https://pypi-hypernode.com/project/pcd>`_).
This library was strongly inspired by them, but we went a step further and use the
`meta<https://github.com/srossross/Meta>`_ programming library to infer violation messages from the code in order to
promote dont-repeat-yourself principle (`DRY<https://en.wikipedia.org/wiki/Don%27t_repeat_yourself`_) and spare the
programmer the tedious task of repeating the message that was already written in code.
We want this library to be used mainly in production code and let us spot both development and production bugs with
enough information. Therefore, we decided to implement only the pre-conditions and post-conditions which require
little overhead, and left out intentionally the class invariants. Class invariants seem to us tricky to grasp (
for example, depending on the design class invariants may hold only at the first call of the public function, but
not in the private functions; or they may hold only at the first call to a method of a class, but not in the sequent
calls to other class methods *etc.*). The invariants hence need to come with an overhead which is generally impractical
for production systems.
Usage
=====
icontract provides two decorators, ``pre`` and ``post`` for pre-conditions and post-conditions, respectively.
The ``condition`` argument specifies the contract and is usually written in lambda notation. In post-conditions,
condition function receives a reserved parameter ``result`` corresponding to the result of the function. The condition
can take as input a subset of arguments required by the wrapped function. This allows for very succinct conditions.
You can provide an optional description by passing in ``description`` argument.
Whenever a violation occurs, ``ViolationError`` is raised. Its message includes:
* the human-readable representation of the condition,
* description (if supplied) and
* representation of all the arguments.
You can provide a custom representation function with the argument ``repr_args`` that needs to cover all the input
arguments (including ``result`` in post-conditions) of the condition function and return a string. If no representation
function was specified, the input arguments are represented by concatenation of ``__repr__`` on each one of them.
.. code-block:: python
>>> import icontract
>>> @icontract.pre(lambda x: x > 3)
... def some_func(x: int, y: int = 5)->None:
... pass
...
>>> some_func(x=5)
# Pre-condition violation
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.ViolationError: Precondition violated: x > 3: x was 1
# Pre-condition violation with a description
>>> @icontract.pre(lambda x: x > 3, "x must not be small")
... def some_func(x: int, y: int = 5) -> None:
... pass
...
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.ViolationError: Precondition violated: x must not be small: x > 3: x was 1
# Pre-condition violation with a custom representation function
>>> @icontract.pre(lambda x: x > 3, repr_args=lambda x: "x was {:03}".format(x))
... def some_func(x: int, y: int = 5) -> None:
... pass
...
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.ViolationError: Precondition violated: x > 3: x was 001
# Post-condition
>>> @icontract.post(lambda result, x: result > x)
... def some_func(x: int, y: int = 5) -> int:
... return x - y
...
>>> some_func(x=10)
Traceback (most recent call last):
...
icontract.ViolationError: Post-condition violated: result > x: result was 5: x was 10
Installation
============
* Install icontract with pip:
.. code-block:: bash
pip3 install icontract
Development
===========
* Check out the repository.
* In the repository root, create the virtual environment:
.. code-block:: bash
python3 -m venv venv3
* Activate the virtual environment:
.. code-block:: bash
source venv3/bin/activate
* Install the development dependencies:
.. code-block:: bash
pip3 install -e .[dev]
* We use tox for testing and packaging the distribution. Run:
.. code-block:: bash
tox
* We also provide a set of pre-commit checks that lint and check code for formatting. Run them locally from an activated
virtual environment with development dependencies:
.. code-block:: bash
./precommit.py
* The pre-commit script can also automatically format the code:
.. code-block:: bash
./precommit.py --overwrite
Versioning
==========
We follow `Semantic Versioning <http://semver.org/spec/v1.0.0.html>`_. The version X.Y.Z indicates:
* X is the major version (backward-incompatible),
* Y is the minor version (backward-compatible), and
* Z is the patch version (backward-compatible bug fix).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
icontract-1.0.0.tar.gz
(5.1 kB
view details)
File details
Details for the file icontract-1.0.0.tar.gz
.
File metadata
- Download URL: icontract-1.0.0.tar.gz
- Upload date:
- Size: 5.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.11.0 pkginfo/1.4.2 requests/2.18.4 setuptools/20.10.1 requests-toolbelt/0.8.0 tqdm/4.24.0 CPython/3.5.2+
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 568958d5d2fc498ab4013da3d887811f774b1f1420b70a321ed194460ecbc28b |
|
MD5 | cd8d6c2ff809b2fce931167307e8030a |
|
BLAKE2b-256 | 00150b9a75566a82385c32d8c802fe06a63456d5667493a5b365b4b485007321 |