'''v20200114 Administrative functions to track timing of python program and specific steps ('laps') within program ''' #--------------------------------------------------------------------- # STARTUP #--------------------------------------------------------------------- def startup(print_to_log = False): '''Print start time and save time to variable for later calculations''' import datetime import inspect import sys import time global time_lap, time_start time_start = time.time() time_lap = time.time() # loop through the stack of the running job and find the program # that called this function -- assume that is parent job for stack_item in inspect.stack(): # stack_item[4] is a list showing how the stack item was called # this startup() function is listed as the 0th element if 'admin_functions.startup(' in stack_item[4][0]: file_name = stack_item[1] # make the log path/name the same as the program, but set extension to .log log_name = file_name.replace('.py', '.log') # redirect output from console to text file if print_to_log: sys.stdout = open(log_name, 'w') pass print('\n') print(f'{"file:":<15} {file_name.split("/")[-1]}') print(f'{"start time:":<15} {datetime.datetime.now()}\n') #--------------------------------------------------------------------- # LAP_TIME #--------------------------------------------------------------------- def lap_time(lap_task = True): '''Calculate and print time since last lap was started''' import time import admin_functions global time_lap # If nothing has been printed since lap_task was called, time is # printed right-justified in the same line left open by lap_task. # Else, time may be printed in odd location, so when lap_task set # to False, print time right-justified on new line if not lap_task: print(' '*90) try: print(f'{admin_functions.print_secs(time.time() - time_lap):>11}') # in case time_lap is not available (e.g. startup() was not run), # do not error out but print blank time except: print(f'{"n/a":>11}') time_lap = time.time() #--------------------------------------------------------------------- # PRINT_SECS #--------------------------------------------------------------------- def print_secs(secs): '''Turn seconds (with decimal places) into easy to read time format; max width of output is 11 (123:45:67.8)''' # round to tenth of second secs = round(secs, 1) # strip off full hours hours = int(secs // 3600) remaining = secs - hours * 3600 # strip off full minutes mins = int(remaining // 60) remaining -= mins * 60 secs = remaining if hours > 0: return f'{hours}:{mins:02}:{secs:04.1f}' elif mins > 0: return f'{mins}:{secs:04.1f}' else: return f'{secs:.1f} s' #--------------------------------------------------------------------- # LAP_TASK #--------------------------------------------------------------------- def lap_task(task_name): '''Grab time of starting task, print partial line with task name''' import sys # process new line printing first, then exclude from spacing calc while task_name.startswith('\n'): print() task_name = task_name[1:] sys.stdout.write(f'{f"{task_name.expandtabs(4)}...":<90}') # print output without waiting for rest of line sys.stdout.flush() #--------------------------------------------------------------------- # SHUTDOWN #--------------------------------------------------------------------- def shutdown(): '''Calculate total run time at end of program''' import datetime import sys import time import admin_functions print('\n') print(f'stop time:\t\t{datetime.datetime.now()}') time_stop = time.time() print(f'{"total time:":<90}' f'{admin_functions.print_secs(time_stop - time_start):>11}\n') # if output was redirected to a log file, set back to console sys.stdout = sys.__stdout__