Design-by-contract in Python3 with informative violation messages and inheritance

Overview

icontract

Continuous integration https://coveralls.io/repos/github/Parquery/icontract/badge.svg?branch=master PyPI - version

PyPI - Python Version

Documentation Gitter chat

icontract provides design-by-contract to Python3 with informative violation messages and inheritance.

It also gives a base for a flourishing of a wider ecosystem:

Related Projects

There exist a couple of contract libraries. However, at the time of this writing (September 2018), they all required the programmer either to learn a new syntax (PyContracts) or to write redundant condition descriptions ( e.g., contracts, covenant, deal, dpcontracts, pyadbc and pcd).

This library was strongly inspired by them, but we go two steps further.

First, our violation message on contract breach are much more informative. The message includes the source code of the contract condition as well as variable values at the time of the breach. This promotes don't-repeat-yourself principle (DRY) and spare the programmer the tedious task of repeating the message that was already written in code.

Second, icontract allows inheritance of the contracts and supports weakining of the preconditions as well as strengthening of the postconditions and invariants. Notably, weakining and strengthening of the contracts is a feature indispensable for modeling many non-trivial class hierarchies. Please see Section Inheritance. To the best of our knowledge, there is currently no other Python library that supports inheritance of the contracts in a correct way.

In the long run, we hope that design-by-contract will be adopted and integrated in the language. Consider this library a work-around till that happens. You might be also interested in the archived discussion on how to bring design-by-contract into Python language on python-ideas mailing list.

Teasers

We give a couple of teasers here to motivate the library. Please see the documentation available on icontract.readthedocs.io for a full scope of its capabilities.

The script is also available as a repl.it post.

None: ... pass ... >>> some_func(x=1) Traceback (most recent call last): ... icontract.errors.ViolationError: File , line 1 in : x must not be small: x > 3: x was 1 y was 5 # Pre-condition violation with more complex values >>> class B: ... def __init__(self) -> None: ... self.x = 7 ... ... def y(self) -> int: ... return 2 ... ... def __repr__(self) -> str: ... return "instance of B" ... >>> class A: ... def __init__(self) -> None: ... self.b = B() ... ... def __repr__(self) -> str: ... return "instance of A" ... >>> SOME_GLOBAL_VAR = 13 >>> @icontract.require(lambda a: a.b.x + a.b.y() > SOME_GLOBAL_VAR) ... def some_func(a: A) -> None: ... pass ... >>> an_a = A() >>> some_func(an_a) Traceback (most recent call last): ... icontract.errors.ViolationError: File , line 1 in : a.b.x + a.b.y() > SOME_GLOBAL_VAR: SOME_GLOBAL_VAR was 13 a was instance of A a.b was instance of B a.b.x was 7 a.b.y() was 2 # Post-condition >>> @icontract.ensure(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.errors.ViolationError: File , line 1 in : result > x: result was 5 x was 10 y was 5 # Pre-conditions fail before post-conditions. >>> @icontract.ensure(lambda result, x: result > x) ... @icontract.require(lambda x: x > 3, "x must not be small") ... def some_func(x: int, y: int = 5) -> int: ... return x - y ... >>> some_func(x=3) Traceback (most recent call last): ... icontract.errors.ViolationError: File , line 2 in : x must not be small: x > 3: x was 3 y was 5 # Invariant >>> @icontract.invariant(lambda self: self.x > 0) ... class SomeClass: ... def __init__(self) -> None: ... self.x = -1 ... ... def __repr__(self) -> str: ... return "an instance of SomeClass" ... >>> some_instance = SomeClass() Traceback (most recent call last): ... icontract.errors.ViolationError: File , line 1 in : self.x > 0: self was an instance of SomeClass self.x was -1">
>>> import icontract

