I’m not entirely sure if this is the most efficient approach, but I’ve found it to be a time-saver when debugging with print statements. It might seem a bit lengthy, and there’s room to add more statements for further refinement, but it serves as a useful debugging tool.
In the debug server module:
import inspect
import os
def print_debug_info(locals=None, details=False, print_keys_list=False):
"""
Print debug information based on the given locals dictionary.
Args:
locals (dict, optional): The locals dictionary containing the variables to print. Defaults to None.
details (bool, optional): Flag indicating whether to print detailed information about each variable. Defaults to False.
print_keys_list (bool, optional): Flag indicating whether to print the keys list for dictionaries and search iterators. Defaults to False.
"""
#Turned off for publised branch
if anvil.server.get_app_origin() == "YOUR APP URL":
return
print('Debug information:')
if details:
# Get the caller's frame information
caller_frame = inspect.currentframe().f_back
caller_func_name = caller_frame.f_code.co_name
caller_line_number = caller_frame.f_lineno
caller_file_path = os.path.abspath(inspect.getfile(caller_frame.f_code))
print(f"Caller Function: {caller_func_name}")
print(f"Line Number: {caller_line_number}")
print(f"File Path: {caller_file_path}")
type_actions = {
list: lambda key, value: print_list(key, value),
dict: lambda key, value: print_dict(key, value, print_keys_list),
tuple: lambda key, value: print_tuple(key, value),
set: lambda key, value: print_set(key, value),
str: lambda key, value: print_string(key, value),
bool: lambda key, value: print_bool(key, value),
int: lambda key, value: print_int(key, value),
float: lambda key, value: print_float(key, value),
type(None): lambda key, value: print_none(key),
anvil.tables.SearchIterator: lambda key, value: print_search_iterator(key, value, print_keys_list),
anvil.tables.v2._row.Row: lambda key, value: print_row(key, value, print_keys_list),
}
if locals:
for key, value in locals.items():
if details:
for type_, action in type_actions.items():
if isinstance(value, type_):
action(key, value)
break
else:
print(key, "is of unknown type.")
else:
print(key, value)
def print_list(key, value):
print(key, "is a list. With a length", len(value))
for item in value:
print(item)
def print_dict(key, value, print_keys_list):
print(key, "is a dictionary.")
for k, v in value.items():
print(f"Key: {k}, Value: {v}")
if print_keys_list:
print("Keys:", list(value.keys()))
def print_tuple(key, value):
print(key, "is a tuple.")
for item in value:
print(item)
def print_set(key, value):
print(key, "is a set.")
for item in value:
print(item)
def print_string(key, value):
print(key, "is a string.")
print(value)
def print_bool(key, value):
print(key, "is a boolean.")
print(value)
def print_int(key, value):
print(key, "is an integer.")
print(value)
def print_float(key, value):
print(key, "is a float.")
print(value)
def print_none(key):
print(key, "is None.")
def print_search_iterator(key, value, print_keys_list):
print(key, "is a SearchIterator object. With a length", len(value))
print(value)
if print_keys_list and len(value):
print_row(key, value[0], print_keys_list)
def print_row(key, value, print_keys_list):
print(key, "is a Row object.")
print(value)
if print_keys_list:
print(list({key for key, x in value.items()}))
To call from a funcation:
DebugModule.print_debug_info(locals(), details = True, print_key_list = True)