Commits

Kamil Kisiel committed 5e21dae

Added @pre and @post decorators.

  • Participants
  • Parent commits d384707

Comments (0)

Files changed (1)

 from inspect import getcallargs, getargspec, isfunction, getmembers
 from functools import wraps
 
+
 if __debug__:
-    __ENABLED = True
+    _ENABLED = True
 else:
-    __ENABLED = False
+    _ENABLED = False
+
+
+def disable():
+    """Disable covenant functionality"""
+    global _ENABLED
+    _ENABLED = False
+
+
+def enable():
+    """Enable covenant functionality"""
+    global _ENABLED
+    _ENABLED = True
+
+
+def is_enabled():
+    """Returns True if covenant functionality is enabled"""
+    return _ENABLED
 
 
 # Keep track of which invariant checks are currently happening so that
 # we don't end up with recursive check issues.
-__INVARIANTS_IN_PROGRESS = set()
+_INVARIANTS_IN_PROGRESS = set()
 
 
-def __invariant_decorator(condition):
-    def _invariant(cls):
-        for attr_name, attr in getmembers(cls, isfunction):
-            if 'self' in getargspec(attr).args:
-                wrapper = __invariant_wrapper(attr, condition)
-                setattr(cls, attr_name, wrapper)
-
-        return cls
-    return _invariant
-
-
-def __invariant_wrapper(attr, condition):
+def _invariant_wrapper(attr, condition):
     @wraps(attr)
     def wrapper(*args, **kwargs):
         callargs = getcallargs(attr, *args, **kwargs)
         value = attr(*args, **kwargs)
 
         inst_id = id(inst)
-        if not inst_id in __INVARIANTS_IN_PROGRESS:
-            __INVARIANTS_IN_PROGRESS.add(inst_id)
+        if not inst_id in _INVARIANTS_IN_PROGRESS:
+            _INVARIANTS_IN_PROGRESS.add(inst_id)
             result = condition(inst)
-            __INVARIANTS_IN_PROGRESS.remove(inst_id)
-            print("Result: {0}".format(result))
+            _INVARIANTS_IN_PROGRESS.remove(inst_id)
             if not result:
                 raise AssertionError("Invariant violated.")
 
     return wrapper
 
 
-def __bind_wrapper(func):
+def _null_decorator(obj):
+    return obj
+
+
+def _decorate_if_enabled(decorator=True):
+    def _inner(func):
+        if is_enabled():
+            return func
+        else:
+            return _null_decorator if decorator else func
+    return _inner
+
+
+@_decorate_if_enabled()
+def invariant(condition):
+    def _invariant(cls):
+        for attr_name, attr in getmembers(cls, isfunction):
+            if 'self' in getargspec(attr).args:
+                wrapper = _invariant_wrapper(attr, condition)
+                setattr(cls, attr_name, wrapper)
+
+        return cls
+    return _invariant
+
+
+@_decorate_if_enabled()
+def pre(condition):
+    def _pre(func):
+        @wraps(func)
+        def wrapped_func(*args, **kwargs):
+            callargs = getcallargs(func, *args, **kwargs)
+            result = condition(**callargs)
+            if not result:
+                raise AssertionError("Precondition check failed.")
+
+            return func(*args, **kwargs)
+
+        return wrapped_func
+    return _pre
+
+
+@_decorate_if_enabled()
+def post(condition):
+    def _post(func):
+        @wraps(func)
+        def wrapped_func(*args, **kwargs):
+            callargs = getcallargs(func, *args, **kwargs)
+
+            value = func(*args, **kwargs)
+
+            result = condition(value, **callargs)
+
+            if not result:
+                raise AssertionError("Precondition check failed.")
+
+        return wrapped_func
+    return _post
+
+
+@_decorate_if_enabled(decorator=False)
+def constrain(func):
     @wraps(func)
-    def bound_func(*args, **kwargs):
+    def wrapped_func(*args, **kwargs):
         callargs = getcallargs(func, *args, **kwargs)
         for arg, arg_value in callargs.items():
             if arg in func.__annotations__:
 
         return value
 
-    return bound_func
-
-
-def invariant(condition):
-    """Decorate a class with an invariant.
-    The class must be of the InvariantMeta metaclass.
-    """
-    if is_enabled():
-        return __invariant_decorator(condition)
-    else:
-        def null_decorator(cls):
-            return cls
-        return null_decorator
-
-
-def bind(func):
-    if is_enabled:
-        return __bind_wrapper(func)
-    else:
-        return func
-
-
-def disable():
-    """Disable covenant functionality"""
-    global __ENABLED
-    __ENABLED = False
-
-
-def enable():
-    """Enable covenant functionality"""
-    global __ENABLED
-    __ENABLED = True
-
-
-def is_enabled():
-    """Returns True if covenant functionality is enabled"""
-    return __ENABLED
+    return wrapped_func