Source code for imednet.cli.decorators

"""Decorators for CLI command functions."""

from __future__ import annotations

import inspect
import os
import sys
from collections.abc import Callable
from functools import wraps
from typing import Concatenate, ParamSpec, TypeVar

from imednet.errors import (
    ApiError,
    AuthenticationError,
    AuthorizationError,
    ForbiddenError,
    NotFoundError,
    RateLimitError,
    UnauthorizedError,
)

from ..sdk import ImednetSDK

P = ParamSpec("P")
R = TypeVar("R")


def _redact_secrets(msg: str) -> str:
    """Redact secrets from error messages."""
    for env_var in ["IMEDNET_API_KEY", "IMEDNET_SECURITY_KEY"]:
        val = os.environ.get(env_var)
        if val and val in msg:
            msg = msg.replace(val, "********")
    return msg


[docs]def with_sdk(func: Callable[Concatenate[ImednetSDK, P], R]) -> Callable[P, R]: """Initialize the SDK and pass it to the wrapped command function.""" sig = inspect.signature(func) wrapper_params = list(sig.parameters.values())[1:] @wraps(func) def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: """Initialize the SDK, execute the command, and handle common API errors.""" from .utils.context import get_sdk sdk = get_sdk() try: return func(sdk, *args, **kwargs) except SystemExit: raise except (AuthenticationError, UnauthorizedError) as exc: msg = _redact_secrets(str(exc)) print(f"Authentication Failed: {msg}") sys.exit(1) except (AuthorizationError, ForbiddenError) as exc: msg = _redact_secrets(str(exc)) print(f"Permission Denied: {msg}") sys.exit(1) except RateLimitError as exc: msg = _redact_secrets(str(exc)) print(f"Rate Limit Exceeded: {msg}") sys.exit(1) except NotFoundError as exc: msg = _redact_secrets(str(exc)) print(f"Not Found: {msg}") sys.exit(1) except ApiError as exc: msg = _redact_secrets(str(exc)) print(f"API Error: {msg}") sys.exit(1) except KeyboardInterrupt: print("\nAborted by user.") sys.exit(130) except Exception as exc: # pragma: no cover - defensive msg = _redact_secrets(str(exc)) print(f"Unexpected error: {msg}") sys.exit(1) finally: close = getattr(sdk, "close", None) if callable(close): close() wrapper.__signature__ = sig.replace(parameters=wrapper_params) # type: ignore[attr-defined] return wrapper