chore: ban module-level imports of startup-heavy modules - #380
Merged
cloudsmith-iduffy merged 2 commits intoAug 25, 2026
Merged
Conversation
6 tasks
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 21, 2026 23:40
82a5203 to
f7601a4
Compare
cloudsmith-iduffy
marked this pull request as ready for review
August 24, 2026 06:51
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a Ruff lint guard (TID253) to prevent module-level imports of known startup-heavy dependencies across eagerly-imported CLI code paths, and fixes two existing eager imports that the new rule surfaced.
Changes:
- Enable Ruff
TID253and configure a banned module list for startup-heavy libraries, plus per-file allowlisting for known lazily-imported leaves. - Defer
keyring.backendimport in the PyInstaller entrypoint so it’s only imported during the packaging selftest path. - Defer
keyringimports incloudsmith_cli/core/keyring.pyby moving them inside the functions that actually use keyring.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
pyproject.toml |
Enables Ruff TID253, configures banned startup-heavy modules, and allowlists known lazy-import leaves via per-file ignores. |
packaging/pyinstaller/entry.py |
Moves keyring.backend import into the selftest-only helper to avoid eager import cost. |
cloudsmith_cli/core/keyring.py |
Refactors keyring imports into function scope to keep the eager import path lightweight. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 24, 2026 10:21
f7601a4 to
dd8af12
Compare
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 24, 2026 13:15
dd8af12 to
999b07d
Compare
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 24, 2026 15:45
999b07d to
48bb7d8
Compare
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 24, 2026 17:58
48bb7d8 to
aa0ab4d
Compare
apoclyps
approved these changes
Aug 25, 2026
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
2 times, most recently
from
August 25, 2026 11:30
7bca7c4 to
960fc11
Compare
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 25, 2026 11:40
960fc11 to
6930443
Compare
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 25, 2026 11:50
6930443 to
45eb2c6
Compare
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 25, 2026 12:08
45eb2c6 to
3cc98ea
Compare
Select TID253 with a ban list of the modules that dominated CLI startup. Files that load lazily are allowlisted per file. Defer the keyring import in the frozen entrypoint to the selftest that uses it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
core/keyring.py sits on the eager import path through the credential chain. Import the keyring library inside the functions that use it and remove the file from the TID253 allowlist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cloudsmith-iduffy
force-pushed
the
lint/ban-heavy-module-level-imports
branch
from
August 25, 2026 13:23
3cc98ea to
a24d3db
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
The perf work in this stack got
mcp,httpx,cloudsmith_api,requests,rich,semver,urllib3andkeyringout of CLI startup. The startup tests guard the two main entry points, but someone could still addimport requeststo the top of any other eagerly-imported file and quietly hand everydocker pullits ~30ms back.This closes that gap with ruff's banned-module-level-import rule (
TID253): the eight modules above can now only be imported inside functions. Files that are themselves loaded lazily — the command modules, thecore/api/*call sites, the MCP server, and the session/rest/saml/download leaves — are allowlisted per file, so their existing top-level imports stay put. Anything new fails lint, in pre-commit and CI, via the existing ruff hook.Turning the rule on immediately found two real problems:
packaging/pyinstaller/entry.py) importedkeyring.backendat module level, but only the packaging selftest uses it — every invocation of the frozen binary paid for an import it didn't need. It now lives inside the selftest helper. (Frozen imports are pre-compiled, so this one is below measurement noise — the binary clocks 0.26s before and after. Fixed because the rule is right, not because it's measurable.)core/keyring.pyimported thekeyringlibrary at module level, and that file is on the eager path (it's pulled in through the credential chain). My first instinct was to allowlist it; on review that was just papering over a real cost. The library is only used inside five functions, so the imports moved there — andcloudsmith --versiondropped from 0.12s to 0.09s.No flame graphs on this one — the only import-graph change is the small keyring subtree, and the numbers above tell the story. The real value is that the next accidental heavy import gets caught by the linter instead of a profiler.
Type of Change
Lint guard for startup performance, plus the two import deferrals it flagged.
Additional Notes
cli/commands/*as a directory, which also exempts the eagerly-importedmain.pyandregistry.py. The subprocess tests incli/tests/test_startup_imports.pycover exactly that hole.SELFTEST: OK, 129 modules).🤖 Generated with Claude Code