Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from goody import type_as_str
- import inspect
- class Check_All_OK:
- """
- Check_All_OK class implements __check_annotation__ by checking whether each
- annotation passed to its constructor is OK; the first one that
- fails (raises AssertionError) prints its problem, with a list of all
- annotations being tried at the end of the check_history.
- """
- def __init__(self,*args):
- self._annotations = args
- def __repr__(self):
- return 'Check_All_OK('+','.join([str(i) for i in self._annotations])+')'
- def __check_annotation__(self, check, param, value,check_history):
- for annot in self._annotations:
- check(param, annot, value, check_history+'Check_All_OK check: '+str(annot)+' while trying: '+str(self)+'\n')
- class Check_Any_OK:
- """
- Check_Any_OK implements __check_annotation__ by checking whether at least
- one of the annotations passed to its constructor is OK; if all fail
- (raise AssertionError) this classes raises AssertionError and prints its
- failure, along with a list of all annotations tried followed by the check_history.
- """
- def __init__(self,*args):
- self._annotations = args
- def __repr__(self):
- return 'Check_Any_OK('+','.join([str(i) for i in self._annotations])+')'
- def __check_annotation__(self, check, param, value, check_history):
- failed = 0
- for annot in self._annotations:
- try:
- check(param, annot, value, check_history)
- except AssertionError:
- failed += 1
- if failed == len(self._annotations):
- assert False, repr(param)+' failed annotation check(Check_Any_OK): value = '+repr(value)+\
- '\n tried '+str(self)+'\n'+check_history
- class Check_Annotation():
- # set name to True for checking to occur
- checking_on = True
- # self._checking_on must also be true for checking to occur
- def __init__(self,f):
- self._f = f
- self.checking_on = True
- # Check whether param's annot is correct for value, adding to check_history
- # if recurs; defines many local function which use it parameters.
- def check(self,param,annot,value,check_history=''):
- # Define local functions for checking, list/tuple, dict, set/frozenset,
- # lambda/functions, and str (str for extra credit)
- # Many of these local functions called by check, call check on their
- # elements (thus are indirectly recursive)
- print("Annot:", annot)
- print("Type of annot:", type(annot))
- print("Param", param)
- print("Value", value, "\tValue Type", type(value))
- print("history", check_history)
- def check_type():
- if isinstance(value, annot): return
- else: raise AssertionError
- def check_list():
- if isinstance(value, list):
- if len(annot) == 1:
- for i in value:
- if not isinstance(i, annot[0]): raise AssertionError
- return
- elif len(value) == len(annot):
- for i,j in zip(value,annot):
- if not isinstance(i, j): raise AssertionError
- return
- else: raise AssertionError
- else: raise AssertionError
- def check_dict():
- if isinstance(value, dict): return
- else: raise AssertionError
- def check_tuple():
- if isinstance(value, tuple):
- if len(annot) == 1:
- for i in value:
- if not isinstance(i, annot[0]): raise AssertionError
- return
- elif len(value) == len(annot):
- for i,j in zip(value,annot):
- if not isinstance(i, j): raise AssertionError
- return
- else: raise AssertionError
- else: raise AssertionError
- def check_set():
- if isinstance(value, set):
- if len(annot) > 1:
- raise AssertionError
- elif len(annot) == 1:
- for i in value:
- if type(i) not in annot: raise AssertionError
- return
- else: raise AssertionError
- def check_frozenset():
- if isinstance(value, frozenset):
- if len(annot) > 1:
- raise AssertionError
- elif len(annot) == 1:
- for i in value:
- if type(i) not in annot: raise AssertionError
- return
- else: raise AssertionError
- def check_lambda():
- pass
- def check_str():
- if isinstance(value, str):
- print("\nEVAL\n", eval(annot))
- return
- else: raise AssertionError
- def check_int():
- if isinstance(value, int): return
- else: raise AssertionError
- # Decode annotation and check it
- if annot == None: return
- elif isinstance(annot, type): check_type()
- elif isinstance(annot, list):
- if isinstance(annot[0], list):
- for i, j in zip(annot, value):
- self.check(param, i, j, check_history)
- else: check_list()
- elif isinstance(annot, dict): check_dict()
- elif isinstance(annot, tuple): check_tuple()
- elif isinstance(annot, set): check_set()
- elif isinstance(annot, frozenset): check_frozenset()
- # elif isinstance(annot, function): check_lambda()
- elif isinstance(annot, str): check_str()
- elif isinstance(annot, int): check_int()
- else: raise AssertionError
- # Return result of calling decorated function call, checking present
- # parameter/return annotations if required
- def __call__(self, *args, **kargs):
- # Return a dictionary of the parameter/argument bindings (actually an
- # ordereddict, in the order parameters occur in the function's header)
- def param_arg_bindings():
- f_signature = inspect.signature(self._f)
- bound_f_signature = f_signature.bind(*args,**kargs)
- for param in f_signature.parameters.values():
- if param.name not in bound_f_signature.arguments:
- bound_f_signature.arguments[param.name] = param.default
- return bound_f_signature.arguments
- # If annotation checking is turned off at the class or function level
- # just return the result of calling the decorated function
- # Otherwise do all the annotation checking
- if Check_Annotation.checking_on and self.checking_on:
- try:
- # Check the annotation for every parameter (if there is one)
- for x, y in param_arg_bindings().items():
- self.check(x, self._f.__annotations__[x], y)
- # Compute/remember the value of the decorated function
- answer = self._f(*args, **kargs)
- # If 'return' is in the annotation, check it
- if "return" in self._f.__annotations__:
- self.check("_return", self._f.__annotaions__["return"])
- # Return the decorated answer
- return answer
- # On first AssertionError, print the source lines of the function and reraise
- except AssertionError:
- # print(80*'-')
- # for l in inspect.getsourcelines(self._f)[0]: # ignore starting line #
- # print(l.rstrip())
- # print(80*'-')
- raise
- else:
- return self._f(*args, **kargs)
- if __name__ == '__main__':
- # an example of testing a simple annotation
- # def f(x:int): pass
- # f = Check_Annotation(f)
- # f(3)
- # f('a')
- import driver
- driver.driver()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement