perf: keep the SDK and requests out of startup - #375
Draft
cloudsmith-iduffy wants to merge 2 commits into
Draft
Conversation
6 tasks
Move create_requests_session to core/session.py, which reads the SDK Configuration defaults only when the SDK is already imported. Defer the SDK, session and saml imports in the decorators, the keyring provider and the OIDC detectors to the code paths that use them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cloudsmith-iduffy
force-pushed
the
perf/defer-cloudsmith-api-sdk
branch
from
August 21, 2026 23:40
f81dca7 to
8799332
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Keep the
cloudsmith_apiSDK andrequestsout of CLI startup.After #374, the shared
cli/decorators.pychain was the last eager cost (145 ms of the remaining 153 ms). It pulled in the full SDK (cloudsmith_api/__init__imports every API class and ~200 model modules, ~70 ms) plusrequests(~30 ms) on every invocation — including--versionand credential-helper calls that never touch either.Changes:
core/session.py(new):create_requests_sessionmoved out ofcore/rest.py.core/rest.pymust import the SDK at module level (RestClientsubclasses the generatedRESTClientObject), so every importer ofcreate_requests_sessionpaid for the SDK. The session module reads the SDKConfigurationdefaults only whencloudsmith_apiis already insys.modules—initialise_api()is the only writer of those defaults (viaset_default()), and it cannot have run if the SDK is not imported, so the literal fallbacks are exact.cli/decorators.py: importcore.api.initinside theinitialise_apiwrapper andcore.sessioninside theinitialise_sessionwrapper.keyring_provider: importcli.saml(→requests+ SDK exceptions) only on the token-refresh path.github_actions,azure_devops): import the session module only on a detector match, per the existing lazy-optional-import convention in the detectors.core/credentials/models.py:requestsis annotation-only →TYPE_CHECKING.Results
Measured on macOS (M-series), Python 3.14.7,
PYTHONDONTWRITEBYTECODE=1(repo.envrcdefault). Baseline column = #374.cloudsmith --versioncredential-helper docker get-X importtime)Note: the credential helper builds a requests session and reads the keyring at run time, so its
requestsimport cost moves rather than disappears. It no longer loads the SDK at all (~70 ms saved is offset by run-timerequests/keyringimports that were previously counted at startup). Its remaining wall time is dominated by the macOS keyring backend roundtrip (~0.19 s), a separate follow-up.Cumulative vs master:
--version2.72 s → 0.18 s (-93%),docker get2.94 s → 0.37 s (-87%).Methodology (how to reproduce)
Attribute the remaining import time after perf: import command modules lazily #374:
Walk the parent chain of each heavy module in the importtime tree (indentation = depth, children print before parents). The chains this PR breaks:
Note
from cloudsmith_api.rest import ApiExceptionruns the wholecloudsmith_api/__init__(parent packages import first) — importing "just the submodule" does not avoid the cost.Guard against regression:
HEAVY_PREFIXESincli/tests/test_startup_imports.pynow includescloudsmith_apiandrequests(written first; failed with the full SDK loaded).Verify behaviour: full suite (800 passed, 40 skipped) plus a live
cloudsmith whoami(exercisesinitialise_api→RestClient→ session defaults with the SDK loaded) and a livecredential-helper docker get.Type of Change
Additional Notes
create_requests_sessionkeeps identical semantics when the SDK is loaded; when it is not, the fallback values it already contained apply.Flame graphs
Probe:
cloudsmith --version. Icicle charts frompython -X importtime: parents above children, width = cumulative import time. Totals include the interpreter's ownsiteimports and vary a few ms between runs.Before:
After: