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 implements __check_annotation__ by checking whether all the
- annotations passed to its constructor are 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():
- # must be 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=''):
- """
- :param param: is a string that specifies the name of the parameter being checked
- (or '_return' for checking the returned value)
- :param annot: is a data structure that specifies the annotation
- :param value: is the value of param that the annotation should be checked against (to ensure it is legal)
- :param check_history: is a string that embodies the history of checking the annotation
- for the parameter to here (it is extended by concatenation in
- each recursive call to provide context for any annotation violations to be checked later);
- it is printed after the details of any annotation violation, to suppy context for the failure.
- :return:
- """
- # 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)
- # Decode annotation and check it
- #pass
- #local functions
- def check_list():
- error_str = '\'{}\' failed annotation check(wrong type):' \
- ' value = {} \n\twas type {} ...should be type {}'.format(
- param,value,type_as_str(value),'list')
- #type list
- if type(annot) == type:
- if isinstance(value,list):
- return
- else:
- raise AssertionError(error_str)
- elif type(annot[0]) == type:
- #type [int]
- if isinstance(value,list):
- if len(annot) == 1:
- #check each value to make sure its same type
- for object in value:
- if not isinstance(object,annot[0]):
- raise AssertionError
- else:
- continue
- if len(annot) > 1:
- if len(annot) == len(value):
- for object,annotation in zip(value,annot):
- if not isinstance(object,annotation):
- raise AssertionError
- else:
- continue
- else:
- raise AssertionError
- else:
- raise AssertionError(error_str)
- else:
- if len(annot[0]) == 1:
- for object in value:
- for sub_object in object:
- if not isinstance(sub_object,annot[0][0]):
- raise AssertionError
- else:
- continue
- def check_tuple():
- error_str = '\'{}\' failed annotation check(wrong type):' \
- ' value = {} \n\twas type {} ...should be type {}'.format(
- param,value,type_as_str(value),'tuple')
- #type list
- if type(annot) == type:
- if isinstance(value,list):
- return
- else:
- raise AssertionError(error_str)
- elif type(annot[0]) == type:
- #type [int]
- if isinstance(value,tuple):
- if len(annot) == 1:
- #check each value to make sure its same type
- for object in value:
- if not isinstance(object,annot[0]):
- raise AssertionError
- else:
- continue
- if len(annot) > 1:
- if len(annot) == len(value):
- for object,annotation in zip(value,annot):
- if not isinstance(object,annotation):
- raise AssertionError
- else:
- continue
- else:
- raise AssertionError
- else:
- raise AssertionError(error_str)
- else:
- if len(annot[0]) == 1:
- for object in value:
- for sub_object in object:
- if not isinstance(sub_object,annot[0][0]):
- raise AssertionError
- else:
- continue
- def check_dict():
- error_str = '\'{}\' failed annotation check(wrong type):' \
- ' value = {} \n\twas type {} ...should be type {}'.format(
- param,value,type_as_str(value),'dict')
- if type(annot) == type:
- if isinstance(value,dict):
- return
- else:
- raise AssertionError(error_str)
- #elif type(annot) == dict:
- #type [int]
- #if isinstance(value,dict):
- #pass
- if isinstance(value,dict):
- for k,v in value.items():
- for key in annot.keys():
- if type(k) == key and type(v) == annot[key]:
- pass
- else:
- raise AssertionError
- else:
- raise AssertionError
- def check_set():
- if isinstance(value,set):
- if len(annot) > 1:
- if not len(value) == len(annot):
- raise AssertionError
- return
- else:
- raise AssertionError
- def check_frozenset():
- if isinstance(value,frozenset):
- if len(annot) > 1:
- if not len(value) == len(annot):
- raise AssertionError
- return
- else:
- raise AssertionError
- def check_lambda():
- parameters = annot.__code__.co_varnames
- if len(parameters) == 0 or len(parameters) > 1:
- raise AssertionError
- # if len(parameters) > 1:
- # expected_tuple_len = len(parameters)
- # if type(value) == list:
- # for tup in value:
- # if len(tup) != expected_tuple_len:
- # raise AssertionError
- # else:
- # raise AssertionError
- #list of values
- if type(value) == list:
- for x in value:
- try:
- if annot(x):
- pass
- else:
- raise AssertionError
- except:
- raise AssertionError
- #one elem
- else:
- if annot(value):
- pass
- else:
- raise AssertionError
- def check_lambda_list():
- parameters = annot[0].__code__.co_varnames
- if len(parameters) == 0 or len(parameters) > 1:
- raise AssertionError
- # if len(parameters) > 1:
- # expected_tuple_len = len(parameters)
- # if type(value) == list:
- # for tup in value:
- # if len(tup) != expected_tuple_len:
- # raise AssertionError
- # else:
- # raise AssertionError
- #list of values
- if type(value) == list:
- for x in value:
- try:
- if annot[0](x):
- pass
- else:
- raise AssertionError
- except:
- raise AssertionError
- #one elem
- else:
- if annot(value):
- pass
- else:
- raise AssertionError
- def check_str():
- error_str = '\'{}\' failed annotation check(wrong type):' \
- ' value = {} \n\twas type {} ...should be type {}'.format(
- param,value,type_as_str(value),'str')
- if isinstance(value,str):
- return
- else:
- raise AssertionError(error_str)
- def check_int():
- if isinstance(value,int):
- return
- else:
- raise AssertionError
- if annot is None:
- #Do Nothing
- return
- elif isinstance(annot,list) or annot == list:
- if inspect.isfunction(annot[0]):
- check_lambda_list()
- else:
- check_list()
- elif isinstance(annot,tuple) or annot == tuple:
- check_tuple()
- elif annot == str:
- check_str()
- elif isinstance(annot,dict) or annot == dict:
- check_dict()
- elif isinstance(annot,set) or annot == set:
- check_set()
- elif isinstance(annot,frozenset) or annot == frozenset:
- check_frozenset()
- elif inspect.isfunction(annot):
- check_lambda()
- elif isinstance(annot,int) or annot == int:
- check_int()
- else: # other
- 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 not self.checking_on:
- return self._f(*args,**kargs)
- try:
- # Check the annotation for every parameter (if there is one)
- param_dict = param_arg_bindings()
- for variable,value in param_dict.items():
- self.check(variable,self._f.__annotations__[variable],value)
- # Compute/remember the value of the decorated function
- return_value = self._f(*args,**kargs)
- # If 'return' is in the annotation, check it
- if 'return' in self._f.__annotations__:
- self.check('_return',self._f.__annotations__['return'],return_value)
- # Return the decorated answer
- return return_value
- # 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
- if __name__ == '__main__':
- #def f(x : list): pass
- #f = Check_Annotation(f)
- #f([1,2])
- class NotSupportProtocol: pass
- def f(x : NotSupportProtocol()): pass
- f = Check_Annotation(f)
- #f(3)
- #f('abc') #assert error
- import driver
- #driver.driver()
- driver.batch_self_check('bsc.txt')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement