Днес съчинихме следното.
import unittest
import inspect
class PreconditionFailed(Exception):
pass
def preconditions(func):
spec = inspect.getfullargspec(func)
expectations = [spec.annotations[arg] for arg in spec.args]
def checked(*args):
for (value, expectation) in zip(args, expectations):
if not expectation(value):
raise PreconditionFailed
return func(*args)
return checked
class expr:
def __and__(self, other): return conjunction(self, other)
class conjunction(expr):
def __init__(self, left, right):
self.left = left
self.right = right
def __call__(self, arg):
return self.left(arg) and self.right(arg)
class gt(expr):
def __init__(self, min): self.min = min
def __call__(self, arg): return self.min < arg
class lt(expr):
def __init__(self, max): self.max = max
def __call__(self, arg): return self.max > arg
class PreconditionsTest(unittest.TestCase):
def test_calls_the_function_if_no_violations(self):
@preconditions
def foo(x: gt(5)):
return 42
self.assertEqual(42, foo(10))
def test_checks_if_number_is_greater_than_specified(self):
@preconditions
def foo(x: gt(5)):
return 42
with self.assertRaises(PreconditionFailed):
foo(0)
def test_checks_if_number_is_less_than_specified(self):
@preconditions
def foo(x: lt(5)):
return 42
with self.assertRaises(PreconditionFailed):
foo(10)
def test_works_with_multiple_arguments(self):
@preconditions
def foo(x: gt(5), y: gt(10)):
return 42
with self.assertRaises(PreconditionFailed):
foo(7, 7)
def test_supports_combining_expectations(self):
@preconditions
def foo(x: gt(5) & lt(10)):
return 42
with self.assertRaises(PreconditionFailed):
foo(20)
if __name__ == '__main__':
unittest.main()
Пробвайте да го разширите. Споделете кода и какво сте научили и получавате точка.
Публикувано преди