| 1 |  |  | """This module is responsible to provide a formal way of registering phi functions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | at runtime. See the 'PhiFunctionRegistrator' class and its 'register' decorator method | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | import logging | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | import inspect | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | from typing import Callable | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | from so_magic.utils import Singleton, ObjectRegistry, Subject | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | logger = logging.getLogger(__name__) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | class PhiFunctionRegistry(Singleton, ObjectRegistry): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |     """A Singleton dict-like object registry for phi functions. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |     Use this class to create a singleton object (instance of this class) that | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |     acts as a storage for phi function objects. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     def __new__(cls, *args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |         """Create a new (singleton) instance and initialize an empty registry. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |             PhiFunctionRegistry: the reference to the singleton object (instance) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |         phi_function_registry = Singleton.__new__(cls, *args, **kwargs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         phi_function_registry = ObjectRegistry(getattr(phi_function_registry, 'objects', {})) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |         return phi_function_registry | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |     @staticmethod | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |     def get_instance(): | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |         """Get the singleton object (instance). | 
            
                                                                        
                            
            
                                    
            
            
                | 31 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 32 |  |  |         Returns: | 
            
                                                                        
                            
            
                                    
            
            
                | 33 |  |  |             PhiFunctionRegistry: the reference to the singleton object (instance) | 
            
                                                                        
                            
            
                                    
            
            
                | 34 |  |  |         """ | 
            
                                                                        
                            
            
                                    
            
            
                | 35 |  |  |         return PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  | phi_registry = PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  | class PhiFunctionMetaclass(type): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |     """Class type with a single broadcasting (notifies listeners) facility. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |     Classes using this class as metaclass, obtain a single broadcasting facility | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |     as a class attribute. The class attribute is called 'subject' can be referenced | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     as any class attribute. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |     Example: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         class MyExampleClass(metaclass=PhiFunctionMetaclass): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |             pass | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         instance_object_1 = MyExampleClass() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |         instance_object_2 = MyExampleClass() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |         assert id(MyExampleClass.subject) == id(instance_object_1.subject) == id(instance_object_2.subject) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |     def __new__(mcs, *args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |         """Create a new class type object and set the 'subject' attribute to a new Subject instance; the broadcaster. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |             PhiFunctionMetaclass: the new class type object | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         phi_function_class = super().__new__(mcs, *args, **kwargs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         phi_function_class.subject = Subject([]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         return phi_function_class | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  | class PhiFunctionRegistrator(metaclass=PhiFunctionMetaclass): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |     """Add phi functions to the registry and notify observers/listeners. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |     This class provides the 'register' decorator, that client can use to decorate either functions (defined with the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |     def python special word), or classes (defined with the python class special word). | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |     # NICE TO HAVE: make the decorator work without parenthesis | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |     def register(cls, phi_name=''): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |         """Add a new phi function to phi function registry and notify listeners/observers. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |         Use this decorator around either a callable function (defined with the 'def' python special word) or a class | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |         with a takes-no-arguments (or all-optional-arguments) constructor and a __call__ magic method. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |         All phi functions are expected to be registered with a __name__ and a __doc__ attribute. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |         You can select your custom phi_name under which to register the phi function or default to an automatic | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |         determination of the phi_name to use. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |         Automatic determination of phi_name is done by examining either the __name__ attribute of the function or the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |         class name of the class. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |         Example: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |             >>> from so_magic.data.features.phi import PhiFunctionRegistry, PhiFunctionRegistrator | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |             >>> registered_phis = PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |             >>> @PhiFunctionRegistrator.register() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |             ... def f1(x): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |             ...  return x * 2 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |             Registering input function f1 as phi function, at key f1. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |             >>> input_value = 5 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |             >>> print(f"{input_value} * 2 = {registered_phis.get('f1')(input_value)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |             5 * 2 = 10 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |             >>> @PhiFunctionRegistrator.register() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |             ... class f2: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |             ...  def __call__(self, data, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |             ...   return data + 5 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |             Registering input class f2 instance as phi function, at key f2. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |             >>> input_value = 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |             >>> print(f"{input_value} + 5 = {registered_phis.get('f2')(input_value)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |             1 + 5 = 6 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |             >>> @PhiFunctionRegistrator.register('f3') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |             ... class MyCustomClass: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |             ...  def __call__(self, data, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |             ...   return data + 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |             Registering input class MyCustomClass instance as phi function, at key f3. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |             >>> input_value = 3 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |             >>> print(f"{input_value} + 1 = {registered_phis.get('f3')(input_value)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |             3 + 1 = 4 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |             phi_name (str, optional): custom name to register the phi function. Defaults to automatic computation. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |         def wrapper(a_callable): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |             """Add a callable object to the phi function registry and preserve info for __name__ and __doc__ attributes. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |             The callable object should either be function (defined with def) or a class (defined with class). In case of | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |             a class the class must have a constructor that takes no arguments (or all arguments are optional) and a | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |             __call__ magic method. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |             Registers the callable as a phi function under the given or automatically computed name, makes sure the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |             __name__ and __doc__ attributes preserve information and notifies potential listeners/observers. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |             Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |                 a_callable (Callable): the object (function or class) to register as phi function | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |             """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |             if hasattr(a_callable, '__code__'):  # it is a function (def func_name ..) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |                 logging.info("Registering input function %s as phi function.", a_callable.__code__.co_name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |                 key = phi_name if phi_name else cls.get_name(a_callable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |                 print(f"Registering input function {a_callable.__code__.co_name} as phi function, at key {key}.") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |                 cls._register(a_callable, key) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |                 if not hasattr(a_callable, '__call__'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |                     raise RuntimeError("Expected an class definition with a '__call__' instance method defined 1." | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |                                        f" Got {type(a_callable)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |                 members = inspect.getmembers(a_callable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |                 if ('__call__', a_callable.__call__) not in members: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |                     raise RuntimeError("Expected an class definition with a '__call__' instance method defined 2." | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |                                        f" Got {type(a_callable)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |                 instance = a_callable() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |                 instance.__name__ = a_callable.__name__ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |                 instance.__doc__ = a_callable.__call__.__doc__ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |                 key = phi_name if phi_name else cls.get_name(instance) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |                 print(f"Registering input class {a_callable.__name__} instance as phi function, at key {key}.") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |                 cls._register(instance, key) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |             return a_callable | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |         return wrapper | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |     def _register(cls, a_callable, key_name): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |         """Register a callable as phi function and notify potential listeners/observers. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |         The phi function is registered under the given key_name or in case of None the name is automatically computed | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |         based on the input callable. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |             a_callable (Callable): the callable that holds the business logic of the phi function | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |             key_name (str, optional): custom phi name. Defaults to None, which means automatic determination of the name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |         phi_registry.add(key_name, a_callable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |         cls.subject.name = key_name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |         cls.subject.state = a_callable | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |         cls.subject.notify() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |     def get_name(a_callable: Callable): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |         """Get the 'name' of the input callable object | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |             a_callable (Callable): a callable object to get its name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |             str: the name of the callable object | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  |         if hasattr(a_callable, 'name'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  |             return a_callable.name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 |  |  |         if hasattr(a_callable, '__code__') and hasattr(a_callable.__code__, 'co_name'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  |             return a_callable.__code__.co_name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  |         if hasattr(type(a_callable), 'name'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |             return type(a_callable).name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |         if hasattr(type(a_callable), '__name__'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  |             return type(a_callable).__name__ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |         # TODO replace below line with a raise Exception | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  |         # we want to cause an error when we fail to get a sensible string name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |         return '' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  | if __name__ == '__main__': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  |     reg1 = PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |     reg2 = PhiFunctionRegistry() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 |  |  |     reg3 = PhiFunctionRegistry.get_instance() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 |  |  |     assert id(reg1) == id(reg2) == id(reg3) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 208 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 209 |  |  |     @PhiFunctionRegistrator.register | 
            
                                                                                                            
                            
            
                                    
            
            
                | 210 |  |  |     def example(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 211 |  |  |         """Inherited Docstring""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 212 |  |  |         print('Called example function') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 213 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 214 |  |  |     example() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 215 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 216 |  |  |     print(example.__name__) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 217 |  |  |     print('--') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 218 |  |  |     print(example.__doc__) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 219 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 220 |  |  |     reg1.get('example')() | 
            
                                                        
            
                                    
            
            
                | 221 |  |  |  |