import ast
import inspect
import importlib
import os
import sys
import traceback
import tempfile
import shutil
def instrument_file(filepath, instrumentation_function):
"""
Instruments a Python file with a given function.
Args:
filepath (str): The path to the Python file.
instrumentation_function (callable): The function to instrument with.
It should take the module object as an argument.
Returns:
bool: True if instrumentation was successful, False otherwise.
"""
try:
with open(filepath, 'r') as f:
source_code = f.read()
tree = ast.parse(source_code)
for node in ast.walk(tree):
if isinstance(node, ast.Module):
instrumentation_function(module=ast.Module(body=[node.body]))
return True
return False # No module found
except (SyntaxError, FileNotFoundError, Exception) as e:
print(f"Error instrumenting {filepath}: {e}")
return False
def wrap_function(function):
"""Wraps a function to log its execution and handle exceptions gracefully."""
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except Exception as e:
print(f"Function {function.__name__} raised an exception: {e}")
traceback.print_exc()
return None # Or some default value, depending on the use case
return wrapper
def instrument_code(filepath, instrumentation_function):
"""
Instruments the code in a file, handling potential errors gracefully.
Args:
filepath (str): The path to the Python file.
instrumentation_function (callable): A function that takes a module
object as an argument, which is
used to modify the code.
Returns:
bool: True if instrumentation was successful, False otherwise.
"""
try:
# Create a temporary file to write the instrumented code
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as temp_file:
with open(filepath, 'r') as source_file:
shutil.copyfileobj(source_file, temp_file)
temp_filepath = temp_file.name
if instrument_file(temp_filepath, instrumentation_function):
# Replace the original file with the instrumented one
shutil.move(temp_filepath, filepath)
return True
else:
# If instrumentation failed, clean up the temporary file
os.remove(temp_filepath)
return False
except Exception as e:
print(f"Error during instrumentation: {e}")
return False
def register_instrumentation(module):
"""Registers the instrumentation function with the module."""
module.instrumentation_function = wrap_function # Assign the wrapper function
if __name__ == '__main__':
# Example Usage:
# Define your instrumentation function
def my_instrumentation(module):
"""
Example instrumentation function.
This function is called to instrument the module.
"""
for name, obj in inspect.getmembers(module):
if inspect.isfunction(obj):
setattr(obj, 'instrumented', my_instrumentation) # Add an attribute to the function
# Specify the file to instrument
file_to_instrument = 'example.py'
# Create a dummy example.py file for testing
with open(file_to_instrument, 'w') as f:
f.write("""
def my_function(x):
return x + 1
def another_function(y):
result = y / 0 # This will cause a ZeroDivisionError
return result
""")
# Instrument the file
if instrument_code(file_to_instrument, my_instrumentation):
print(f"Successfully instrumented {file_to_instrument}")
# Example of running the instrumented code
import example
print(example.my_function(5))
try:
print(example.another_function(10))
except Exception as e:
print(f"Caught exception: {e}")
else:
print(f"Failed to instrument {file_
Add your comment