Package: ret-tools
ret-toolsret-tools is a small library used for formating function responses, handling function exceptions, executing and handling asynchronous tasks. View examples below:Handling Functionsret-tools is built off two main functions:run()andrun_async()both return a RetResp with four properties:success (bool True or False),
msg ("Success" or Exception),
tb (None or Exception Traceback),
resp (None or response of original function)RetResp can be treated asa list[success, msg, tb, resp],
a dict{"success": True, "msg": "Success", "tb": None, "resp": "some random data"},
or a str:Succeeded: some random data,Example ofrun():importret_toolsasrtdeffunc(name):return"Hi{}".format(name)defmain():ret=rt.run(func,("John Smith"))print(ret.success)# Trueprint(ret.msg)# Successprint(ret.resp)# "Hi John Smith"print(tuple(ret))# (True, "Success", None, "Hi John Smith")if__name__=="__main__":main()Example ofrun_async()importret_toolsasrtimportasyncioasyncdefafunc(name):awaitasyncio.sleep(1)return"HI{}".format(name)defmain():ret=asyncio.run(rt.run_async(afunc("John Smith")))print(ret.success)# Trueprint(ret.msg)# Successprint(ret.resp)# "Hi John Smith"print(tuple(ret))# (True, "Success", None, "Hi John Smith")if__name__=="__main__":main()If a function throws an Exception the response is as follows:importret_toolsasrtdeffunc():raiseException("Something went wrong")defmain():ret=rt.run(func)print(ret.success)# Falseprint(ret.msg)# Exception("Something went wrong")print(ret.resp)# Noneprint(tuple(ret))# (False, Exception("Something went wrong"), "Traceback: ...", None)if__name__=="__main__":main()ret-tools can be configured with a RetConfig object, you can specify a failed callback, error callback, and a task callbackfailed callbackret_config.ffgets called when a function throws an error, this can change on a function to function basis, you can also specify custom arguments, an example would be a websocket client that closes the connection when a send or recv failserror callbackret_config.ecgets called every time a function throws an error, it is global and can't change on a function-to-function basis, this can be used for logging purposes, the argument will be a RetResptask callbackret_config.tcgets called when a async task finishes, this can be changed on a task to task basis, the argument will be a RetRespExample:importret_toolsasrtdeferror_callback(err_resp):print(err_resp)# Failed: Exception Textret_config=rt.RetConfig(ec=error_callback)rt.init(ret_config)deffailed(function_name,other_arg):print("{}Failed,{}".format(function_name,other_arg))# Do something if function failsdeffunc(*args):raiseException("Function Failed")defmain():#            function, fargs, failed_func, *failed_argsret=rt.run(func,(),failed,"Name of function","some other argument")print(ret.success)# Falseif__name__=="__main__":main()Function Decoratorsret-tools offer two different function decorators:@def_ret()and@async_ret()each decorator will pass the function throughrt.run()orrt.run_async()Example:importret_toolsasrt@rt.def_ret()deffunc():return"some random data"defmain():ret=func()print(ret.success)# Trueprint(ret.resp)# "some random data"print(tuple(ret))# (True, "Success", None, "some random data")if__name__=="__main__":main()You can also specify custom failed callbacks through the decoratorsExample:importret_toolsasrtdeffunction_failed(arg1,arg2):print("Failed:{}{}".format(arg1,arg2))# Failed: func failed@rt.def_ret(function_failed,"func","failed")deffunc():raiseException("Failed")defmain():ret=func()print(ret.success)# Trueprint(ret.msg)# Failedif__name__=="__main__":main()Handling Tasksret-tools can also be used to handle asynchronous tasks, there are two main methods:create_task(),wait_task()Example ofcreate_task():importret_toolsasrtimportasynciodeftask_callback(resp):# response is a RetResp objectprint(resp)# Succeeded: Hi John Smithasyncdeftask(name):awaitasyncio.sleep(1)return"Hi{}".format(name)defmain():t=rt.create_task(task("John Smith"),task_callback)# returns asyncio.Taskif__name__=="__main__":main()create_task()works even when no asyncio event loop is present, ret-tools will detect if a loop is running, if not it will create a new loop and run it in a seperate thread then it will execute the task from thereExample ofwait_task():importret_toolsasrtimportasyncioasyncdeftask(name):awaitasyncio.sleep(1)return"Hi{}".format(name)defmain():resp=rt.wait_task(task("John Smith"))print(resp)# Succeeded: Hi John Smithasyncdefasync_main():resp=awaitrt.run_async(task("John Smith"))print(resp)# Succeeded: Hi John Smithresp=awaitrt.create_task(task("John Smith"))print(resp)# Succeeded: Hi John Smithif__name__=="__main__":main()asyncio.run(async_main())rt.wait_task()is equivilent toawait rt.create_task()which is equivilent toawait rt.run_async()If there is no event loop usert.wait_task(), If you have an event loop and you want the response imediately useawait rt.run_async(), if you want the response in a callback usert.create_task(task(), callback)Good and BadRetResp's are built off two functionsgood()andbad()good()returns(True, "Success", None)alwaysbad()returns(False, Exception, Traceback)usingsys.exc_info()andtraceback.print_exc()Example:importret_toolsasrtdefmain():ret=Nonetry:print("Do Something Here")ret=rt.good()except:ret=rt.bad()print(tuple(ret))# (True, "Success", None)ret=Nonetry:raiseException("Something went wrong")ret=rt.good()# Won't happen because exception is raisedexcept:ret=rt.bad()print(tuple(ret))# (False, Exception("Something went wrong"), "Traceback: ...")if__name__=="__main__":main()