"""Utilities for debugging"""from__future__importannotationsimportloggingimportsysimporttimefromdatetimeimportdatetimefromtypingimportDict,Listimportwraptfromrichimportprint__all__=["debug_breakpoint","debug_watch","get_debug_flags","get_debug_options","is_debug","set_debug","wrap_function",]# global variable to control debug output# set via --debug__osxphotos_debug=False
defdebug_watch(wrapped,instance,args,kwargs):"""For use with wrapt.wrap_function_wrapper to watch calls to a function"""caller=sys._getframe().f_back.f_code.co_namename=wrapped.__name__timestamp=datetime.now().isoformat()print(f"{timestamp}{name} called from {caller} with args: {args} and kwargs: {kwargs}")start_t=time.perf_counter()rv=wrapped(*args,**kwargs)stop_t=time.perf_counter()print(f"{timestamp}{name} returned: {rv}, elapsed time: {stop_t-start_t} sec")returnrvdefdebug_breakpoint(wrapped,instance,args,kwargs):"""For use with wrapt.wrap_function_wrapper to set breakpoint on a function"""breakpoint()returnwrapped(*args,**kwargs)defwrap_function(function_path,wrapper):"""Wrap a function with wrapper function"""module,name=function_path.split("::",1)try:returnwrapt.wrap_function_wrapper(module,name,wrapper)exceptAttributeErrorase:raiseAttributeError(f"{module}.{name} does not exist")fromedefget_debug_options(arg_names:List,argv:List)->Dict:"""Get the options for the debug options; Some of the debug options like --watch and --breakpoint need to be processed before any other packages are loaded so they can't be handled in the normal click argument processing, thus this function is called from osxphotos/cli/__init__.py Assumes multi-valued options are OK and that all options take form of --option VALUE or --option=VALUE """# argv[0] is the program name# argv[1] is the command# argv[2:] are the argumentsargs={}forarg_nameinarg_names:foridx,arginenumerate(argv[1:]):ifarg.startswith(f"{arg_name}="):arg_value=arg.split("=")[1]try:args[arg].append(arg_value)exceptKeyError:args[arg]=[arg_value]elifarg==arg_name:try:args[arg].append(argv[idx+2])exceptKeyError:try:args[arg]=[argv[idx+2]]exceptIndexErrorase:raiseValueError(f"Missing value for {arg}")fromeexceptIndexErrorase:raiseValueError(f"Missing value for {arg}")fromereturnargsdefget_debug_flags(arg_names:List,argv:List)->Dict:"""Get the flags for the debug options; Processes flags like --debug that resolve to True or False """# argv[0] is the program name# argv[1] is the command# argv[2:] are the argumentsargs={arg_name:Falseforarg_nameinarg_names}forarg_nameinarg_names:ifarg_nameinargv[1:]:args[arg_name]=Truereturnargs