Skip to content

Commit

Permalink
Merge c0ff158 into 846e318
Browse files Browse the repository at this point in the history
  • Loading branch information
mristin committed May 8, 2019
2 parents 846e318 + c0ff158 commit 27773d2
Show file tree
Hide file tree
Showing 13 changed files with 228 additions and 145 deletions.
30 changes: 20 additions & 10 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ If you want to customize the error, see Section "Custom Errors".
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.errors.ViolationError: x > 3: x was 1
icontract.errors.ViolationError: File <doctest README.rst[1]>, line 1 in <module>:
x > 3: x was 1
# Pre-condition violation with a description
>>> @icontract.require(lambda x: x > 3, "x must not be small")
Expand All @@ -94,7 +95,8 @@ If you want to customize the error, see Section "Custom Errors".
>>> some_func(x=1)
Traceback (most recent call last):
...
icontract.errors.ViolationError: x must not be small: x > 3: x was 1
icontract.errors.ViolationError: File <doctest README.rst[4]>, line 1 in <module>:
x must not be small: x > 3: x was 1
# Pre-condition violation with more complex values
>>> class B:
Expand Down Expand Up @@ -123,7 +125,8 @@ If you want to customize the error, see Section "Custom Errors".
>>> some_func(an_a)
Traceback (most recent call last):
...
icontract.errors.ViolationError: a.b.x + a.b.y() > SOME_GLOBAL_VAR:
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
Expand All @@ -138,7 +141,8 @@ If you want to customize the error, see Section "Custom Errors".
>>> some_func(x=10)
Traceback (most recent call last):
...
icontract.errors.ViolationError: result > x:
icontract.errors.ViolationError: File <doctest README.rst[12]>, line 1 in <module>:
result > x:
result was 5
x was 10
Expand Down Expand Up @@ -292,7 +296,8 @@ Here is an example that uses snapshots to check that a value was appended to the
>>> some_func(lst=[1, 2], value=3)
Traceback (most recent call last):
...
icontract.errors.ViolationError: lst == OLD.lst + [value]:
icontract.errors.ViolationError: File <doctest README.rst[28]>, line 2 in <module>:
lst == OLD.lst + [value]:
OLD was a bunch of OLD values
OLD.lst was [1, 2]
lst was [1, 2, 3, 1984]
Expand All @@ -314,7 +319,8 @@ The following example shows how you can name the snapshot:
>>> some_func(lst=[1, 2], value=3)
Traceback (most recent call last):
...
icontract.errors.ViolationError: len(lst) == OLD.len_lst + 1:
icontract.errors.ViolationError: File <doctest README.rst[32]>, line 2 in <module>:
len(lst) == OLD.len_lst + 1:
OLD was a bunch of OLD values
OLD.len_lst was 2
len(lst) was 4
Expand Down Expand Up @@ -392,7 +398,8 @@ The following example shows an abstract parent class and a child class that inhe
>>> some_b.func(y=0)
Traceback (most recent call last):
...
icontract.errors.ViolationError: result < y:
icontract.errors.ViolationError: File <doctest README.rst[36]>, line 7 in A:
result < y:
result was 1
y was 0
Expand Down Expand Up @@ -445,7 +452,8 @@ The following example shows how preconditions are weakened:
>>> b.func(x=5)
Traceback (most recent call last):
...
icontract.errors.ViolationError: x % 3 == 0: x was 5
icontract.errors.ViolationError: File <doctest README.rst[45]>, line 2 in B:
x % 3 == 0: x was 5
The example below illustrates how snaphots are inherited:

Expand All @@ -469,7 +477,8 @@ The example below illustrates how snaphots are inherited:
>>> b.func(lst=[1, 2], value=3)
Traceback (most recent call last):
...
icontract.errors.ViolationError: len(lst) == len(OLD.lst) + 1:
icontract.errors.ViolationError: File <doctest README.rst[50]>, line 4 in A:
len(lst) == len(OLD.lst) + 1:
OLD was a bunch of OLD values
OLD.lst was [1, 2]
len(OLD.lst) was 2
Expand Down Expand Up @@ -567,7 +576,8 @@ Here is an example of the error given as an exception class:
>>> some_func(x=0)
Traceback (most recent call last):
...
ValueError: x > 0: x was 0
ValueError: File <doctest README.rst[56]>, line 1 in <module>:
x > 0: x was 0
Here is an example of the error given as a callable:

