| 1 |  |  | import abc | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | import inspect | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | import types | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | from functools import wraps | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | __all__ = ['Transformer'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | class TransformerInterface(abc.ABC): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |     """The interface defining a method to transform structured data. Anyone, implementing this has the ability to receive | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |     some kind of data and return some kind of transformed version of them. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |     @abc.abstractmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |     def transform(self, data, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |         """Takes data and optional keyword arguments and transforms them. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |         Input data can represent either a single variable of an observation (scalar) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |         or a vector of observations of the same variable (if N observations then returns a [N x 1] array-like). | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |         Example 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |         obs1 = [x1, y1, z1] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |         fa = f_a(x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         fb = f_b(x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |         fc = f_c(x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         feature_vector1 = [fa(x1), fb(y1), fc(z1)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         So, each of fa, fb and fc can implement the Transformer interface. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |         Example 2: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |         obs1 = [x1, y1, z1] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |         obs2 = [x2, y2, z2] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |         obs3 = [x3, y3, z3] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |         obs4 = [x4, y4, z4] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |         data = [obs1; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |                 obs2; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |                 obs3; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |                 obs4]  shape = (4,3) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |         fa = f_a(x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         fb = f_b(x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |         fc = f_c(x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |         feature_vectors = [fa(data[:0], fb(data[:1], fc(data[:2])]  - shape = (4,3) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |         Again each of fa, fb and fc can implement the Transformer interface. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |             data (object): the input data to transform; the x in an f(x) invocation | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |             NotImplementedError: [description] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         raise NotImplementedError | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  | class RuntimeTransformer(TransformerInterface, abc.ABC): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |     """Examines whether the input object is callable, if it can receive at least one input argument and also | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |     whether it can accept kwargs. Depending on the kwargs check, "configures" the '_transform' method to process | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |      any kwargs at runtime or to ignore them. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |     Delegates all the transformation operation to its '_transform' method provided by its '_callable' field. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |         a_callable (callable): a callable object used to delegate the transformation operation | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |     def __new__(cls, *args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         x = super().__new__(cls) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         a_callable = args[0] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         if not callable(a_callable): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |             raise ValueError(f"Expected a callable as argument; instead got '{type(a_callable)}'") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |         nb_mandatory_arguments = a_callable.__code__.co_argcount  # this counts sums both *args and **kwargs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         # use syntax like 'def a(b, *, c=1, d=2): .. to separate pos args from kwargs and to inform 'inspect' lib about it | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |         if nb_mandatory_arguments < 1: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |             raise ValueError(f"Expected a callable that receives at least one positional argument; instead got a callable that " | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |                              f"receives '{nb_mandatory_arguments}'") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |         signature = inspect.signature(a_callable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |         parameters = [param for param in signature.parameters.values()] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |         if 1 < nb_mandatory_arguments: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |             def _transform(self, data, **keyword_args): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |                 return a_callable(data, **keyword_args) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |             x._transform = types.MethodType(_transform, x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |         elif nb_mandatory_arguments == len(parameters): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |             def _transform(self, data, **keyword_args): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |                 return a_callable(data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |             x._transform = types.MethodType(_transform, x) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |             raise Exception(f"Something went really bad. Check code above. Parameters: [{', '.join(str(_) for _ in parameters)}]") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |         x._callable = a_callable | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |         return x | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 87 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 88 |  |  |     def transform(self, data, **kwargs): | 
            
                                                        
            
                                    
            
            
                | 89 |  |  |         return self._transform(data, **kwargs) | 
            
                                                        
            
                                    
            
            
                | 90 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 91 |  |  | class Transformer(RuntimeTransformer): pass |