**Approach (brief)** Create a parameterized decorator that catches common Selenium WebDriver exceptions, retries with exponential backoff, saves a timestamped thread-safe screenshot on each failure, and preserves metadata using functools.wraps.python
import os, time, threading, uuid
from datetime import datetime
from functools import wraps
from selenium.common.exceptions import WebDriverException, NoSuchElementException, StaleElementReferenceException, TimeoutException
def retry_for_selenium(max_retries: int = 3, backoff_seconds: float = 1.0, screenshot_dir: str = None):
if screenshot_dir is None:
screenshot_dir = os.getenv("SELENIUM_SCREENSHOT_DIR", "/tmp/selenium_screenshots")
os.makedirs(screenshot_dir, exist_ok=True)
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
last_exc = None
for attempt in range(1, max_retries + 1):
try:
return fn(*args, **kwargs)
except (WebDriverException, NoSuchElementException, StaleElementReferenceException, TimeoutException) as exc:
last_exc = exc
# try to get driver to save screenshot: look in args/kwargs for 'driver' or first arg
driver = kwargs.get("driver", args[0] if args else None)
ts = datetime.utcnow().strftime("%Y%m%dT%H%M%S.%fZ")
fname = f"screenshot_{ts}_tid{threading.get_ident()}_{uuid.uuid4().hex}.png"
path = os.path.join(screenshot_dir, fname)
try:
if hasattr(driver, "get_screenshot_as_file"):
driver.get_screenshot_as_file(path)
else:
# fallback: if driver not available, write exception details
with open(path + ".txt", "w") as f:
f.write(repr(exc))
except Exception:
# do not mask original exception; just continue
pass
if attempt == max_retries:
raise
sleep = backoff_seconds * (2 ** (attempt - 1))
time.sleep(sleep)
raise last_exc
return wrapper
return decorator
Why this works- Catches common flaky Selenium errors and retries them.- Exponential backoff reduces hammering transient issues.- Screenshot filenames include UTC timestamp, thread id and uuid for thread-safety and uniqueness.- Preserves metadata with functools.wraps so test frameworks report correct names.- Screenshot directory configurable via param or SELENIUM_SCREENSHOT_DIR env var.Usage example:- Decorate test functions that take a Selenium WebDriver (commonly as first arg or named 'driver').