Expand Down
26 changes: 23 additions & 3 deletions icontract/_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ def __init__(self,
if not enabled:
return

self._contract = Contract(condition=condition, description=description, a_repr=a_repr, error=error)
location = None # type: Optional[str]
tb_stack = traceback.extract_stack(limit=2)[:1]
if len(tb_stack) > 0:
frame = tb_stack[0]
location = 'File {}, line {} in {}'.format(frame.filename, frame.lineno, frame.name)

self._contract = Contract(
condition=condition, description=description, a_repr=a_repr, error=error, location=location)

def __call__(self, func: CallableT) -> CallableT:
"""
Expand Down Expand Up @@ -130,7 +137,13 @@ def __init__(self, capture: Callable[..., Any], name: Optional[str] = None, enab

# Resolve the snapshot only if enabled so that no overhead is incurred
if enabled:
self._snapshot = Snapshot(capture=capture, name=name)
location = None # type: Optional[str]
tb_stack = traceback.extract_stack(limit=2)[:1]
if len(tb_stack) > 0:
frame = tb_stack[0]
location = 'File {}, line {} in {}'.format(frame.filename, frame.lineno, frame.name)

self._snapshot = Snapshot(capture=capture, name=name, location=location)

def __call__(self, func: CallableT) -> CallableT:
"""
Expand Down Expand Up @@ -214,7 +227,14 @@ def __init__(self,
if not enabled:
return

self._contract = Contract(condition=condition, description=description, a_repr=a_repr, error=error)
location = None # type: Optional[str]
tb_stack = traceback.extract_stack(limit=2)[:1]
if len(tb_stack) > 0:
frame = tb_stack[0]
location = 'File {}, line {} in {}'.format(frame.filename, frame.lineno, frame.name)

self._contract = Contract(
condition=condition, description=description, a_repr=a_repr, error=error, location=location)

def __call__(self, func: CallableT) -> CallableT:
"""
Expand Down
5 changes: 4 additions & 1 deletion icontract/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def __init__(self,
class Snapshot:
"""Define a snapshot of an argument *prior* to the function invocation that is later supplied to a postcondition."""

def __init__(self, capture: Callable[..., Any], name: Optional[str] = None) -> None:
def __init__(self, capture: Callable[..., Any], name: Optional[str] = None, location: Optional[str] = None) -> None:
"""
Initialize.
Expand All @@ -65,6 +65,7 @@ def __init__(self, capture: Callable[..., Any], name: Optional[str] = None) -> N
of the original function)
:param name: name of the captured variable in OLD that is passed to postconditions
:param location: indicate where the snapshot was defined (*e.g.*, path and line number)
"""
self.capture = capture
Expand All @@ -88,3 +89,5 @@ def __init__(self, capture: Callable[..., Any], name: Optional[str] = None) -> N
self.arg = args[0]
else:
assert len(args) == 0, "There can be at most one argument to a snapshot capture, but got: {}".format(args)

self.location = location
30 changes: 18 additions & 12 deletions tests/test_inheritance_invariant.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __repr__(self) -> str:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual("self.x > 0:\n"
"self was instance of B\n"
"self.x was -1", tests.violation_error.lstrip_location(str(icontract_violation_error)))
"self.x was -1", tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_inherited_violated_in_child(self):
@icontract.invariant(lambda self: self.x > 0)
Expand Down Expand Up @@ -102,7 +102,7 @@ def __repr__(self) -> str:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual("self.x > 0:\n"
"self was instance of B\n"
"self.x was -1", tests.violation_error.lstrip_location(str(icontract_violation_error)))
"self.x was -1", tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_additional_invariant_violated_in_childs_init(self):
@icontract.invariant(lambda self: self.x > 0)
Expand All @@ -127,7 +127,7 @@ def __repr__(self) -> str:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual("self.x > 100:\n"
"self was instance of B\n"
"self.x was 10", tests.violation_error.lstrip_location(str(icontract_violation_error)))
"self.x was 10", tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_method_violates_in_child(self):
@icontract.invariant(lambda self: self.x > 0)
Expand Down Expand Up @@ -156,7 +156,7 @@ def __repr__(self) -> str:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual("self.x > 100:\n"
"self was instance of B\n"
"self.x was 10", tests.violation_error.lstrip_location(str(icontract_violation_error)))
"self.x was 10", tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_triple_inheritance(self):
@icontract.invariant(lambda self: self.x > 0)
Expand Down Expand Up @@ -188,7 +188,7 @@ def __repr__(self) -> str:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual("self.x > 0:\n"
"self was instance of C\n"
"self.x was -1", tests.violation_error.lstrip_location(str(icontract_violation_error)))
"self.x was -1", tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_with_abstract_method(self):
@icontract.invariant(lambda self: self.x > 0)
Expand Down Expand Up @@ -220,7 +220,7 @@ def __repr__(self) -> str:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual("self.x > 0:\n"
"self was instance of B\n"
"self.x was -1", tests.violation_error.lstrip_location(str(icontract_violation_error)))
"self.x was -1", tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))


class TestProperty(unittest.TestCase):
Expand Down Expand Up @@ -250,7 +250,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_inherited_setter(self):
@icontract.invariant(lambda self: not self.toggled)
Expand Down Expand Up @@ -281,7 +282,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_inherited_deleter(self):
@icontract.invariant(lambda self: not self.toggled)
Expand Down Expand Up @@ -312,7 +314,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_inherited_invariant_on_getter(self):
@icontract.invariant(lambda self: not self.toggled)
Expand Down Expand Up @@ -340,7 +343,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_inherited_invariant_on_setter(self):
@icontract.invariant(lambda self: not self.toggled)
Expand Down Expand Up @@ -371,7 +375,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_inherited_invariant_on_deleter(self):
@icontract.invariant(lambda self: not self.toggled)
Expand Down Expand Up @@ -402,7 +407,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))


if __name__ == '__main__':
Expand Down
27 changes: 16 additions & 11 deletions tests/test_inheritance_postcondition.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class B(A):

self.assertIsNotNone(icontract_violation_error)
self.assertEqual("result < 100: result was 1000",
tests.violation_error.lstrip_location(str(icontract_violation_error)))
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_inherited_with_modified_implementation(self):
class A(icontract.DBC):
Expand All @@ -110,7 +110,7 @@ def func(self) -> int:

self.assertIsNotNone(icontract_violation_error)
self.assertEqual("result < 100: result was 10000",
tests.violation_error.lstrip_location(str(icontract_violation_error)))
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_ensure_then_violated_in_base(self):
class A(icontract.DBC):
Expand All @@ -132,7 +132,8 @@ def func(self) -> int:
icontract_violation_error = err

self.assertIsNotNone(icontract_violation_error)
self.assertEqual("result % 2 == 0: result was 3", str(icontract_violation_error))
self.assertEqual("result % 2 == 0: result was 3",
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_ensure_then_violated_in_child(self):
class A(icontract.DBC):
Expand All @@ -155,7 +156,7 @@ def func(self) -> int:

self.assertIsNotNone(icontract_violation_error)
self.assertEqual("result % 3 == 0: result was 2",
tests.violation_error.lstrip_location(str(icontract_violation_error)))
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_abstract_method(self):
class A(icontract.DBC):
Expand All @@ -177,7 +178,7 @@ def func(self) -> int:

self.assertIsNotNone(icontract_violation_error)
self.assertEqual("result < 100: result was 1000",
tests.violation_error.lstrip_location(str(icontract_violation_error)))
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_that_base_postconditions_apply_to_init_if_not_defined(self):
class A(icontract.DBC):
Expand All @@ -200,7 +201,7 @@ class B(A):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('self.x >= 0:\n'
'self was B\n'
'self.x was -1', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.x was -1', tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_that_base_postconditions_dont_apply_to_init_if_overridden(self):
class A(icontract.DBC):
Expand Down Expand Up @@ -229,7 +230,7 @@ def __repr__(self) -> str:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('self.x < 0:\n'
'self was B\n'
'self.x was 0', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.x was 0', tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))


class TestPropertyOK(unittest.TestCase):
Expand Down Expand Up @@ -295,7 +296,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_setter(self):
class SomeBase(icontract.DBC):
Expand Down Expand Up @@ -330,7 +332,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_deleter(self):
class SomeBase(icontract.DBC):
Expand Down Expand Up @@ -365,7 +368,8 @@ def some_prop(self) -> None:
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))

def test_setter_strengthened(self):
class SomeBase(icontract.DBC):
Expand Down Expand Up @@ -400,7 +404,8 @@ def __repr__(self):
self.assertIsNotNone(icontract_violation_error)
self.assertEqual('not self.toggled:\n'
'self was SomeClass\n'
'self.toggled was True', tests.violation_error.lstrip_location(str(icontract_violation_error)))
'self.toggled was True',
tests.violation_error.wo_mandatory_location(str(icontract_violation_error)))


class TestInvalid(unittest.TestCase):
Expand Down
Loading

0 comments on commit 27773d2

Please sign in to comment.