>>> @icontract.require(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.errors.ViolationError: File <doctest README.rst[1]>, line 1 in <module>:
x > 3:
x was 1
y was 5

# Pre-condition violation with a description
>>> @icontract.require(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.errors.ViolationError: File <doctest README.rst[4]>, line 1 in <module>:
x must not be small: x > 3:
x was 1
y was 5

# Pre-condition violation with more complex values
>>> class B:
...     def __init__(self) -> None:
...         self.x = 7
...
...     def y(self) -> int:
...         return 2
...
...     def __repr__(self) -> str:
...         return "instance of B"
...
>>> class A:
...     def __init__(self) -> None:
...         self.b = B()
...
...     def __repr__(self) -> str:
...         return "instance of A"
...
>>> SOME_GLOBAL_VAR = 13
>>> @icontract.require(lambda a: a.b.x + a.b.y() > SOME_GLOBAL_VAR)
... def some_func(a: A) -> None:
...     pass
...
>>> an_a = A()
>>> some_func(an_a)
Traceback (most recent call last):
  ...
icontract.errors.ViolationError: File <doctest README.rst[9]>, line 1 in <module>:
a.b.x + a.b.y() > SOME_GLOBAL_VAR:
SOME_GLOBAL_VAR was 13
a was instance of A
a.b was instance of B
a.b.x was 7
a.b.y() was 2

# Post-condition
>>> @icontract.ensure(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.errors.ViolationError: File <doctest README.rst[12]>, line 1 in <module>:
result > x:
result was 5
x was 10
y was 5


# Pre-conditions fail before post-conditions.
>>> @icontract.ensure(lambda result, x: result > x)
... @icontract.require(lambda x: x > 3, "x must not be small")
... def some_func(x: int, y: int = 5) -> int:
...    return x - y
...
>>> some_func(x=3)
Traceback (most recent call last):
  ...
icontract.errors.ViolationError: File <doctest README.rst[14]>, line 2 in <module>:
x must not be small: x > 3:
x was 3
y was 5

# Invariant
>>> @icontract.invariant(lambda self: self.x > 0)
... class SomeClass:
...     def __init__(self) -> None:
...         self.x = -1
...
...     def __repr__(self) -> str:
...         return "an instance of SomeClass"
...
>>> some_instance = SomeClass()
Traceback (most recent call last):
 ...
icontract.errors.ViolationError: File <doctest README.rst[16]>, line 1 in <module>:
self.x > 0:
self was an instance of SomeClass
self.x was -1

Installation

  • Install icontract with pip:
pip3 install icontract

Versioning

We follow Semantic Versioning. 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).
Comments
  • "Soft" contracts

    This is a proposal to introduce new functionality, "soft contracts".

    Problem

    Sometimes you want to track unwanted behaviour but instead of getting an exception, you want to log it.

    Say, your code is already in production and nothing fatal happens when this unwanted behaviour occurs. You want to track and eliminate it, but if you use the usual contracts, the users would suffer - the execution will stop at the contract point with an exception. Thus trying to catch a minor unwanted behaviour via introducing a contract would cause a bigger problem.

    So, you insert logging code into the body of your function. But now the code is less readable because of the "service code injections". The code would be cleaner if you used decorators similar to what icontract provides.

    Proposal

    Introduce a set of decorators named require_soft, ensure_soft, invariant_soft that would log an error (or a warning?) in case the condition is breached, but keep on running.

    This way the users are not harmed and the developer can track the bugs through inspecting the logs.

    opened by leshchenko1979 16
  • require decorator removes type annotations for mypy

    require decorator removes type annotations for mypy

    $ cat ic.py  
    from icontract import require
    
    @require(lambda x: x > 0)
    def f1(x: int): return x
    
    def f2(x: int): return 0
    
    f1("this is wrong")
    f2("this is too")
    
    $ mypy ic.py              
    ic.py:9: error: Argument 1 to "f2" has incompatible type "str"; expected "int"
    

    Both function calls are invalid types but mypy only sees the call as f2 as wrong. The decorator loses the type annotations?

    Related https://github.com/python/mypy/issues/3157

    opened by jamescasbon 12
  • AttributeError in contract caused by method call in constructor

    AttributeError in contract caused by method call in constructor

    When a method is called in the constructor, an AttributeError is raised in the contract. Here is a reproducer:

    from icontract import invariant
    
    
    @invariant(lambda self: all(" " not in part for part in self.parts))
    class ID:
        def __init__(self, identifier: str) -> None:
            self.parts = identifier.split(self.separator())
    
        def separator(self) -> str:
            return "."
    
    
    ID("A")
    
    $ python test.py  
    Traceback (most recent call last):
      File "test.py", line 14, in <module>
        ID("A")
      File "/home/tr/.local/lib/python3.8/site-packages/icontract/_checkers.py", line 461, in wrapper
        result = func(*args, **kwargs)
      File "test.py", line 7, in __init__
        self.parts = identifier.split(self.separator)
      File "/home/tr/.local/lib/python3.8/site-packages/icontract/_checkers.py", line 498, in wrapper
        _assert_invariant(contract=contract, instance=instance)
      File "/home/tr/.local/lib/python3.8/site-packages/icontract/_checkers.py", line 162, in _assert_invariant
        check = contract.condition(self=instance)
      File "test.py", line 4, in <lambda>
        @invariant(lambda self: all(" " not in part for part in self.parts))
    AttributeError: 'ID' object has no attribute 'parts'
    

    The contract works correctly when self.separator() is replaced by a string literal.

    Versions

    icontract 2.3.4 asttokens 2.0.4 Python 3.8.5

    opened by treiher 11
  • *args and **kwargs not supported

    *args and **kwargs not supported

    Given the following code snippet:

    from icontract import require
    
    
    def test_args():
        @require(lambda *args: args)
        def args(*args, **kwargs):
            pass
        args(0, x=0)
    
    
    def test_kwargs():
        @require(lambda **kwargs: kwargs)
        def args(*args, **kwargs):
            pass
        args(0, x=0)
    
    
    def test_both():
        @require(lambda *args, **kwargs: args and kwargs)
        def args(*args, **kwargs):
            pass
        args(0, x=0)
    

    I get errors saying that precondition arguments could not be set (from _checkers.py:114).

    Unless I've missed it, the README didn't explicitly state that * and ** aren't supported. My use case is a rather generic decorator applied to some endpoints. It shouldn't matter how these endpoints are called, but they must contain a request (for the decorator to do its magic), for which I want to create a contract.

    Some observations:

    • @require(lambda args: ...) without the asterisk only passes the first argument supplied to the function to the check (i.e. 0, not [0])
    • @require(lambda kwargs: ...) without the asterisks raises the same error

    I would gladly help with fixing/implementing this since I believe every language today should provide tools for DBC, and your library does a good job. Any thoughts on the feasibility of this? :)

    opened by ghost 11
  • Transpiler

    Transpiler

    (From python-ideas list in thread: "old" values in postconditions)

    What about a tool that converts contracts back and forth to readable form on IDE save/load with the following syntax:

    with contracts:
        with preconditions:
            assert arg1 < arg2
    
        with snapshot as S:
            S.var1 = some_func(arg1)
            with postconditions, \
                 resultie as result:
                     # result would be annotated with "# type:" 
                     # if return type is annotated.
                     assert arg1 < S.var1 < arg2, \
                         "Some contract description"
                      
                     # if not (...) followed by a raise statement 
                     # allows for custom exceptions
                     if not (arg1 > arg2):
                         "another contract description"
                         raise SomeException("some message", arg1)
                     
                     # if (..) followed by a list of asserts or if-not-raises 
                     # allows for toggling contracts
                     if some_enabled_flag:
                         assert arg1 + 10 < arg2
                         assert arg2 > 0
                         if not some_func(arg1, arg2):
                             raise AnotherException("some message", var1, arg1, arg2)
    

    For classes:

    class SomeClass:
        with invariants,
            selfie as self: # type: SomeClass
                 assert 0 < self.x < sqrt(self.x)
    

    icontract.dummies would provide these dummy context managers (all of them would raise exceptions on enter so that the code can not run by accident). The converter would add/remove these imports automatically.

    The advantage: no variable shadowing, valid python code, autocomplete works in Pycharm, even mypy could be made to work. with contracts makes it easier and less error prone to group preconditions and postconditions. The converter would check that there is no "with contracts" in the body of the function except in the first statement (and the same for class invariants).

    Descriptions in asserts and if-not-raise must be string literals (without format() etc.).

    wontfix 
    opened by mristin 11
  • Invariant on a class changes the type of the class

    Invariant on a class changes the type of the class

    from icontract import invariant
    
    class TestClass1():
        test_int: int = 1
    
    reveal_type(TestClass1)
    # Type[TestClass1]
    
    @invariant(lambda self: self.test_int == 1)
    class TestClass2():
        test_int: int = 1
    
    reveal_type(TestClass2)
    # type
    
    opened by ciresnave 10
  • convert readme example into a script that can be easily copy/pasted

    convert readme example into a script that can be easily copy/pasted

    this might just be my personal preference but i feel that it's easy to run and work with the example this way. direct copy and paste into a script would allow you to run the example and step through each piece without losing information. i also added an example showing that "Pre-conditions fail before Post-conditions". that wasn't immediately obvious to me. of course the big assumption is that people would know how to handle the python debugger. i'd guess that more people are familiar with the terminal session. so perhaps this won't be accepted. but with some simple instructions, literally just, type "c" and press enter, you'll walk through each example while being able to inspect either the result or the exception that was raised for each scenario. enjoying testing out the library, thanks :-)

    opened by wgwz 10
  • fixed performance regression due to state

    fixed performance regression due to state

    This commit makes a couple of fixes to improve the computational efficiency of the contracts. There was a performance regression when the state was introduced (notably, ExitStack caused a lot of overhead).

    This commit also introduces benchmarking into the continuous integration (as part of the precommit.py script) so that we can continously monitor the efficiency in the future.

    Fixes #142 .

    opened by mristin 10
  • Failed to recompute the values of the contract condition

    Failed to recompute the values of the contract condition

    I have the following code:

    @ensure(
        lambda result: len(result) > 30_000, "Too few lines"
    )
    @ensure(
        lambda result: all(
            result[col].notna().sum() / len(result) > 0.3 for col in FILTER_FEATURES
        ),
        "Filter features are not filled in properly",
    )
    def load_listings(regions=None) -> pd.DataFrame:
    ...
    

    If the first contract fails, I'm getting a RuntimeError instead of a ViolationError:

    Traceback (most recent call last):
      File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 2070, in wsgi_app
        response = self.full_dispatch_request()
      File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1515, in full_dispatch_request
        rv = self.handle_user_exception(e)
      File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1513, in full_dispatch_request
        rv = self.dispatch_request()
      File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1499, in dispatch_request
        return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
      File "/workspace/main.py", line 43, in main
        listings = load_listings()
      File "/layers/google.python.pip/pip/lib/python3.9/site-packages/icontract/_checkers.py", line 646, in wrapper
        violation_error = _assert_postconditions(
      File "/layers/google.python.pip/pip/lib/python3.9/site-packages/icontract/_checkers.py", line 396, in _assert_postconditions
        exception = _create_violation_error(contract=contract, resolved_kwargs=resolved_kwargs)
      File "/layers/google.python.pip/pip/lib/python3.9/site-packages/icontract/_checkers.py", line 192, in _create_violation_error
        raise RuntimeError(''.join(parts)) from err
    RuntimeError: Failed to recompute the values of the contract condition:
    File /workspace/main.py, line 65 in <module>:
    Too few lines: lambda result: len(result) > 30_000
    

    I also made the second one fail with pytest, and the test output was:

    ./test_minos.py::test_loading Failed: [undefined]RuntimeError: Failed to recompute the values of the contract condition:
    File c:\Users\leshc\flipio\minos\main.py, line 68 in <module>:
    Filter features are not filled in properly: lambda result: all(
            result[col].notna().sum() / len(result) > 0.3 for col in FILTER_FEATURES
        )
    contract = <icontract._types.Contract object at 0x000001C5B46DACA0>
    resolved_kwargs = {'_ARGS': (), '_KWARGS': {}, 'regions': None, 'result':        repair  house_material  windows_type  room_type
    0      ...         NaN           NaN        NaN
    39999     NaN             NaN           NaN        NaN
    
    [40000 rows x 4 columns]}
    
        def _create_violation_error(contract: Contract, resolved_kwargs: Mapping[str, Any]) -> BaseException:
            """Create the violation error based on the violated contract."""
            exception = None  # type: Optional[BaseException]
        
            if contract.error is None:
                try:
    >               msg = icontract._represent.generate_message(contract=contract, resolved_kwargs=resolved_kwargs)
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_checkers.py:181: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    contract = <icontract._types.Contract object at 0x000001C5B46DACA0>
    resolved_kwargs = {'_ARGS': (), '_KWARGS': {}, 'regions': None, 'result':        repair  house_material  windows_type  room_type
    0      ...         NaN           NaN        NaN
    39999     NaN             NaN           NaN        NaN
    
    [40000 rows x 4 columns]}
    
        def generate_message(contract: Contract, resolved_kwargs: Mapping[str, Any]) -> str:
            """Generate the message upon contract violation."""
            parts = []  # type: List[str]
        
            if contract.location is not None:
                parts.append("{}:\n".format(contract.location))
        
            if contract.description is not None:
                parts.append("{}: ".format(contract.description))
        
            lambda_inspection = None  # type: Optional[ConditionLambdaInspection]
            if not is_lambda(a_function=contract.condition):
                condition_text = contract.condition.__name__
            else:
                # We need to extract the source code corresponding to the decorator since inspect.getsource() is broken with
                # lambdas.
                lambda_inspection = inspect_lambda_condition(condition=contract.condition)
                assert lambda_inspection is not None, \
                    "Unexpected no lambda inspection for condition: {}".format(contract.condition)
                condition_text = lambda_inspection.text
        
            parts.append(condition_text)
        
    >       repr_vals = repr_values(
                condition=contract.condition,
                lambda_inspection=lambda_inspection,
                resolved_kwargs=resolved_kwargs,
                a_repr=contract._a_repr)
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_represent.py:542: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    condition = <function <lambda> at 0x000001C5B46E48B0>
    lambda_inspection = <icontract._represent.ConditionLambdaInspection object at 0x000001C5B484EF40>
    resolved_kwargs = {'_ARGS': (), '_KWARGS': {}, 'regions': None, 'result':        repair  house_material  windows_type  room_type
    0      ...         NaN           NaN        NaN
    39999     NaN             NaN           NaN        NaN
    
    [40000 rows x 4 columns]}
    a_repr = <reprlib.Repr object at 0x000001C5A34D9BB0>
    
        def repr_values(condition: Callable[..., bool], lambda_inspection: Optional[ConditionLambdaInspection],
                        resolved_kwargs: Mapping[str, Any], a_repr: reprlib.Repr) -> List[str]:
            """
            Represent function arguments and frame values in the error message on contract breach.
        
            :param condition: condition function of the contract
            :param lambda_inspection:
                inspected lambda AST node corresponding to the condition function (None if the condition was not given as a
                lambda function)
            :param resolved_kwargs: arguments put in the function call
            :param a_repr: representation instance that defines how the values are represented.
            :return: list of value representations
            """
            # Hide _ARGS and _KWARGS if they are not part of the condition for better readability
            if '_ARGS' in resolved_kwargs or '_KWARGS' in resolved_kwargs:
                parameters = inspect.signature(condition).parameters
                malleable_kwargs = cast(
                    MutableMapping[str, Any],
                    resolved_kwargs.copy()  # type: ignore
                )
        
                if '_ARGS' not in parameters:
                    malleable_kwargs.pop('_ARGS', None)
        
                if '_KWARGS' not in parameters:
                    malleable_kwargs.pop('_KWARGS', None)
        
                selected_kwargs = cast(Mapping[str, Any], malleable_kwargs)
            else:
                selected_kwargs = resolved_kwargs
        
            # Don't use ``resolved_kwargs`` from this point on.
            # ``selected_kwargs`` is meant to be used instead for better readability of error messages.
        
            if is_lambda(a_function=condition):
                assert lambda_inspection is not None, "Expected a lambda inspection when given a condition as a lambda function"
            else:
                assert lambda_inspection is None, "Expected no lambda inspection in a condition given as a non-lambda function"
        
            reprs = None  # type: Optional[MutableMapping[str, Any]]
        
            if lambda_inspection is not None:
                variable_lookup = collect_variable_lookup(condition=condition, resolved_kwargs=selected_kwargs)
        
                recompute_visitor = icontract._recompute.Visitor(variable_lookup=variable_lookup)
        
    >           recompute_visitor.visit(node=lambda_inspection.node.body)
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_represent.py:463: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.Call object at 0x000001C5B486ABB0>
    
        def visit(self, node):
            """Visit a node."""
            method = 'visit_' + node.__class__.__name__
            visitor = getattr(self, method, self.generic_visit)
    >       return visitor(node)
    
    C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2032.0_x64__qbz5n2kfra8p0\lib\ast.py:407: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.Call object at 0x000001C5B486ABB0>
    
        def visit_Call(self, node: ast.Call) -> Any:
            """Visit the function and the arguments and finally make the function call with them."""
            func = self.visit(node=node.func)
        
            # Please see "NOTE ABOUT PLACEHOLDERS AND RE-COMPUTATION"
            if func == PLACEHOLDER:
                return PLACEHOLDER
        
            if not callable(func):
                raise ValueError("Unexpected call to a non-calllable during the re-computation: {}".format(func))
        
            if inspect.iscoroutinefunction(func):
                raise ValueError(
                    ("Unexpected coroutine function {} as a condition of a contract. "
                     "You must specify your own error if the condition of your contract is a coroutine function."
                     ).format(func))
        
            # Short-circuit tracing the all quantifier over a generator expression
            # yapf: disable
            if (
                    func == builtins.all  # pylint: disable=comparison-with-callable
                    and len(node.args) == 1
                    and isinstance(node.args[0], ast.GeneratorExp)
            ):
                # yapf: enable
    >           result = self._trace_all_with_generator(func=func, node=node)
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_recompute.py:567: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    func = <built-in function all>, node = <ast.Call object at 0x000001C5B486ABB0>
    
        def _trace_all_with_generator(self, func: Callable[..., Any], node: ast.Call) -> Any:
            """Re-write the all call with for loops to trace the first offending item, if any."""
            assert func == builtins.all  # pylint: disable=comparison-with-callable
            assert len(node.args) == 1
            assert isinstance(node.args[0], ast.GeneratorExp)
        
            # Try the happy path first
        
            # Please see "NOTE ABOUT PLACEHOLDERS AND RE-COMPUTATION"
    >       recomputed_arg = self.visit(node=node.args[0])
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_recompute.py:733: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.GeneratorExp object at 0x000001C5B486AAC0>
    
        def visit(self, node):
            """Visit a node."""
            method = 'visit_' + node.__class__.__name__
            visitor = getattr(self, method, self.generic_visit)
    >       return visitor(node)
    
    C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2032.0_x64__qbz5n2kfra8p0\lib\ast.py:407: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.GeneratorExp object at 0x000001C5B486AAC0>
    
        def visit_GeneratorExp(self, node: ast.GeneratorExp) -> Any:
            """Compile the generator expression as a function and call it."""
            # NOTE ABOUT PLACEHOLDERS AND RE-COMPUTATION:
            # Re-computing the comprehensions would be too slow. Therefore we re-compile the comprehension and call
            # the compiled code directly.
            #
            # However, we still want to report the values of the variables unrelated to the comprehension back
            # to the user. Therefore we introduce PLACEHOLDER's and propagate them through re-computation in all
            # the visit methods.
        
            # The following visits propagate the visitation to descendant nodes.
            # However, as we re-compute the comprehension *via* re-compilation & execution,
            # the results of the visits are all PLACEHOLDER's.
        
            # NOTE ABOUT NAME #x1F812 VALUE STACKING:
            # We need to make a copy of name #x1F812 value mapping since we need to add targets as placeholders
            # while we visit the comprehension. For example, as we compute comprehensions through re-compilation
            # and not through manual re-computation, we can not re-compute nested comprehensions.
            #
            # However, when our visit of comprehension is finished, the targets are not valid any more,
            # so we need to remove them from the mapping.
            #
            # Finally, we compute the comprehension with the original name #x1F812 value mapping by using
            # re-compilation. This final step is skipped if any of the names involved in the comprehension are
            # PLACEHOLDER's.
        
            old_name_to_value = copy.copy(self._name_to_value)
            for target_name in _collect_stored_names([generator.target for generator in node.generators]):
                self._name_to_value[target_name] = PLACEHOLDER
        
    >       self.visit(node.elt)
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_recompute.py:846: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.Compare object at 0x000001C5B486AB20>
    
        def visit(self, node):
            """Visit a node."""
            method = 'visit_' + node.__class__.__name__
            visitor = getattr(self, method, self.generic_visit)
    >       return visitor(node)
    
    C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2032.0_x64__qbz5n2kfra8p0\lib\ast.py:407: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.Compare object at 0x000001C5B486AB20>
    
        def visit_Compare(self, node: ast.Compare) -> Any:
            """Recursively visit the comparators and apply the operations on them."""
    >       left = self.visit(node=node.left)
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_recompute.py:499: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.BinOp object at 0x000001C5B486AA00>
    
        def visit(self, node):
            """Visit a node."""
            method = 'visit_' + node.__class__.__name__
            visitor = getattr(self, method, self.generic_visit)
    >       return visitor(node)
    
    C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2032.0_x64__qbz5n2kfra8p0\lib\ast.py:407: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.BinOp object at 0x000001C5B486AA00>
    
        def visit_BinOp(self, node: ast.BinOp) -> Any:
            """Recursively visit the left and right operand, respectively, and apply the operation on the results."""
            left = self.visit(node=node.left)
    >       right = self.visit(node=node.right)
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_recompute.py:441: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.Call object at 0x000001C5B486A8B0>
    
        def visit(self, node):
            """Visit a node."""
            method = 'visit_' + node.__class__.__name__
            visitor = getattr(self, method, self.generic_visit)
    >       return visitor(node)
    
    C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2032.0_x64__qbz5n2kfra8p0\lib\ast.py:407: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self = <icontract._recompute.Visitor object at 0x000001C5B48575E0>
    node = <ast.Call object at 0x000001C5B486A8B0>
    
        def visit_Call(self, node: ast.Call) -> Any:
            """Visit the function and the arguments and finally make the function call with them."""
            func = self.visit(node=node.func)
        
            # Please see "NOTE ABOUT PLACEHOLDERS AND RE-COMPUTATION"
            if func == PLACEHOLDER:
                return PLACEHOLDER
        
            if not callable(func):
                raise ValueError("Unexpected call to a non-calllable during the re-computation: {}".format(func))
        
            if inspect.iscoroutinefunction(func):
                raise ValueError(
                    ("Unexpected coroutine function {} as a condition of a contract. "
                     "You must specify your own error if the condition of your contract is a coroutine function."
                     ).format(func))
        
            # Short-circuit tracing the all quantifier over a generator expression
            # yapf: disable
            if (
                    func == builtins.all  # pylint: disable=comparison-with-callable
                    and len(node.args) == 1
                    and isinstance(node.args[0], ast.GeneratorExp)
            ):
                # yapf: enable
                result = self._trace_all_with_generator(func=func, node=node)
        
                if result is PLACEHOLDER:
                    return PLACEHOLDER
            else:
                args = []  # type: List[Any]
                for arg_node in node.args:
                    if isinstance(arg_node, ast.Starred):
                        args.extend(self.visit(node=arg_node))
                    else:
                        args.append(self.visit(node=arg_node))
        
                kwargs = dict()  # type: Dict[Union[str, Placeholder], Any]
                for keyword in node.keywords:
                    if keyword.arg is None:
                        kw = self.visit(node=keyword.value)
                        for key, val in kw.items():
                            kwargs[key] = val
        
                    else:
                        kwargs[keyword.arg] = self.visit(node=keyword.value)
        
                # Please see "NOTE ABOUT PLACEHOLDERS AND RE-COMPUTATION"
    >           if PLACEHOLDER in args or PLACEHOLDER in kwargs or PLACEHOLDER in kwargs.values():
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_recompute.py:590: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    self =        repair  house_material  windows_type  room_type
    0       False           False         False      False
    1       ...        False         False      False
    39999   False           False         False      False
    
    [40000 rows x 4 columns]
    
        @final
        def __nonzero__(self):
    >       raise ValueError(
                f"The truth value of a {type(self).__name__} is ambiguous. "
                "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
            )
    E       ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\pandas\core\generic.py:1537: ValueError
    
    The above exception was the direct cause of the following exception:
    
    monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x000001C5B46EC0D0>
    
        def test_loading(monkeypatch):
            def fake_load_psql(*args, **kwargs):
                return pd.DataFrame([{} for _ in range(40_000)], columns=FILTER_FEATURES)
        
            monkeypatch.setattr(main, "load_psql", fake_load_psql)
    >       load_listings()
    
    test_minos.py:22: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_checkers.py:646: in wrapper
        violation_error = _assert_postconditions(
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_checkers.py:396: in _assert_postconditions
        exception = _create_violation_error(contract=contract, resolved_kwargs=resolved_kwargs)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
    contract = <icontract._types.Contract object at 0x000001C5B46DACA0>
    resolved_kwargs = {'_ARGS': (), '_KWARGS': {}, 'regions': None, 'result':        repair  house_material  windows_type  room_type
    0      ...         NaN           NaN        NaN
    39999     NaN             NaN           NaN        NaN
    
    [40000 rows x 4 columns]}
    
        def _create_violation_error(contract: Contract, resolved_kwargs: Mapping[str, Any]) -> BaseException:
            """Create the violation error based on the violated contract."""
            exception = None  # type: Optional[BaseException]
        
            if contract.error is None:
                try:
                    msg = icontract._represent.generate_message(contract=contract, resolved_kwargs=resolved_kwargs)
                except Exception as err:
                    parts = ["Failed to recompute the values of the contract condition:\n"]
                    if contract.location is not None:
                        parts.append("{}:\n".format(contract.location))
        
                    if contract.description is not None:
                        parts.append("{}: ".format(contract.description))
        
                    parts.append(icontract._represent.represent_condition(condition=contract.condition))
        
    >               raise RuntimeError(''.join(parts)) from err
    E               RuntimeError: Failed to recompute the values of the contract condition:
    E               File c:\Users\leshc\flipio\minos\main.py, line 68 in <module>:
    E               Filter features are not filled in properly: lambda result: all(
    E                       result[col].notna().sum() / len(result) > 0.3 for col in FILTER_FEATURES
    E                   )
    
    ..\..\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\icontract\_checkers.py:192: RuntimeError
    
    opened by leshchenko1979 9
  • Runtime type validation?

    Runtime type validation?

    We are assessing a switch from typeguard to icontract for stricter runtime validation. However, I don't see anything akin to typeguard's @typechecked decorator. Correct me if I'm wrong, is the only way to do runtime type validation by making an @icontract.require(lambda arg: isinstance(arg, <type>) for all args?

    opened by crypdick 9
  • RecursionError due to contract checking during contract checking

    RecursionError due to contract checking during contract checking

    from typing import Any
    
    from icontract import DBC, ensure
    
    
    class Dimension(DBC):
        @ensure(lambda self, label, result: self.label(result) == label)
        def index(self, label: Any) -> int:
            return int(label)
    
        @ensure(lambda self, index, result: self.index(result) == index)
        def label(self, index: int) -> Any:
            return str(index)
    
    
    x = Dimension()
    print(x.label(0))
    

    This code results in a RecursionError, since while checking the postcondition for label the method index is invoked which triggers the check for the postcondition of index.

    It would be great if it were possible to suspend the checking of any other contracts while checking one contract, either by default or as a option when specifying the contract.

    opened by markusschmaus 9
  • License perms

    License perms

    When installing via pip. The license is placed in /usr/local

    ERROR: Could not install packages due to an OSError: [Errno 13] Permission denied: '/usr/local/LICENSE.txt'
    Consider using the `--user` option or check the permissions.
    

    Maybe consider rename for global installation too LICENSE.icontract.txt (or subdirectory). Just a suggestion, keep up the good work!

    opened by ronaldpetty 6
  • Question/Feature request: Iterable usage in `require` and `snapshot` decorators

    Question/Feature request: Iterable usage in `require` and `snapshot` decorators

    Question

    How do I use Iterable in a @snapshot or in a @require decorator? I didn't find any hints in the documentation so I assume I either used them wrong or didn't understand a core concept. Otherwise, I would like to propose a feature request 😀

    Examples for @ensure

    If I try to take a snapshot of an Iterable, it is not possible since snapshot consumes it. Using the file iter_in_ensure.py

    # ––– file iter_in_ensure.py
    from collections.abc import Iterable
    from icontract import ensure, snapshot
    from more_itertools import always_iterable
    
    
    @snapshot(lambda i: list(i))
    @ensure(lambda result, OLD: set(OLD.i) == set(result))
    def ensure_iter(i: Iterable[int]) -> list[int]:
        return list(i)
    
    
    assert 1 == len(ensure_iter(always_iterable(1)))
    

    in a python environment where icontract and more_itertools is included, the error message is:

    $ python iter_in_ensure.py
    Traceback (most recent call last):
      File "iter_in_ensure.py", line 13, in <module>
        assert 1 == len(ensure_iter(always_iterable(1)))
      File "/…/icontract/_checkers.py", line 649, in wrapper
        raise violation_error
    icontract.errors.ViolationError: File iter_in_ensure.py, line 8 in <module>:
    set(OLD.i) == set(result):
    OLD was a bunch of OLD values
    OLD.i was [1]
    i was <tuple_iterator object at 0x7fe0fe9afb20>
    result was []
    set(OLD.i) was {1}
    set(result) was set()
    

    showing that the @snapshot decorator already consumed the iterator, leaving an empty result back. A possible workaround is to use itertools.tee inside the function:

    # ––– file fixup_ensure.py
    from collections.abc import Iterable
    from icontract import ensure
    from itertools import tee
    from more_itertools import always_iterable
    
    
    @ensure(lambda result: set(result[0]) == set(result[1]))
    def ensure_iter(i: Iterable[int]) -> tuple[list[int], Iterable[int]]:
        tee0, tee1 = tee(i, 2)
        return list(tee0), tee1
    
    
    assert 1 == len(ensure_iter(always_iterable(1))[0])
    

    but that requires to change the functions's signature for usage in @ensure only which – at least in my opinion – contradicts icontract's philosophy.

    Examples for @require

    With the @require decorator, I even didn't find a workaround:

    # ––– file iter_in_require.py
    from collections.abc import Iterable
    from icontract import require
    from more_itertools import always_iterable
    
    
    @require(lambda i: 1 == len(list(i)))
    def require_iter(i: Iterable[int]) -> list[int]:
        return list(i)
    
    
    length = len(require_iter(always_iterable(1)))
    assert 1 == length, f"result length was {length}"
    

    results in

    $ python iter_in_require.py
    Traceback (most recent call last):
      File "iter_in_require.py", line 13, in <module>
        assert 1 == length, f"result length was {length}"
    AssertionError: result length was 0
    

    showing that @require already consumed the iterator and the function require_iter has no chance to access it again.

    Versions

    • Python: Python 3.10.4
    • more-itertools: 8.13.0
    • icontract: 2.6.1

    Feature pitch

    If I didn't miss anything, there are features missing for the @snapshot and the @require function decorators. I suggest to introduce additional arguments to disable iterator consumption.

    A possible example usage for @snapshot:

    from collections.abc import Iterable
    from icontract import ensure, snapshot
    from more_itertools import always_iterable
    
    
    @snapshot(lambda i: list(i), iter='i')  # <- new argument 'iter'
    @ensure(lambda result, OLD: set(OLD.i) == set(result))
    def ensure_iter(i: Iterable[int]) -> list[int]:
        return list(i)
    
    
    assert 1 == len(ensure_iter(always_iterable(1)))
    

    A possible example usage for @require:

    from collections.abc import Iterable
    from icontract import require
    from more_itertools import always_iterable
    
    
    @require(lambda i: 1 == len(list(i)), iter='i')  # <- new argument 'iter'
    def require_iter(i: Iterable[int]) -> list[int]:
        return list(i)
    
    
    length = len(require_iter(always_iterable(1)))
    assert 1 == length, f"result length was {length}"
    

    The new argument iter indicates to use an independent iterator. In @require's case, it forwards it to the decorated function.

    I'm aware that the proposed solution is not applicable to all iterables, but I'm still convinced it would pose an improvement.

    opened by claudio-ebel 4
  • icontract fails to restore class invariants at method exit

    icontract fails to restore class invariants at method exit

    icontract fails to restore class invariants at method exit:

    import icontract
    
    @icontract.invariant(lambda self: self.x > 0)
    class A:
        def __init__(self):
            self.x = 1
        def f(self):
            self.x = -1
            raise ValueError
    
    a = A()
    assert a.x > 0  # ok
    try:
        a.f()
    except ValueError:
        pass
    assert a.x > 0  # AssertionError
    

    This is contrary to what Bertrand Meyer prescribes in his 1992 seminal article Applying “Design by Contract”:

    Any exception handling, whether for resumption or for organized panic, should restore the invariant.

    Class invariants are the minimal guarantees in case of failure.

    opened by maggyero 3
  • Mypy fails to determine function's type in icontract.ensure()

    Mypy fails to determine function's type in icontract.ensure()

    Bug Report When a type-annotated function is (re-)used in its own postcondition icontract.ensure decorator, mypy is not able to determine its type. Since mypy does successfully infers the types of an annotated function before the function's actual definition, this bug is part of the icontract library and not mypy.

    To Reproduce

    1. Create a file “bug.py” with this content:
      # ––– file: bug.py –––
      from icontract import ensure
      
      
      @ensure(lambda a, b, result: result == myadd(b, a), "Commutativity violated!")
      def myadd(a: int, b: int) -> int:
          return a + b
      
    2. Use mypy on it
      $ mypy --config-file= bug.py 
      bug.py:5: error: Cannot determine type of "myadd"
      Found 1 error in 1 file (checked 1 source file)
      

    Expected Behavior In general, mypy does not have a problem with using an annotated function before its definition. To see this,

    1. Create a file “no_bug.py” with this content:
      # ––– file: no_bug.py –––
      
      
      def use_before() -> int:
          return myadd(1, 2)  # used before def; like in bug.py
      
      
      def myadd(a: int, b: int) -> int:
          return a + b
      
    2. Use mypy on it
      $ mypy --config-file= no_bug.py 
      Success: no issues found in 1 source file
      

    Failed solution attempts Using a forward declaration of myadd did not help:

    1. Create a file “forward_decl.py” with this content:
      # ––– file forward_decl.py ––
      from icontract import ensure
      from typing import Callable, cast
      
      MyaddType = Callable[[int, int], int]
      
      
      @ensure(lambda a, b, result: result == cast(MyaddType, myadd)(b, a),
              "Commutativity violated!")
      def myadd(a: int, b: int) -> int:
          return a + b
      
    2. Use mypy on it
      $ mypy --config-file= forward_decl.py
      forward_decl.py:8: error: Cannot determine type of "myadd"
      Found 1 error in 1 file (checked 1 source file)
      

    An alternative use of a cast of myadd's return type did not help either:

    1. Create a file “return_type.py” with this content:
      # ––– file: return_type.py –––
      from icontract import ensure
      from typing import cast
      
      
      @ensure(lambda a, b, result: result == cast(bool, myadd(b, a)),
              "Commutativity violated!")
      def myadd(a: int, b: int) -> int:
          return a + b
      
    2. Use mypy on it
      $ mypy --config-file= return_type.py
      return_type.py:6: error: Cannot determine type of "myadd"
      Found 1 error in 1 file (checked 1 source file)
      

    Your Environment

    • Mypy version used: mypy 0.950 (compiled: yes)
    • Mypy command-line flags: --config-file=
    • icontract version used: icontract==2.6.1
    • Python version used: Python 3.10.4
    opened by claudio-ebel 6
Releases(v2.6.2)
Owner
null
Black-Scholes library implemented as a Cairo smart contract

Cairo Black-Scholes Library Black-Scholes library implemented as a Cairo smart contract. All inputs, outputs, and internal calculations use 27-digit f

Aditya Raghavan 47 Dec 19, 2022
Telop - Encode and decode messages using an interpretation of the telegraphic code devised by José María Mathé

telop Telop (TELégrafoÓPtico) - Utilidad para codificar y descodificar mensajes de texto empleando una interpretación del código telegráfico ideado po

Ricardo F. 4 Nov 1, 2022
Telegram bot to remove the forwarded tag from messages.

Anonymous Sender Bot @AnonySendBot Telegram bot to remove the forwarded tag from messages. Table of Contents Usage Deploy To Heroku Local Deploying En

Stark Bots 26 Nov 24, 2022
Run Python code right in your Telegram messages

Run Python code right in your Telegram messages Made with Telethon library, TGPy is a tool for evaluating expressions and Telegram API scripts. Instal

null 29 Nov 22, 2022
Automatically remove user join messages when the user leaves the server.

CleanLeave Automatically remove user join messages when the user leaves the server. Installation You will need to install poetry to run this bot local

null 11 Sep 19, 2022
A python tool for synchronizing the messages from different threads, processes, or hosts.

Sync-stream This project is designed for providing the synchoronization of the stdout / stderr among different threads, processes, devices or hosts.

Yuchen Jin 0 Aug 11, 2021
Python tools for working with Orbit Ephemeris Messages (OEMs).

Python Orbit Ephemeris Message tools Python tools for working with Orbit Ephemeris Messages (OEMs). Development Status Installation The oem package is

Brad Sease 4 Apr 6, 2022
Simple script with AminoLab to send ghost messages

Simple script with AminoLab to send ghost messages

Moleey 1 Nov 22, 2021
Provide error messages for Python exceptions, even if the original message is empty

errortext is a Python package to provide error messages for Python exceptions, even if the original message is empty.

Thomas Aglassinger 0 Dec 7, 2021
A Github Action for sending messages to a Matrix Room.

matrix-commit A Github Action for sending messages to a Matrix Room. Screenshot: Example Usage: # .github/workflows/matrix-commit.yml on: push:

null 3 Sep 11, 2022
ViberExport - Export messages from Viber messenger using viber.db file

?? ViberExport Export messages from Viber messenger using viber.db file ⚡ Usage:

null 7 Nov 23, 2022
Automatically unpin old messages so you can always pin more!

PinRotate Automatically unpin old messages so you can always pin more! Installation You will need to install poetry to run this bot locally for develo

null 3 Sep 18, 2022
3D Printed Flip Clock Design and Code

Smart Flip Clock 3D printed smart clock that puts a new twist on old technology. Making The Smart Flip Clock The first thing that must be done for thi

Thomas 105 Oct 17, 2022
A collection of design patterns and idioms in Python (With tests!).

Python Patterns Help the project financially: Donate: https://smartlegion.github.io/donate/ Yandex Money: https://yoomoney.ru/to/4100115206129186 PayP

null 5 Sep 12, 2021
Here is my Senior Design Project that I implemented to graduate from Computer Engineering.

Here is my Senior Design Project that I implemented to graduate from Computer Engineering. It is a chatbot made in RASA and helps the user to plan their vacation in the Turkish language. In order to plan the user's vacation, it provides reservations by asking various questions for hotel, flight, or event.

Ezgi Subaşı 25 May 31, 2022
An app about keyboards, originating from the design of u/Sonnenschirm

keebapp-backend An app about keyboards, originating from the design of u/Sonnenschirm Setup Firstly, ensure that the environment for python is install

null 8 Sep 4, 2022
An addin for Autodesk Fusion 360 that lets you view your design in a Looking Glass Portrait 3D display

An addin for Autodesk Fusion 360 that lets you view your design in a Looking Glass Portrait 3D display

Brian Peiris 12 Nov 2, 2022
Random pass word generator made with python. PyQt5 module is used to design GUI.

Differences in this GUI program : Default titlebar removed Custom Minimize,Maximize and Close Buttons Drag & move window from any point Program work l

Dimuth De Zoysa 1 Jan 26, 2022
This Python3 script will monitor Upwork RSS feed and then email you the results.

Upwork RSS Parser This Python3 script will monitor Upwork RSS feed and then email you the results. Table of Contents General Info Technologies Used Fe

Chris 5 Nov 29, 2021