Created
March 26, 2026 20:11
-
-
Save robbienohra/bb1c1ff646999e7ad6f43704e5468da8 to your computer and use it in GitHub Desktop.
decorator.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import functools | |
| import time | |
| # --- 1. The Decorator --- | |
| def retry_api_call(): | |
| """Decorator that introspects 'self' for config, allowing kwargs overrides.""" | |
| def decorator(func): | |
| @functools.wraps(func) | |
| def wrapper(self, *args, **kwargs): | |
| # Extract per-call overrides if the user provided them | |
| call_retries = kwargs.pop("retries", None) | |
| call_delay = kwargs.pop("delay", None) | |
| # Fallback to instance defaults (from 'self') if no overrides exist | |
| retries = call_retries if call_retries is not None else self.retries | |
| delay = call_delay if call_delay is not None else self.delay | |
| print( | |
| f" [Decorator] Resolved config -> Retries: {retries}, Delay: {delay}s" | |
| ) | |
| for attempt in range(1, retries + 1): | |
| try: | |
| print(f" [Decorator] Attempt {attempt} of {retries}...") | |
| # Call the actual API method | |
| return func(self, *args, **kwargs) | |
| except Exception as e: | |
| if attempt == retries: | |
| print( | |
| f" [Decorator] All {retries} attempts failed. Raising exception." | |
| ) | |
| raise e | |
| print( | |
| f" [Decorator] Failed. Waiting {delay}s before next attempt...\n" | |
| ) | |
| time.sleep(delay) | |
| return wrapper | |
| return decorator | |
| # --- 2. The API Client --- | |
| class MyAPIClient: | |
| def __init__(self, retries=3, delay=1.0): | |
| # Client-wide defaults | |
| self.retries = retries | |
| self.delay = delay | |
| @retry_api_call() | |
| def fetch_data(self, endpoint): | |
| """A simulated API call that always fails to demonstrate retries.""" | |
| print(f" [Client] Hitting endpoint: {endpoint}") | |
| raise ConnectionError("503 Service Unavailable") | |
| # --- 3. Local Testing / Execution --- | |
| if __name__ == "__main__": | |
| # Initialize the client with a default 3 retries and a fast 0.2s delay for testing | |
| client = MyAPIClient(retries=4, delay=0.2) | |
| print("=== TEST 1: Using Client-Wide Defaults ===") | |
| try: | |
| # We don't pass any kwargs, so it falls back to the client's init settings | |
| client.fetch_data("/users") | |
| except ConnectionError: | |
| print("Caught expected ConnectionError from Test 1.\n") | |
| print("=== TEST 2: Overriding Config for a Specific Call ===") | |
| try: | |
| # We pass kwargs directly to the method to override the client defaults | |
| client.fetch_data("/payments", retries=2, delay=0.5) | |
| except ConnectionError: | |
| print("Caught expected ConnectionError from Test 2.\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment