| 1 |  |  | from abc import abstractmethod, ABC | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | from functools import wraps | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | import inspect | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | from so_magic.utils import Singleton, Transformer, ObjectRegistry, Subject | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | class PhiFunctionRegistry(Singleton, ObjectRegistry): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |     def __new__(cls, *args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |         x = Singleton.__new__(cls, *args, **kwargs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |         x = ObjectRegistry(getattr(x, 'objects', {})) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |         return x | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 12 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 13 |  |  |     @staticmethod | 
            
                                                                        
                            
            
                                    
            
            
                | 14 |  |  |     def get_instance(): | 
            
                                                                        
                            
            
                                    
            
            
                | 15 |  |  |         return PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     def get_name(a_callable): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |         if hasattr(a_callable, 'name'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |             return a_callable.name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         if hasattr(a_callable, '__code__') and hasattr(a_callable.__code__, 'co_name'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |             return a_callable.__code__.co_name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         if hasattr(type(a_callable), 'name'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |             return type(a_callable).name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         if hasattr(type(a_callable), '__name__'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |             return type(a_callable).__name__ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |         return '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  | phi_registry = PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  | class PhiFunctionMetaclass(type): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |     def __new__(mcs, *args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |         x = super().__new__(mcs, *args, **kwargs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |         x.subject = Subject([]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         return x | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  | class PhiFunctionRegistrator(metaclass=PhiFunctionMetaclass): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |     def register(cls, phi_name=''): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |         def wrapper(a_callable): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |             if hasattr(a_callable, '__code__'):  # it a function (def func_name ..) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |                 print(f"Registering input function {a_callable.__code__.co_name}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |                 cls._register(a_callable, key_name=phi_name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |                 if not hasattr(a_callable, '__call__'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |                     raise RuntimeError(f"Expected an class definition with a '__call__' instance method defined 1. Got {type(a_callable)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |                 members = inspect.getmembers(a_callable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |                 if not ('__call__', a_callable.__call__) in members: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |                     raise RuntimeError(f"Expected an class definition with a '__call__' instance method defined 2. Got {type(a_callable)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |                 print(f"Registering a class {type(a_callable).__name__}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |                 instance = a_callable() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |                 cls._register(instance, key_name=phi_name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |             return a_callable | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |         return wrapper | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     def _register(cls, a_callable, key_name=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         key = key_name if key_name else PhiFunctionRegistry.get_name(a_callable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         print(f"Registering object {a_callable} at key {key}.") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         phi_registry.add(key, a_callable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         cls.subject.name = key | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |         cls.subject.state = a_callable | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |         cls.subject.notify() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |     def my_decorator(cls, f): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |         print(f"Running 'my_decorator' with input type {type(f)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |         @wraps(f) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |         def wrapper(*args, **kwds): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |             if hasattr(f, '__code__'):  # it a function (def func_name ..) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |                 print(f"Registering input function {a_callable.__code__.co_name}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |                 cls._register(f) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |                 if not hasattr(f, '__call__'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |                     raise RuntimeError(f"Expected an class definition with a '__call__' instance method defined 1. Got {type(f)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |                 members = inspect.getmembers(f) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |                 if not ('__call__', f.__call__) in members: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |                     raise RuntimeError(f"Expected an class definition with a '__call__' instance method defined 2. Got {type(f)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |                 print(f"Registering a class {type(a_callable).name}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |                 instance = f() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |                 cls._register(instance) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |             return f(*args, **kwds) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |         return wrapper | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  | if __name__ == '__main__': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |     reg1 = PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |     reg2 = PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |     reg3 = PhiFunctionRegistry.get_instance() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |     assert id(reg1) == id(reg2) == id(reg3) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |     @PhiFunctionRegistrator.my_decorator | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |     def example(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |         """Inherited Docstring""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         print('Called example function') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |     example() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |     print(example.__name__) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |     print('--') | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 107 |  |  |     print(example.__doc__) | 
            
                                                        
            
                                    
            
            
                | 108 |  |  |  |