| 1 |  |  | import inspect | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | from collections import OrderedDict | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | from typing import Callable, Any, Union, Iterable, Dict, Tuple | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | from typish._types import Empty | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | from typish.classes._cls_dict import ClsDict | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                                                    
                                                                                                        
            
            
                | 9 |  | View Code Duplication | class ClsFunction: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |     ClsDict is a callable that takes a ClsDict or a dict. When called, it uses | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |     the first argument to check for the right function in its body, executes it | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |     and returns the result. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |     def __init__(self, body: Union[ClsDict, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |                                    Dict[type, Callable], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |                                    Iterable[Tuple[type, Callable]], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |                                    Iterable[Callable]]): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |         from typish.functions._instance_of import instance_of | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         if isinstance(body, ClsDict): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |             self.body = body | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         elif isinstance(body, dict): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |             self.body = ClsDict(body) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         elif instance_of(body, Iterable[Callable]): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |             list_of_tuples = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |             for func in body: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |                 signature = inspect.signature(func) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |                 params = list(signature.parameters.keys()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |                 if not params: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |                     raise TypeError('ClsFunction expects callables that take ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |                                     'at least one parameter, {} does not.' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |                                     .format(func.__name__)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |                 first_param = signature.parameters[params[0]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |                 hint = first_param.annotation | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |                 key = Any if hint == Empty else hint | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |                 list_of_tuples.append((key, func)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |             self.body = ClsDict(OrderedDict(list_of_tuples)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |         elif instance_of(body, Iterable[Tuple[type, Callable]]): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |             self.body = ClsDict(OrderedDict(body)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |         else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |             raise TypeError('ClsFunction expects a ClsDict or a dict that can ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |                             'be turned to a ClsDict or an iterable of ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |                             'callables.') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |         if not all(isinstance(value, Callable) for value in self.body.values()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |             raise TypeError('ClsFunction expects a dict or ClsDict with only ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |                             'callables as values.') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |     def understands(self, item: Any) -> bool: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         Check to see if this ClsFunction can take item. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |         :param item: the item that is checked. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |         :return: True if this ClsFunction can take item. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |             self.body[item] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |             return True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |         except KeyError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |             return False | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 61 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 62 |  |  |     def __call__(self, *args, **kwargs): | 
            
                                                        
            
                                    
            
            
                | 63 |  |  |         if not args: | 
            
                                                        
            
                                    
            
            
                | 64 |  |  |             raise TypeError('ClsFunction must be called with at least 1 ' | 
            
                                                        
            
                                    
            
            
                | 65 |  |  |                             'positional argument.') | 
            
                                                        
            
                                    
            
            
                | 66 |  |  |         callable_ = self.body[args[0]] | 
            
                                                        
            
                                    
            
            
                | 67 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 68 |  |  |             return callable_(*args, **kwargs) | 
            
                                                        
            
                                    
            
            
                | 69 |  |  |         except TypeError as err: | 
            
                                                        
            
                                    
            
            
                | 70 |  |  |             raise TypeError('Unable to call function for \'{}\': {}' | 
            
                                                        
            
                                    
            
            
                | 71 |  |  |                             .format(args[0], err.args[0])) | 
            
                                                        
            
                                    
            
            
                | 72 |  |  |  |