Files
aitbc/aitbc/decorators.py
aitbc b064f922bd
Some checks failed
Blockchain Synchronization Verification / sync-verification (push) Successful in 2s
Integration Tests / test-service-integration (push) Failing after 10s
Multi-Node Blockchain Health Monitoring / health-check (push) Successful in 2s
P2P Network Verification / p2p-verification (push) Successful in 2s
Python Tests / test-python (push) Successful in 11s
Security Scanning / security-scan (push) Has been cancelled
Add normalization to gossip transaction processing to preserve type field
2026-04-22 13:48:20 +02:00

186 lines
5.2 KiB
Python

"""
AITBC Common Decorators
Reusable decorators for common patterns in AITBC applications
"""
import time
import functools
from typing import Callable, Type, Any
from .exceptions import AITBCError
def retry(
max_attempts: int = 3,
delay: float = 1.0,
backoff: float = 2.0,
exceptions: tuple[Type[Exception], ...] = (Exception,),
on_failure: Callable[[Exception], Any] = None
):
"""
Retry a function with exponential backoff.
Args:
max_attempts: Maximum number of retry attempts
delay: Initial delay between retries in seconds
backoff: Multiplier for delay after each retry
exceptions: Tuple of exception types to catch
on_failure: Optional callback function called on final failure
Returns:
Decorated function that retries on failure
"""
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs):
last_exception = None
current_delay = delay
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except exceptions as e:
last_exception = e
if attempt < max_attempts - 1:
time.sleep(current_delay)
current_delay *= backoff
else:
if on_failure:
on_failure(e)
raise
raise last_exception if last_exception else AITBCError("Retry failed")
return wrapper
return decorator
def timing(func: Callable) -> Callable:
"""
Decorator to measure and log function execution time.
Args:
func: Function to time
Returns:
Decorated function that prints execution time
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
execution_time = end_time - start_time
print(f"{func.__name__} executed in {execution_time:.4f} seconds")
return result
return wrapper
def cache_result(ttl: int = 300):
"""
Simple in-memory cache decorator with TTL.
Args:
ttl: Time to live for cached results in seconds
Returns:
Decorated function with caching
"""
cache = {}
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Create cache key from function name and arguments
cache_key = (func.__name__, args, frozenset(kwargs.items()))
current_time = time.time()
# Check if cached result exists and is not expired
if cache_key in cache:
result, timestamp = cache[cache_key]
if current_time - timestamp < ttl:
return result
# Call function and cache result
result = func(*args, **kwargs)
cache[cache_key] = (result, current_time)
return result
return wrapper
return decorator
def validate_args(*validators: Callable):
"""
Decorator to validate function arguments.
Args:
*validators: Validation functions that raise ValueError on invalid input
Returns:
Decorated function with argument validation
"""
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs):
for validator in validators:
validator(*args, **kwargs)
return func(*args, **kwargs)
return wrapper
return decorator
def handle_exceptions(
default_return: Any = None,
log_errors: bool = True,
raise_on: tuple[Type[Exception], ...] = ()
):
"""
Decorator to handle exceptions gracefully.
Args:
default_return: Value to return on exception
log_errors: Whether to log errors
raise_on: Tuple of exception types to still raise
Returns:
Decorated function with exception handling
"""
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except raise_on as e:
raise
except Exception as e:
if log_errors:
print(f"Error in {func.__name__}: {e}")
return default_return
return wrapper
return decorator
def async_timing(func: Callable) -> Callable:
"""
Decorator to measure async function execution time.
Args:
func: Async function to time
Returns:
Decorated async function that prints execution time
"""
@functools.wraps(func)
async def wrapper(*args, **kwargs):
start_time = time.time()
result = await func(*args, **kwargs)
end_time = time.time()
execution_time = end_time - start_time
print(f"{func.__name__} executed in {execution_time:.4f} seconds")
return result
return wrapper