Skip to content

Instantly share code, notes, and snippets.

@innateessence
Last active July 3, 2024 01:26
Show Gist options
  • Save innateessence/40df68d4ce12531bea8b2817321611de to your computer and use it in GitHub Desktop.
Save innateessence/40df68d4ce12531bea8b2817321611de to your computer and use it in GitHub Desktop.
Quick and Dirty custom python tracer ; trace all function calls for only the functions you wrote ; written in less than 10 minutes
#!/usr/bin/env python3
import os
import re
import sys
'''
Example of how to dynamically trace all function calls for your python project, and not any other python code.
use case:
- You wrote a lot of code, there's a bug, you don't know where it is, and you know the bug doesn't exist in how you're using some 3rd party code
'''
FilePath = str
FuncName = str
func_names = []
def _resolve_python_files(path: str = ".") -> list[FilePath]:
"""Recursively resolve all python files in a directory"""
python_files = []
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(".py"):
python_files.append(os.path.join(root, file))
for dir in dirs:
python_files.extend(_resolve_python_files(dir))
return python_files
def _resolve_func_names(file_path: str = ".") -> list[FuncName]:
with open(file_path, "r") as file:
text = file.read()
func_names = re.findall(r"def\s+(\w+)\s*\(", text)
return func_names
def trace(frame, event, arg=None):
global func_names
code = frame.f_code
func_name = code.co_name
line_no = frame.f_lineno
if func_name in func_names:
print(f"A {event} encountered in {func_name}() at line number {line_no}")
return trace
if __name__ == "__main__":
for _file in _resolve_python_files():
func_names.extend(_resolve_func_names(_file))
sys.settrace(trace)
@innateessence
Copy link
Author

This needs to be included in your projects python entrypoint.
Can wrap this functionality into a single function that you can call from a module for portability purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment