Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions sp_api/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import TYPE_CHECKING

from .base_client import BaseClient
from .client import Client
from .helpers import (
fill_query_params,
sp_endpoint,
Expand Down Expand Up @@ -36,11 +37,14 @@
from .processing_status import ProcessingStatus
from .reportTypes import ReportType
from .feedTypes import FeedType
from sp_api.auth import AccessTokenClient, Credentials
from sp_api.auth.exceptions import AuthorizationError
from sp_api.base.inegibility_reasons import IneligibilityReasonList
from .marketplaces import AwsEnv

if TYPE_CHECKING:
from .client import Client
from sp_api.auth import AccessTokenClient, Credentials
from sp_api.auth.exceptions import AuthorizationError


__all__ = [
"Credentials",
Expand Down Expand Up @@ -92,3 +96,23 @@
# Backward-compatibility aliases for docs and legacy imports.
FeedTypes = FeedType
FulfillmentChannels = FulfillmentChannel


def __getattr__(name):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider refactoring the lazy imports into a single mapping of names to loader callables so that __getattr__ just looks up and caches values instead of handling multiple conditional branches.

You can keep the lazy-import behavior while reducing branching and duplication by centralizing the mapping of exported names to loader functions. This also helps keep TYPE_CHECKING, __all__, and __getattr__ in sync.

For example:

from typing import TYPE_CHECKING, Callable, Dict, Any

if TYPE_CHECKING:
    from .client import Client
    from sp_api.auth import AccessTokenClient, Credentials
    from sp_api.auth.exceptions import AuthorizationError

_LAZY_LOADERS: Dict[str, Callable[[], Any]] = {
    "Client": lambda: __import__(__name__ + ".client", fromlist=["Client"]).Client,
    "AccessTokenClient": lambda: __import__("sp_api.auth", fromlist=["AccessTokenClient"]).AccessTokenClient,
    "Credentials": lambda: __import__("sp_api.auth", fromlist=["Credentials"]).Credentials,
    "AuthorizationError": lambda: __import__("sp_api.auth.exceptions", fromlist=["AuthorizationError"]).AuthorizationError,
}

def __getattr__(name: str) -> Any:
    try:
        loader = _LAZY_LOADERS[name]
    except KeyError:
        raise AttributeError(f"module '{__name__}' has no attribute '{name}'") from None
    value = loader()
    globals()[name] = value  # cache
    return value

This simplifies:

  • One place to list supported lazy symbols (_LAZY_LOADERS) instead of multiple if branches.
  • __getattr__ no longer mixes unrelated responsibilities; it just looks up a loader and caches.
  • Adding/removing a symbol only requires touching _LAZY_LOADERS, and optionally __all__ / TYPE_CHECKING, reducing risk of drift.

if name == "Client":
from .client import Client

globals()[name] = Client
return Client
if name in {"AccessTokenClient", "Credentials"}:
from sp_api.auth import AccessTokenClient, Credentials

exports = {"AccessTokenClient": AccessTokenClient, "Credentials": Credentials}
globals()[name] = exports[name]
return exports[name]
if name == "AuthorizationError":
from sp_api.auth.exceptions import AuthorizationError

globals()[name] = AuthorizationError
return AuthorizationError
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
Loading