1. import ast
  2. import inspect
  3. import importlib
  4. import os
  5. import sys
  6. import traceback
  7. import tempfile
  8. import shutil
  9. def instrument_file(filepath, instrumentation_function):
  10. """
  11. Instruments a Python file with a given function.
  12. Args:
  13. filepath (str): The path to the Python file.
  14. instrumentation_function (callable): The function to instrument with.
  15. It should take the module object as an argument.
  16. Returns:
  17. bool: True if instrumentation was successful, False otherwise.
  18. """
  19. try:
  20. with open(filepath, 'r') as f:
  21. source_code = f.read()
  22. tree = ast.parse(source_code)
  23. for node in ast.walk(tree):
  24. if isinstance(node, ast.Module):
  25. instrumentation_function(module=ast.Module(body=[node.body]))
  26. return True
  27. return False # No module found
  28. except (SyntaxError, FileNotFoundError, Exception) as e:
  29. print(f"Error instrumenting {filepath}: {e}")
  30. return False
  31. def wrap_function(function):
  32. """Wraps a function to log its execution and handle exceptions gracefully."""
  33. def wrapper(*args, **kwargs):
  34. try:
  35. return function(*args, **kwargs)
  36. except Exception as e:
  37. print(f"Function {function.__name__} raised an exception: {e}")
  38. traceback.print_exc()
  39. return None # Or some default value, depending on the use case
  40. return wrapper
  41. def instrument_code(filepath, instrumentation_function):
  42. """
  43. Instruments the code in a file, handling potential errors gracefully.
  44. Args:
  45. filepath (str): The path to the Python file.
  46. instrumentation_function (callable): A function that takes a module
  47. object as an argument, which is
  48. used to modify the code.
  49. Returns:
  50. bool: True if instrumentation was successful, False otherwise.
  51. """
  52. try:
  53. # Create a temporary file to write the instrumented code
  54. with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as temp_file:
  55. with open(filepath, 'r') as source_file:
  56. shutil.copyfileobj(source_file, temp_file)
  57. temp_filepath = temp_file.name
  58. if instrument_file(temp_filepath, instrumentation_function):
  59. # Replace the original file with the instrumented one
  60. shutil.move(temp_filepath, filepath)
  61. return True
  62. else:
  63. # If instrumentation failed, clean up the temporary file
  64. os.remove(temp_filepath)
  65. return False
  66. except Exception as e:
  67. print(f"Error during instrumentation: {e}")
  68. return False
  69. def register_instrumentation(module):
  70. """Registers the instrumentation function with the module."""
  71. module.instrumentation_function = wrap_function # Assign the wrapper function
  72. if __name__ == '__main__':
  73. # Example Usage:
  74. # Define your instrumentation function
  75. def my_instrumentation(module):
  76. """
  77. Example instrumentation function.
  78. This function is called to instrument the module.
  79. """
  80. for name, obj in inspect.getmembers(module):
  81. if inspect.isfunction(obj):
  82. setattr(obj, 'instrumented', my_instrumentation) # Add an attribute to the function
  83. # Specify the file to instrument
  84. file_to_instrument = 'example.py'
  85. # Create a dummy example.py file for testing
  86. with open(file_to_instrument, 'w') as f:
  87. f.write("""
  88. def my_function(x):
  89. return x + 1
  90. def another_function(y):
  91. result = y / 0 # This will cause a ZeroDivisionError
  92. return result
  93. """)
  94. # Instrument the file
  95. if instrument_code(file_to_instrument, my_instrumentation):
  96. print(f"Successfully instrumented {file_to_instrument}")
  97. # Example of running the instrumented code
  98. import example
  99. print(example.my_function(5))
  100. try:
  101. print(example.another_function(10))
  102. except Exception as e:
  103. print(f"Caught exception: {e}")
  104. else:
  105. print(f"Failed to instrument {file_

Add your comment