here2share

# tk_step_debug.py

Jul 4th, 2026
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.04 KB | None | 0 0
  1. # tk_step_debug.py
  2.  
  3. import tkinter as tk
  4. from tkinter import scrolledtext
  5. import sys
  6. import io
  7. import copy
  8.  
  9. steps = []
  10. current_step_idx = -1
  11. stdout_buffer = io.StringIO()
  12. source_lines = []
  13. auto_stepping = False
  14. drag_start_x = 0
  15. drag_start_y = 0
  16.  
  17. BG_DARK = "#181824"
  18. BG_PANEL = "#1e1e2e"
  19. BG_INPUTS = "#28283d"
  20. FG_LIGHT = "#cdd6f4"
  21. FG_MUTED = "#a6adc8"
  22. ACCENT_BLUE = "#89b4fa"
  23. ACCENT_GREEN = "#a6e3a1"
  24.  
  25. CHANGED_BG_LINE = "#008800"
  26. CHANGED_BG_BOX = "#1e2e24"
  27. CHANGED_BORDER = "#40a02b"
  28.  
  29. def trace_calls(frame, event, arg):
  30.     if event not in ('line', 'call', 'return', 'exception'):
  31.         return trace_calls
  32.     stack = []
  33.     f = frame
  34.     while f:
  35.         stack.append(f"{f.f_code.co_name} (line {f.f_lineno})")
  36.         f = f.f_back
  37.     stack.reverse()
  38.    
  39.     step_data = {
  40.         'line_no': frame.f_lineno,
  41.         'event': event,
  42.         'stdout': stdout_buffer.getvalue(),
  43.         'locals': {k: copy.deepcopy(v) for k, v in frame.f_locals.items() if not k.startswith('__')},
  44.         'globals': {k: copy.deepcopy(v) for k, v in frame.f_globals.items() if not k.startswith('__')},
  45.         'stack_frames': stack
  46.     }
  47.     steps.append(step_data)
  48.     return trace_calls
  49.  
  50. def compile_and_start():
  51.     global steps, current_step_idx, stdout_buffer, source_lines, auto_stepping
  52.     auto_stepping = False
  53.     btn_play.config(text="Auto Play")
  54.    
  55.     code = code_editor.get("1.0", tk.END).strip()
  56.     if not code:
  57.         return
  58.        
  59.     source_lines = code.splitlines()
  60.     steps = []
  61.     current_step_idx = -1
  62.     stdout_buffer = io.StringIO()
  63.    
  64.     original_stdout = sys.stdout
  65.     sys.stdout = stdout_buffer
  66.    
  67.     try:
  68.         compiled = compile(code, '<string>', 'exec')
  69.         sys.settrace(trace_calls)
  70.         exec(compiled, {})
  71.     except Exception as e:
  72.         sys.settrace(None)
  73.         stdout_buffer.write(f"\n{type(e).__name__}: {e}\n")
  74.     finally:
  75.         sys.settrace(None)
  76.         sys.stdout = original_stdout
  77.  
  78.     if steps:
  79.         current_step_idx = 0
  80.         for btn in (btn_first, btn_back10, btn_back, btn_step, btn_step10, btn_last, btn_play):
  81.             btn.config(state="normal")
  82.         sync_ui_to_step()
  83.  
  84. def sync_ui_to_step():
  85.     if not steps or current_step_idx < 0:
  86.         return
  87.        
  88.     step = steps[current_step_idx]
  89.     step_label.config(text=f"Step {current_step_idx + 1} of {len(steps)} ({step['event']})")
  90.    
  91.     code_editor.tag_remove("current_line", "1.0", tk.END)
  92.     code_editor.tag_add("current_line", f"{step['line_no']}.0", f"{step['line_no']}.end")
  93.     code_editor.tag_config("current_line", background=CHANGED_BG_LINE, foreground="#ffffff")
  94.     code_editor.see(f"{step['line_no']}.0")
  95.    
  96.     console_output.config(state="normal")
  97.     console_output.delete("1.0", tk.END)
  98.     console_output.insert("1.0", step['stdout'])
  99.     console_output.config(state="disabled")
  100.    
  101.     draw_objects_diagram(step)
  102.  
  103. def draw_objects_diagram(step):
  104.     canvas.delete("all")
  105.     x_offset = 30
  106.     y_cursor = 40
  107.    
  108.     changed_vars = set()
  109.     if current_step_idx > 0:
  110.         prev_step = steps[current_step_idx - 1]
  111.        
  112.         prev_vars = {}
  113.         prev_vars.update(prev_step['globals'])
  114.         prev_vars.update(prev_step['locals'])
  115.        
  116.         curr_vars = {}
  117.         curr_vars.update(step['globals'])
  118.         curr_vars.update(step['locals'])
  119.        
  120.         for k, v in curr_vars.items():
  121.             if k not in prev_vars or prev_vars[k] != v:
  122.                 changed_vars.add(k)
  123.  
  124.     canvas.create_text(x_offset, y_cursor, text="Frames & Dynamic Heap Variables (Stack Timeline)", font=("Arial", 12, "bold"), anchor="w", fill=FG_LIGHT)
  125.     y_cursor += 40
  126.    
  127.     if step['stack_frames']:
  128.         canvas.create_text(x_offset, y_cursor, text="→ Active Call Stack:", font=("Arial", 10, "bold"), anchor="w", fill=ACCENT_BLUE)
  129.         y_cursor += 20
  130.         for frame_name in reversed(step['stack_frames']):
  131.             canvas.create_rectangle(x_offset, y_cursor, x_offset + 350, y_cursor + 28, fill="#242535", outline="#45475a", width=1)
  132.             canvas.create_text(x_offset + 10, y_cursor + 14, text=frame_name, font=("Consolas", 10, "bold"), anchor="w", fill=ACCENT_BLUE)
  133.             y_cursor += 34
  134.         y_cursor += 15
  135.  
  136.     active_variables = {}
  137.     active_variables.update(step['globals'])
  138.     active_variables.update(step['locals'])
  139.    
  140.     filtered_vars = {k: v for k, v in active_variables.items() if str(type(v)) not in ("<class 'module'>", "<class 'function'>")}
  141.    
  142.     if filtered_vars:
  143.         canvas.create_text(x_offset, y_cursor, text="→ Variables Map:", font=("Arial", 10, "bold"), anchor="w", fill=FG_MUTED)
  144.         y_cursor += 25
  145.        
  146.         for key, val in filtered_vars.items():
  147.             is_changed = key in changed_vars
  148.             var_box_bg = CHANGED_BG_BOX if is_changed else "#242535"
  149.             var_box_outline = CHANGED_BORDER if is_changed else "#45475a"
  150.             var_box_width = 2 if is_changed else 1
  151.            
  152.             canvas.create_rectangle(x_offset, y_cursor, x_offset + 500, y_cursor + 24, fill=var_box_bg, outline=var_box_outline, width=var_box_width)
  153.            
  154.             lbl_suffix = " [UPDATED]" if is_changed else ""
  155.             lbl_color = ACCENT_GREEN if is_changed else FG_LIGHT
  156.             canvas.create_text(x_offset + 10, y_cursor + 12, text=f"Variable Name: {key}{lbl_suffix}", font=("Consolas", 10, "bold"), anchor="w", fill=lbl_color)
  157.             y_cursor += 24
  158.            
  159.             if isinstance(val, (list, dict, set, tuple)):
  160.                 val_str = f"[{type(val).__name__}] {str(val)}"
  161.                 box_color = CHANGED_BG_BOX if is_changed else "#24202a"
  162.                 border_color = CHANGED_BORDER if is_changed else "#6c7086"
  163.                 text_color = ACCENT_GREEN if is_changed else "#f5c2e7"
  164.             else:
  165.                 val_str = repr(val)
  166.                 box_color = CHANGED_BG_BOX if is_changed else "#1e222a"
  167.                 border_color = CHANGED_BORDER if is_changed else "#45475a"
  168.                 text_color = ACCENT_GREEN if is_changed else "#b4befe"
  169.                
  170.             canvas.create_rectangle(x_offset, y_cursor, x_offset + 500, y_cursor + 28, fill=box_color, outline=border_color, width=var_box_width)
  171.             canvas.create_text(x_offset + 10, y_cursor + 14, text=f"Value ➔ {val_str}", font=("Consolas", 10), anchor="w", fill=text_color)
  172.             y_cursor += 42
  173.            
  174.     canvas.config(scrollregion=(0, 0, 700, max(y_cursor + 100, 800)))
  175.  
  176. def step_forward():
  177.     global current_step_idx, auto_stepping
  178.     if current_step_idx < len(steps) - 1:
  179.         current_step_idx += 1
  180.         sync_ui_to_step()
  181.     else:
  182.         auto_stepping = False
  183.         btn_play.config(text="Auto Play")
  184.  
  185. def step_forward_10():
  186.     global current_step_idx, auto_stepping
  187.     if steps:
  188.         current_step_idx = min(len(steps) - 1, current_step_idx + 10)
  189.         sync_ui_to_step()
  190.         if current_step_idx == len(steps) - 1:
  191.             auto_stepping = False
  192.             btn_play.config(text="Auto Play")
  193.  
  194. def step_back():
  195.     global current_step_idx
  196.     if current_step_idx > 0:
  197.         current_step_idx -= 1
  198.         sync_ui_to_step()
  199.  
  200. def step_back_10():
  201.     global current_step_idx
  202.     if steps:
  203.         current_step_idx = max(0, current_step_idx - 10)
  204.         sync_ui_to_step()
  205.  
  206. def go_to_first():
  207.     global current_step_idx
  208.     if steps:
  209.         current_step_idx = 0
  210.         sync_ui_to_step()
  211.  
  212. def go_to_last():
  213.     global current_step_idx
  214.     if steps:
  215.         current_step_idx = len(steps) - 1
  216.         sync_ui_to_step()
  217.  
  218. def toggle_play():
  219.     global auto_stepping
  220.     if auto_stepping:
  221.         auto_stepping = False
  222.         btn_play.config(text="Auto Play")
  223.     else:
  224.         auto_stepping = True
  225.         btn_play.config(text="Pause ⏸")
  226.         play_loop()
  227.  
  228. def play_loop():
  229.     if not auto_stepping:
  230.         return
  231.     step_forward()
  232.     if current_step_idx < len(steps) - 1:
  233.         interval = int(1100 - (speed_slider.get() * 100))
  234.         root.after(interval, play_loop)
  235.  
  236. def start_drag(event):
  237.     global drag_start_x, drag_start_y
  238.     drag_start_x = event.x
  239.     drag_start_y = event.y
  240.  
  241. def do_drag(event):
  242.     global drag_start_x, drag_start_y
  243.     dx = event.x - drag_start_x
  244.     dy = event.y - drag_start_y
  245.     canvas.xview_scroll(-dx, "units")
  246.     canvas.yview_scroll(-dy, "units")
  247.     drag_start_x = event.x
  248.     drag_start_y = event.y
  249.  
  250. root = tk.Tk()
  251. root.title("# tk_step_debug.py")
  252. root.geometry("1400x750+-10+0")
  253. root.configure(bg=BG_DARK)
  254.  
  255. toolbar = tk.Frame(root, bg=BG_PANEL, bd=0)
  256. toolbar.pack(fill="x", side="top", ipady=6)
  257.  
  258. btn_run = tk.Button(toolbar, text="Visualize Execution", bg="#008800", fg="#ffffff", activebackground="#a6e3a1", font=("Arial", 10, "bold"), relief=tk.FLAT, command=compile_and_start)
  259. btn_run.pack(side="left", padx=12, pady=5)
  260.  
  261. btn_first = tk.Button(toolbar, text="<< First", bg=BG_INPUTS, fg=FG_LIGHT, disabledforeground="#585b70", activebackground=CHANGED_BG_LINE, activeforeground=FG_LIGHT, relief=tk.FLAT, state="disabled", command=go_to_first)
  262. btn_back10 = tk.Button(toolbar, text="-10 Steps", bg=BG_INPUTS, fg=FG_LIGHT, disabledforeground="#585b70", activebackground=CHANGED_BG_LINE, activeforeground=FG_LIGHT, relief=tk.FLAT, state="disabled", command=step_back_10)
  263. btn_back = tk.Button(toolbar, text="< -1 Step", bg=BG_INPUTS, fg=FG_LIGHT, disabledforeground="#585b70", activebackground=CHANGED_BG_LINE, activeforeground=FG_LIGHT, relief=tk.FLAT, state="disabled", command=step_back)
  264. btn_step = tk.Button(toolbar, text="+1 Step >", bg=BG_INPUTS, fg=FG_LIGHT, disabledforeground="#585b70", activebackground=CHANGED_BG_LINE, activeforeground=FG_LIGHT, relief=tk.FLAT, state="disabled", command=step_forward)
  265. btn_step10 = tk.Button(toolbar, text="+10 Steps", bg=BG_INPUTS, fg=FG_LIGHT, disabledforeground="#585b70", activebackground=CHANGED_BG_LINE, activeforeground=FG_LIGHT, relief=tk.FLAT, state="disabled", command=step_forward_10)
  266. btn_last = tk.Button(toolbar, text="Last >>", bg=BG_INPUTS, fg=FG_LIGHT, disabledforeground="#585b70", activebackground=CHANGED_BG_LINE, activeforeground=FG_LIGHT, relief=tk.FLAT, state="disabled", command=go_to_last)
  267.  
  268. for btn in (btn_first, btn_back10, btn_back, btn_step, btn_step10, btn_last):
  269.     btn.pack(side="left", padx=3)
  270.    
  271. step_label = tk.Label(toolbar, text="Step 0 of 0", bg=BG_PANEL, fg=FG_MUTED, font=("Consolas", 10))
  272. step_label.pack(side="left", padx=15)
  273.  
  274. tk.Label(toolbar, text="Auto Speed:", bg=BG_PANEL, fg=FG_MUTED).pack(side="left", padx=(15, 0))
  275. speed_slider = tk.Scale(toolbar, from_=1, to=10, orient=tk.HORIZONTAL, length=150, showvalue=False, bg=BG_PANEL, fg=FG_LIGHT, highlightthickness=0, troughcolor=BG_INPUTS, activebackground=ACCENT_BLUE)
  276. speed_slider.set(5)
  277. speed_slider.pack(side="left", padx=5)
  278.  
  279. btn_play = tk.Button(toolbar, text="Auto Play", bg=BG_INPUTS, fg=FG_LIGHT, disabledforeground="#585b70", relief=tk.FLAT, state="disabled", command=toggle_play)
  280. btn_play.pack(side="left", padx=5)
  281.  
  282. main_pane = tk.PanedWindow(root, orient=tk.HORIZONTAL, bg=BG_DARK, bd=0, sashwidth=4)
  283. main_pane.pack(fill="both", expand=True)
  284.  
  285. left_frame = tk.Frame(main_pane, bg=BG_PANEL)
  286. main_pane.add(left_frame, minsize=450)
  287.  
  288. tk.Label(left_frame, text=" Python Source Code Editor", anchor="w", font=("Arial", 10, "bold"), bg=BG_DARK, fg=FG_MUTED).pack(fill="x", ipady=4)
  289. code_editor = scrolledtext.ScrolledText(left_frame, wrap=tk.NONE, font=("Consolas", 11), bg=BG_INPUTS, fg=FG_LIGHT, insertbackground="white", bd=0, highlightthickness=0)
  290. code_editor.pack(fill="both", expand=True)
  291.  
  292. sample_code = (
  293.     "def factorial(n):\n"
  294.     "    if n <= 1:\n"
  295.     "        return 1\n"
  296.     "    return n * factorial(n - 1)\n\n"
  297.     "data = [3, 4]\n"
  298.     "results = []\n"
  299.     "for val in data:\n"
  300.     "    res = factorial(val)\n"
  301.     "    results.append(res)\n\n"
  302.     "print(f\"Final Results: {results}\")\n"
  303. )
  304. code_editor.insert("1.0", sample_code)
  305.  
  306. tk.Label(left_frame, text=" Print Output (Console)", anchor="w", font=("Arial", 10, "bold"), bg=BG_DARK, fg=FG_MUTED).pack(fill="x", pady=(5,0), ipady=4)
  307. console_output = scrolledtext.ScrolledText(left_frame, height=8, font=("Consolas", 10), bg="#11111b", fg=ACCENT_GREEN, bd=0, highlightthickness=0)
  308. console_output.pack(fill="x")
  309.  
  310. right_frame = tk.Frame(main_pane, bg=BG_PANEL)
  311. main_pane.add(right_frame, minsize=850)
  312.  
  313. tk.Label(right_frame, text=" Dynamic Heap Stack Monitor Panel", anchor="w", font=("Arial", 10, "bold"), bg=BG_DARK, fg=FG_MUTED).pack(fill="x", ipady=4)
  314.  
  315. canvas = tk.Canvas(right_frame, bg=BG_INPUTS, highlightthickness=0, xscrollincrement=1, yscrollincrement=1)
  316. canvas.pack(fill="both", expand=True, side="left")
  317.  
  318. canvas_vbar = tk.Scrollbar(right_frame, orient="vertical", command=canvas.yview, bg=BG_PANEL)
  319. canvas_vbar.pack(fill="y", side="right")
  320. canvas_hbar = tk.Scrollbar(right_frame, orient="horizontal", command=canvas.xview, bg=BG_PANEL)
  321. canvas_hbar.pack(fill="x", side="bottom")
  322.  
  323. canvas.config(yscrollcommand=canvas_vbar.set, xscrollcommand=canvas_hbar.set)
  324.  
  325. canvas.bind("<ButtonPress-1>", start_drag)
  326. canvas.bind("<B1-Motion>", do_drag)
  327.  
  328. root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment