""" debug_lib A bunch of helpful debuging functions Cal.W 2025 """ import numpy as np # Consts IS_CLOSE_VAR = 0.001 # Horriable ENUM types class NO_EVAL(type): pass # Whats an enum? class TUPLE_EVAL(type): pass def compair_outputs(tasks): """ callable, args, expected, force comp type tasks: Tuple[Tuple[callable, Tuple[...], Expacted, [TYPE]], ...] tasks = ( (determine_power_used, (5e6, 250, 8, 85), 500.9191176470588), (determine_water_released, (300, 250, 8, 85), 2994495.4128440367), (determine_cost_to_pump, (300, 8, 0.02), 48), (calc_speed_at_outlet, (30,), 24.261079942986875), (calc_new_water_height, (20, 40000, 1, 30), (19.985143183382704, 592567.1021442247)), (calc_heights_water_out, (40, 5, 40000, 1, 30), ((39.97898928844613, 39.95798409574207, 39.93698442188801), (838016.4324684857, 837796.3120398963, 837576.1916037091), TUPLE_EVAL)), ) """ for i, (task, args, expected) in enumerate(tasks): print(f'Task {i+1}') result = task(*args) # Number comparison if isinstance(expected, (float, int)): foo = np.isclose(result, expected, IS_CLOSE_VAR) print(f'{task.__qualname__}{args}') print(f' -> {result} {"~=" if foo else "!="} {expected}') print(f'Task is{"" if foo else " NOT"} close enough to expected result.') # Run the task and print out what is is expected on a new line elif isinstance(expected, (list, tuple)) and expected[-1] is NO_EVAL: print(f'{task.__qualname__}{args} -> {result}') print(f'Expected: {expected[:-1]}') # Do a tuple eval # [TODO] Do this, not complete elif isinstance(expected, (list, tuple)) and expected[-1] is TUPLE_EVAL: expected_result = expected[:-1] comp_lenths = tuple(len(z) for z in expected_result) flag = False for ii, comp_res in enumerate(comp_lenths): for iii in range(comp_res): bar = isinstance(expected[ii][iii], (float, int)) and isinstance(result[ii][iii], (float, int)) baz = np.isclose(result[ii][iii], expected[ii][iii], IS_CLOSE_VAR) if bar else (result[ii][iii] == expected[ii][iii]) if not baz: flag = True break if flag: break print(f'{task.__qualname__}{args} -> {tuple(result[z][:comp_lenths[z]] for z in range(len(result)))}') print(f'Expected: {expected[:-1]}') if flag: print(f"First Mismatch; result[{ii}][{iii}] -> {result[ii][iii]} != {expected[ii][iii]}") print(f'Task is{" NOT" if flag else ""} close enough to expected result.') # Literal Comparison elif expected is not None: print(f'{task.__qualname__}{args} -> {result} {"==" if result == expected else "!="} {expected}') print(f'Task is{"" if result == expected else " NOT"} equal to expected result.') # Just run the task else: print(f'{task.__qualname__}{args} -> {result}') # Newline print() class auto_input: """Given a list automagicly enter a value.""" def __init__(self, input_list): #Just setup some internal stuff self.input_index = 0 self.input_list = input_list def __call__(self, input_text): #TLDR: Get the next value from the array and return that # If there was an error then ask the user for input try: out = self.input_list[self.input_index] except: out = None self.input_index += 1 if out is None: out = __builtins__['input']('#Input#: '+input_text) else: print(str(input_text)+str(out)) return str(out) def stringCompairTests(test_function, tests, doPrint=True, logFile=None): """Run a bunch of tests on a function and check the outputs via comparing them to wanted outputs as strings. Prams: test_function: function - This needs to be the function to test tests: list - The list of tests to run. Each test is a list in the form: [(arg1, arg2, ...), expected_output] Note: The number of arguments in the tuple *must* equal the number required for the function doPrint: bool - Print the test results - Default: True logFile: str - The path to write the output as a log if it is NoneType(None) then it won't make a logfile - Default: None Returns: list - A list containing each test result as a tuple in the form: (returned_result, Bool(test_succeeded), test) Example: def doThing(arg1, arg2): return arg1 + arg2 tests = [ [(1, 2), 3], [("Hello", "World"), "HelloWorld"], [(1, 3), 2] ] test_results = stringCompairTests(doThing, tests) >>>test_results => [ (3, True, [(1, 2), 3]), ("HelloWorld", True, [("Hello", "World"), "HelloWorld"]), (4, False, [(1, 3), 2]) ] """ test_results = [] logString = "" for i, test in enumerate(tests): result = test_function(**test[0]) if type(test[0]) is dict else test_function(*test[0]) test_results.append((result, str(test[1]) == str(result), test)) logStringL = "-"*50 logStringL += "\n"+ "Test: " + str(i) + (" - Success" if result else " - Failure") logStringL += "\n"+ "Given Arguments: \"" + '", "'.join(test[0]) + '"' logStringL += "\n"+ "Expected Output: " + str(test[1]) logStringL += "\n"+ "Returned Output: " + str(result) logStringL += "\n"+ "Returned Values " + ("don't" if not result else "") + "match." logString += '\n' + logStringL if doPrint: print(logStringL) successfull_tests = sum([1 for x in test_results if x[1]]) logStringL = "\n" + str(successfull_tests) + " test" + ("s" if len(test_results)-successfull_tests == 1 else '') logStringL += " succeeded with " + str(len(test_results)-successfull_tests) + " test" logStringL += ("s" if len(test_results)-successfull_tests == 1 else "") + " failing." logString += '\n' + logStringL if doPrint: print(logStringL,"\n") if logFile not in (None, ""): if type(logFile) is bool and logFile: logFile = __file__.rsplit('\\', 1)[1] if logString[0] == "\n": logString = logString[1:] with open(str(logFile)+".log", 'w') as writeFile: writeFile.write(logString) writeFile.close() if doPrint: print("The logfile:", '\''+str(logFile)+".log'", "has been written to.", "\n") return test_results