MethodMonitor is a utility class to monitor method calls on Python classes. It supports instance methods, class methods, and static methods, and allows attaching multiple monitors to a single method.
from classmods import MethodMonitor-
Purpose: Trigger custom callables whenever a method is invoked.
-
Features:
- Monitor
__init__or any other method. - Supports multiple monitors per method.
- Works with
@staticmethod,@classmethod, and regular instance methods. - Can pass extra
argsandkwargsto the monitor callable. - Activate, deactivate, or remove monitors at runtime.
- Monitor
class MethodMonitor:
def __init__(
self,
target: Type,
monitor_callable: Callable[..., None],
monitor_args: Optional[Tuple] = None,
monitor_kwargs: Optional[Dict[str, Any]] = None,
*,
target_method: str | Callable = "__init__",
active: bool = True
)| Parameter | Type | Description | |
|---|---|---|---|
target |
Type |
The class to monitor. | |
monitor_callable |
Callable[..., None] |
Function to call after the method is executed. Signature: (instance_or_cls_or_none, *monitor_args, **monitor_kwargs) |
|
monitor_args |
Optional[Tuple] |
Extra positional arguments passed to the monitor callable. | |
monitor_kwargs |
Optional[Dict[str, Any]] |
Extra keyword arguments passed to the monitor callable. | |
target_method |
`str | Callable` | Name of the method to monitor, or the method itself. Defaults to '__init__'. |
active |
bool |
If True, the monitor is active immediately. |
class MyClass:
def greet(self, name):
print(f"Hello {name}")
def monitor_fn(instance, *args, **kwargs):
print(f"Monitor: Called {instance} with args={args}, kwargs={kwargs}")
monitor = MethodMonitor(
MyClass,
monitor_fn,
monitor_args=("ExtraArg",),
target_method=MyClass.greet,
)
obj = MyClass()
obj.greet("Alice")
# Output:
# Hello Alice
# Monitor: Called <MyClass instance> with args=('ExtraArg',), kwargs={}class MyClass:
@classmethod
def announce(cls, message):
print(f"{cls.__name__}: {message}")
def monitor_cls(cls, *args, **kwargs):
print(f"Monitor: class={cls}, args={args}, kwargs={kwargs}")
monitor = MethodMonitor(
MyClass,
monitor_cls,
monitor_args=("ExtraArg",),
target_method=MyClass.announce,
)
MyClass.announce("Hello")
# Output:
# MyClass: Hello
# Monitor: class=<class 'MyClass'>, args=('ExtraArg',), kwargs={}class MyClass:
@staticmethod
def static_print(msg):
print(msg)
def monitor_static(_none, *args, **kwargs):
print(f"Monitor: args={args}, kwargs={kwargs}")
monitor = MethodMonitor(MyClass, monitor_static, monitor_args=("ExtraArg",), target_method="static_print")
MyClass.static_print("Hello")
# Output:
# Hello
# Monitor: args=('ExtraArg',), kwargs={}Note: For static methods, the first argument passed to the monitor is always
None.
monitor.deactivate() # Monitor will not trigger
monitor.activate() # Monitor triggers again
monitor.remove() # Monitor is removed and original method restoreddef monitor_a(instance, *args, **kwargs):
print("Monitor A triggered")
def monitor_b(instance, *args, **kwargs):
print("Monitor B triggered")
MethodMonitor(MyClass, monitor_a, target_method=MyClass.greet)
MethodMonitor(MyClass, monitor_b, target_methodMyClass.greet)
obj = MyClass()
obj.greet("Bob")
# Output:
# Hello Bob
# Monitor A triggered
# Monitor B triggered- Use
target_methodas a string or the actual method reference. - Static methods always receive
Noneas the first argument in the monitor. - Class methods receive
clsas the first argument. - Avoid monitoring methods that return large or sensitive data for performance and security reasons.
MethodMonitormodifies the class method dynamically (monkey-patching).- Removing all monitors restores the original method.
- Supports any callable signature in
monitor_callable, as long as it accepts the first argument (instance/cls/None).