Files
aitbc/aitbc/decorators.py
aitbc 3897bcbf24
Some checks failed
CLI Tests / test-cli (push) Failing after 4s
Deploy to Testnet / deploy-testnet (push) Successful in 1m40s
Documentation Validation / validate-docs (push) Failing after 12s
Documentation Validation / validate-policies-strict (push) Successful in 4s
Integration Tests / test-service-integration (push) Successful in 2m42s
Package Tests / Python package - aitbc-agent-sdk (push) Failing after 34s
Package Tests / Python package - aitbc-core (push) Successful in 27s
Package Tests / Python package - aitbc-crypto (push) Successful in 13s
Package Tests / Python package - aitbc-sdk (push) Successful in 16s
Package Tests / JavaScript package - aitbc-sdk-js (push) Successful in 8s
Package Tests / JavaScript package - aitbc-token (push) Successful in 18s
Python Tests / test-python (push) Failing after 50s
Security Scanning / security-scan (push) Failing after 43s
Multi-Node Stress Testing / stress-test (push) Successful in 12s
Cross-Node Transaction Testing / transaction-test (push) Successful in 9s
refactor: move version to separate module and improve logging
- Created aitbc/_version.py with centralized version definition
- Updated aitbc/__init__.py to import __version__ from _version module
- Updated constants.py to use __version__ for PACKAGE_VERSION
- Replaced print() calls with logger in decorators.py, events.py, queue_manager.py, and state.py
- Added logger initialization using get_logger(__name__) in config.py, decorators.py, events.py, queue_manager.py, and state.py
- Added cli/commands
2026-05-11 20:12:01 +02:00

189 lines
5.3 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
from .aitbc_logging import get_logger
logger = get_logger(__name__)
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
logger.info(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:
logger.error(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
logger.info(f"{func.__name__} executed in {execution_time:.4f} seconds")
return result
return wrapper