Package: tpify
tpifyPronounced like "typify"Return, don't raise.What this doestpifyallows you to configure functions to return contextual statuses, and to return errors rather than raise them.Why?Python programs often have inconsistent conventions when it comes to returning data. They also have a problem of not making it clear when exceptions can be raised. This is an attempt to see if there is enough benefit to violate Pythonic conventions to get some additional reliability and improved (albeit verbose,Go-like) error handling.BenefitsNo moretry/exceptAll tpified functions return an object, removing the need to wrap functions in atryblock. This leads to safer, more predictable execution paths. Exceptions are still returned when raised, and the ability to customize which status code is returned means the type and source of error can be more easily communicated.Better contextTPResponseobjects contain status codes, enabling richer context about successes and failures. For example:Functions that returnTruecan return context about whether a new resource was created usingtp.Createdstatus, or updated using thetp.Updatedstatus.Functions that returnNonecan return information about whetherNonemeans a successful or failed execution.Failure origination can be returned to indicate if the error is an error with the input data (tp.InputErrorresponses), or with the processing of the data iteself (tp.ProcessingErrorresponses).
If you can't find a code that works for you, there is always the option to create your own.Dos and Don'tsDO: Check yourTPResponsestatus codes. While youcanjust take thecontentof aTPResponseif you only want the safety of avoiding unintendedraisestatements, it is encouraged to have some paradigm to processstatus_codevalues.DO: append_tpat the end of tpified function names. This communicates that this function returns aTPResponseobject, since the function itself may show it returns a different type.fromtpifyimporttpify@tpify()deffibonacci_tp(n:int)->int:# TODO: Implement fibonacci recursivelyDO: use@tpify()after non-return type-modifying decorators. If you have multiple decorators on a tpified function, havetpify()be after those that don't modify return types, so that the return types are accounted for in any other decorator logic.fromfunctoolsimportcachefromtpifyimporttpify@cache@tpify()deffibonacci_tp(n:int):# TODO: Implement fibonacci recursivelyAdvanced usesexception_type_mapThe@tpify()decorator takes an optional argument that maps raised exceptions toTPStatuscodes. This allows you to map errors to status codes other than the defaultTPStatus.ProcessingErrorvalue. For example:importjsonfromtypingimportAnyfromtpifyimportappend_statuses_tp,tp,tpify@tpify(exception_type_map={json.JSONDecodeError:tp.InputError})defparse_json_tp(json_str:str)->Any:return(tp.OK,json.loads(json_str))if__name__=="__main__":status,resp=parse_json_tp('{"fibNum": 13}')print(type(status))print(status==tp.OK)print(status==tp["OK"])print(resp)status,resp=parse_json_tp('{"fibNum": error}')print(type(status))print(status==tp.InputError)print(status==tp["InputError"])print(resp)<enum 'TPStatus'>TrueTrue{'fibNum': 13}<enum 'TPStatus'>TrueTrueAdding customTPStatusvaluesYou can add customTPStatusvalues usingappend_statuses_tp(). This ends up creating a newTPStatusCustomobject that contains the originalTPStatuscodes, as well as the new ones you request. Here's the gist of how that works:importjsonfromtypingimportAnyfromtpifyimportappend_statuses_tp,tp,tpifytp_status,tp_cust=append_statuses_tp(statuses=("JSONParseOK","JSONParseFailed",))iftp_status!=tp.OK:print(f"ERROR: Could not create new statuses:{tp_cust}")exit(1)@tpify(exception_type_map={json.JSONDecodeError:tp_cust.JSONParseFailed})defparse_json_tp(json_str:str)->Any:return(tp_cust.JSONParseOK,json.loads(json_str))if__name__=="__main__":status,resp=parse_json_tp('{"fibNum": 13}')print(type(status))print(status==tp_cust.JSONParseOK)print(status==tp_cust["JSONParseOK"])print(resp)status,resp=parse_json_tp('{"fibNum": error}')print(type(status))print(status==tp_cust.JSONParseFailed)print(status==tp_cust["JSONParseFailed"])print(resp)<enum 'TPStatusCustom'>TrueTrue{'fibNum': 13}<enum 'TPStatusCustom'>TrueTrueExpecting value: line 1 column 12 (char 11)