pamda.pamda_curry
1import types, threading, ctypes 2from functools import update_wrapper 3import type_enforced 4 5 6class curry_obj: 7 def __init__( 8 self, 9 __fn__, 10 *__args__, 11 __flips__=[], 12 __fnExecute__=None, 13 __isThunk__=False, 14 __isTypeEnforced__=False, 15 **__kwargs__, 16 ): 17 update_wrapper(self, __fn__) 18 self.__fn__ = __fn__ 19 self.__fnExecute__ = ( 20 __fnExecute__ if __fnExecute__ is not None else __fn__ 21 ) 22 self.__args__ = __args__ 23 self.__kwargs__ = __kwargs__ 24 self.__isCurried__ = True 25 self.__isThunk__ = __isThunk__ 26 self.__isTypeEnforced__ = __isTypeEnforced__ 27 self.__flips__ = __flips__ 28 self.__fnArity__ = self.__getFnArity__() 29 self.__arity__ = self.__getArity__(__args__, __kwargs__) 30 self.__thread__ = None 31 self.__thread_results__ = None 32 33 def __call__(self, *args, **kwargs): 34 new_args = self.__args__ + args 35 new_kwargs = dict(**self.__kwargs__, **kwargs) 36 self.__arity__ = self.__getArity__(new_args, new_kwargs) 37 if self.__arity__ < 0: 38 self.__exception__("Too many arguments were supplied") 39 if self.__arity__ == 0: 40 if len(self.__flips__) > 0: 41 new_args = self.__unflipArgs__(new_args) 42 if (not self.__isThunk__) or (len(args) + len(kwargs) == 0): 43 results = self.__fnExecute__(*new_args, **new_kwargs) 44 if self.__thread__ != None: 45 self.__thread_results__ = results 46 return results 47 return curry_obj( 48 self.__fn__, 49 *new_args, 50 __flips__=self.__flips__, 51 __isThunk__=self.__isThunk__, 52 __isTypeEnforced__=self.__isTypeEnforced__, 53 __fnExecute__=self.__fnExecute__, 54 **new_kwargs, 55 ) 56 57 def __get__(self, instance, owner): 58 def bind(*args, **kwargs): 59 if instance is not None and self.__arity__ == self.__fnArity__: 60 return self.__call__(instance, *args, **kwargs) 61 else: 62 return self.__call__(*args, **kwargs) 63 64 return bind 65 66 def __repr__(self): 67 return f"<curried {self.__fn__.__module__}.{self.__fn__.__qualname__} object at {hex(id(self))}>" 68 69 def __getArity__(self, args, kwargs): 70 return self.__fnArity__ - (len(args) + len(kwargs)) 71 72 def __getFnArity__(self): 73 if not isinstance(self.__fn__, (types.MethodType, types.FunctionType)): 74 self.__exception__( 75 "A non function was passed as a function and does not have any arity. See the stack trace above for more information." 76 ) 77 extra_method_input_count = ( 78 1 if isinstance(self.__fn__, (types.MethodType)) else 0 79 ) 80 return self.__fn__.__code__.co_argcount - extra_method_input_count 81 82 def thunkify(self): 83 self.__isThunk__ = True 84 return self 85 86 def flip(self): 87 if self.__arity__ < 2: 88 self.__exception__( 89 "To `flip` a function, it must have an arity of at least 2 (take two or more inputs)" 90 ) 91 self.__flips__ = [len(self.__args__)] + self.__flips__ 92 return self 93 94 def __unflipArgs__(self, args): 95 args = list(args) 96 for flip in self.__flips__: 97 arg = args.pop(flip + 1) 98 args.insert(flip, arg) 99 return tuple(args) 100 101 def __exception__(self, message): 102 pre_message = ( 103 f"({self.__fn__.__module__}.{self.__fn__.__qualname__}_curried): " 104 ) 105 raise Exception(pre_message + message) 106 107 def typeEnforce(self): 108 if not self.__isTypeEnforced__: 109 self.__fnExecute__ = type_enforced.Enforcer(self.__fnExecute__) 110 self.__isTypeEnforced__ = True 111 return self 112 113 def asyncRun(self, daemon=False): 114 if not self.__isThunk__ and self.__arity__ == 0: 115 self.__exception__( 116 f"To `asyncRun` a Function, it must be a thunk with arity 0" 117 ) 118 if self.__thread__ is not None: 119 self.__exception__( 120 "`asyncRun` has already been executed on this thunk" 121 ) 122 self.__thread_completed__ = False 123 self.__thread__ = threading.Thread(target=self) 124 self.__thread__.setDaemon(daemon) 125 self.__thread__.start() 126 return self 127 128 def asyncWait(self): 129 if self.__thread__ == None: 130 self.__exception__( 131 f"To `asyncWait` a Function, it must be `asyncRun` first" 132 ) 133 if not self.__thread_completed__: 134 self.__thread__.join() 135 self.__thread_completed__ = True 136 return self.__thread_results__ 137 138 def asyncKill(self): 139 if self.__thread__ == None: 140 self.__exception__( 141 f"To `asyncKill` a Function, it must be `asyncRun` first" 142 ) 143 if self.__thread_completed__: 144 return self.__thread_results__ 145 146 thread_id = self.__thread__.ident 147 if thread_id is None: 148 self.__exception__( 149 f"Cannot `asyncKill` a Function that does not have a thread id" 150 ) 151 152 # Use ctypes to set the async exception 153 try: 154 res = ctypes.pythonapi.PyThreadState_SetAsyncExc( 155 ctypes.c_long(thread_id), ctypes.py_object(SystemExit) 156 ) 157 except: 158 self.__exception__( 159 f"Failed to `asyncKill`: Something failed when seting the Exit state for thread id ({thread_id})" 160 ) 161 if res == 0: 162 self.__exception__( 163 f"Failed to `asyncKill`: Thread id not found ({thread_id})" 164 ) 165 elif res == 1: 166 # Success, thread killed join the thread to clean up resources 167 self.__thread_completed__ = True 168 self.__thread__.join() 169 return self.__thread_results__ 170 elif res > 1: 171 # Something is wrong, set it back to 0 172 ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0) 173 self.__exception__( 174 f"Failed to `asyncKill`: ctypes returned multiple results for thread id ({thread_id}). This should not happen. Returned thread state back to normal." 175 )
class
curry_obj:
7class curry_obj: 8 def __init__( 9 self, 10 __fn__, 11 *__args__, 12 __flips__=[], 13 __fnExecute__=None, 14 __isThunk__=False, 15 __isTypeEnforced__=False, 16 **__kwargs__, 17 ): 18 update_wrapper(self, __fn__) 19 self.__fn__ = __fn__ 20 self.__fnExecute__ = ( 21 __fnExecute__ if __fnExecute__ is not None else __fn__ 22 ) 23 self.__args__ = __args__ 24 self.__kwargs__ = __kwargs__ 25 self.__isCurried__ = True 26 self.__isThunk__ = __isThunk__ 27 self.__isTypeEnforced__ = __isTypeEnforced__ 28 self.__flips__ = __flips__ 29 self.__fnArity__ = self.__getFnArity__() 30 self.__arity__ = self.__getArity__(__args__, __kwargs__) 31 self.__thread__ = None 32 self.__thread_results__ = None 33 34 def __call__(self, *args, **kwargs): 35 new_args = self.__args__ + args 36 new_kwargs = dict(**self.__kwargs__, **kwargs) 37 self.__arity__ = self.__getArity__(new_args, new_kwargs) 38 if self.__arity__ < 0: 39 self.__exception__("Too many arguments were supplied") 40 if self.__arity__ == 0: 41 if len(self.__flips__) > 0: 42 new_args = self.__unflipArgs__(new_args) 43 if (not self.__isThunk__) or (len(args) + len(kwargs) == 0): 44 results = self.__fnExecute__(*new_args, **new_kwargs) 45 if self.__thread__ != None: 46 self.__thread_results__ = results 47 return results 48 return curry_obj( 49 self.__fn__, 50 *new_args, 51 __flips__=self.__flips__, 52 __isThunk__=self.__isThunk__, 53 __isTypeEnforced__=self.__isTypeEnforced__, 54 __fnExecute__=self.__fnExecute__, 55 **new_kwargs, 56 ) 57 58 def __get__(self, instance, owner): 59 def bind(*args, **kwargs): 60 if instance is not None and self.__arity__ == self.__fnArity__: 61 return self.__call__(instance, *args, **kwargs) 62 else: 63 return self.__call__(*args, **kwargs) 64 65 return bind 66 67 def __repr__(self): 68 return f"<curried {self.__fn__.__module__}.{self.__fn__.__qualname__} object at {hex(id(self))}>" 69 70 def __getArity__(self, args, kwargs): 71 return self.__fnArity__ - (len(args) + len(kwargs)) 72 73 def __getFnArity__(self): 74 if not isinstance(self.__fn__, (types.MethodType, types.FunctionType)): 75 self.__exception__( 76 "A non function was passed as a function and does not have any arity. See the stack trace above for more information." 77 ) 78 extra_method_input_count = ( 79 1 if isinstance(self.__fn__, (types.MethodType)) else 0 80 ) 81 return self.__fn__.__code__.co_argcount - extra_method_input_count 82 83 def thunkify(self): 84 self.__isThunk__ = True 85 return self 86 87 def flip(self): 88 if self.__arity__ < 2: 89 self.__exception__( 90 "To `flip` a function, it must have an arity of at least 2 (take two or more inputs)" 91 ) 92 self.__flips__ = [len(self.__args__)] + self.__flips__ 93 return self 94 95 def __unflipArgs__(self, args): 96 args = list(args) 97 for flip in self.__flips__: 98 arg = args.pop(flip + 1) 99 args.insert(flip, arg) 100 return tuple(args) 101 102 def __exception__(self, message): 103 pre_message = ( 104 f"({self.__fn__.__module__}.{self.__fn__.__qualname__}_curried): " 105 ) 106 raise Exception(pre_message + message) 107 108 def typeEnforce(self): 109 if not self.__isTypeEnforced__: 110 self.__fnExecute__ = type_enforced.Enforcer(self.__fnExecute__) 111 self.__isTypeEnforced__ = True 112 return self 113 114 def asyncRun(self, daemon=False): 115 if not self.__isThunk__ and self.__arity__ == 0: 116 self.__exception__( 117 f"To `asyncRun` a Function, it must be a thunk with arity 0" 118 ) 119 if self.__thread__ is not None: 120 self.__exception__( 121 "`asyncRun` has already been executed on this thunk" 122 ) 123 self.__thread_completed__ = False 124 self.__thread__ = threading.Thread(target=self) 125 self.__thread__.setDaemon(daemon) 126 self.__thread__.start() 127 return self 128 129 def asyncWait(self): 130 if self.__thread__ == None: 131 self.__exception__( 132 f"To `asyncWait` a Function, it must be `asyncRun` first" 133 ) 134 if not self.__thread_completed__: 135 self.__thread__.join() 136 self.__thread_completed__ = True 137 return self.__thread_results__ 138 139 def asyncKill(self): 140 if self.__thread__ == None: 141 self.__exception__( 142 f"To `asyncKill` a Function, it must be `asyncRun` first" 143 ) 144 if self.__thread_completed__: 145 return self.__thread_results__ 146 147 thread_id = self.__thread__.ident 148 if thread_id is None: 149 self.__exception__( 150 f"Cannot `asyncKill` a Function that does not have a thread id" 151 ) 152 153 # Use ctypes to set the async exception 154 try: 155 res = ctypes.pythonapi.PyThreadState_SetAsyncExc( 156 ctypes.c_long(thread_id), ctypes.py_object(SystemExit) 157 ) 158 except: 159 self.__exception__( 160 f"Failed to `asyncKill`: Something failed when seting the Exit state for thread id ({thread_id})" 161 ) 162 if res == 0: 163 self.__exception__( 164 f"Failed to `asyncKill`: Thread id not found ({thread_id})" 165 ) 166 elif res == 1: 167 # Success, thread killed join the thread to clean up resources 168 self.__thread_completed__ = True 169 self.__thread__.join() 170 return self.__thread_results__ 171 elif res > 1: 172 # Something is wrong, set it back to 0 173 ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0) 174 self.__exception__( 175 f"Failed to `asyncKill`: ctypes returned multiple results for thread id ({thread_id}). This should not happen. Returned thread state back to normal." 176 )
curry_obj( __fn__, *__args__, __flips__=[], __fnExecute__=None, __isThunk__=False, __isTypeEnforced__=False, **__kwargs__)
8 def __init__( 9 self, 10 __fn__, 11 *__args__, 12 __flips__=[], 13 __fnExecute__=None, 14 __isThunk__=False, 15 __isTypeEnforced__=False, 16 **__kwargs__, 17 ): 18 update_wrapper(self, __fn__) 19 self.__fn__ = __fn__ 20 self.__fnExecute__ = ( 21 __fnExecute__ if __fnExecute__ is not None else __fn__ 22 ) 23 self.__args__ = __args__ 24 self.__kwargs__ = __kwargs__ 25 self.__isCurried__ = True 26 self.__isThunk__ = __isThunk__ 27 self.__isTypeEnforced__ = __isTypeEnforced__ 28 self.__flips__ = __flips__ 29 self.__fnArity__ = self.__getFnArity__() 30 self.__arity__ = self.__getArity__(__args__, __kwargs__) 31 self.__thread__ = None 32 self.__thread_results__ = None
def
asyncRun(self, daemon=False):
114 def asyncRun(self, daemon=False): 115 if not self.__isThunk__ and self.__arity__ == 0: 116 self.__exception__( 117 f"To `asyncRun` a Function, it must be a thunk with arity 0" 118 ) 119 if self.__thread__ is not None: 120 self.__exception__( 121 "`asyncRun` has already been executed on this thunk" 122 ) 123 self.__thread_completed__ = False 124 self.__thread__ = threading.Thread(target=self) 125 self.__thread__.setDaemon(daemon) 126 self.__thread__.start() 127 return self
def
asyncKill(self):
139 def asyncKill(self): 140 if self.__thread__ == None: 141 self.__exception__( 142 f"To `asyncKill` a Function, it must be `asyncRun` first" 143 ) 144 if self.__thread_completed__: 145 return self.__thread_results__ 146 147 thread_id = self.__thread__.ident 148 if thread_id is None: 149 self.__exception__( 150 f"Cannot `asyncKill` a Function that does not have a thread id" 151 ) 152 153 # Use ctypes to set the async exception 154 try: 155 res = ctypes.pythonapi.PyThreadState_SetAsyncExc( 156 ctypes.c_long(thread_id), ctypes.py_object(SystemExit) 157 ) 158 except: 159 self.__exception__( 160 f"Failed to `asyncKill`: Something failed when seting the Exit state for thread id ({thread_id})" 161 ) 162 if res == 0: 163 self.__exception__( 164 f"Failed to `asyncKill`: Thread id not found ({thread_id})" 165 ) 166 elif res == 1: 167 # Success, thread killed join the thread to clean up resources 168 self.__thread_completed__ = True 169 self.__thread__.join() 170 return self.__thread_results__ 171 elif res > 1: 172 # Something is wrong, set it back to 0 173 ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0) 174 self.__exception__( 175 f"Failed to `asyncKill`: ctypes returned multiple results for thread id ({thread_id}). This should not happen. Returned thread state back to normal." 176 )