Skip to content

[Fix] Replace subprocess startup-import diff with static source scan - #26934

Merged
Michael-RZ-Berri merged 1 commit into
litellm_internal_stagingfrom
litellm_lazyStartupTestFix
Apr 30, 2026
Merged

[Fix] Replace subprocess startup-import diff with static source scan#26934
Michael-RZ-Berri merged 1 commit into
litellm_internal_stagingfrom
litellm_lazyStartupTestFix

Conversation

@Michael-RZ-Berri

Copy link
Copy Markdown
Contributor

Relevant issues

Fixes lazy loading test that times out by statically checking imports instead.

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Screenshots / Proof of Fix

Test is 13 seconds locally instead of timing out past two minutes.

Type

🐛 Bug Fix
✅ Test

Changes

test_proxy_server

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Michael Riad Zaky seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces a subprocess-based sys.modules diff (which timed out at 60–120 s) with a static regex scan of proxy_server.py source to verify that lazy feature modules aren't imported at startup. The performance improvement is real, but the new approach is meaningfully weaker than the original.

  • The class docstring still says the test ensures lazy modules are "NOT present in sys.modules immediately after proxy_server imports," but the static scan cannot verify that — transitive imports (a heavy module pulled in by another top-level import) will slip through undetected.
  • The regex also misses the from litellm.proxy.guardrails import guardrail_endpoints form, which causes the same startup load as the patterns it does match.

Confidence Score: 3/5

Safe to merge for CI speed, but intentionally weakens the test's runtime guarantee — the class docstring and the actual assertion are now mismatched.

P1 finding: the replacement test no longer verifies the property its class claims to assert (no lazy modules in sys.modules at startup), missing transitive and partial-path import leaks.

tests/test_litellm/proxy/test_proxy_server.py — the test_heavy_modules_absent_at_startup method and its class docstring need to be updated to match the new (weaker) semantics, or the approach should be extended to also cover the gap patterns.

Important Files Changed

Filename Overview
tests/test_litellm/proxy/test_proxy_server.py Replaces subprocess sys.modules diffing with a static regex scan of proxy_server.py; the new approach misses transitive imports and the partial-path import form, so the test no longer verifies what its class docstring claims.

Reviews (1): Last reviewed commit: "test: replace subprocess startup-import ..." | Re-trigger Greptile

Comment on lines 5515 to 5543
def test_heavy_modules_absent_at_startup(self):
# Force a fresh `proxy_server` import in a subprocess so other tests
# in this run (which may have triggered lazy loads via the TestClient)
# don't pollute the result.
import subprocess

check = (
"import sys; "
"from litellm.proxy.proxy_server import app; " # noqa: F401
"heavy = ["
"'litellm.proxy._experimental.mcp_server.rest_endpoints',"
"'litellm.proxy._experimental.mcp_server.server',"
"'litellm.proxy.management_endpoints.config_override_endpoints',"
"'litellm.proxy.guardrails.guardrail_endpoints',"
"'litellm.proxy.openai_evals_endpoints.endpoints',"
"]; "
"still_present = [m for m in heavy if m in sys.modules]; "
"print('PRESENT_AT_STARTUP:', still_present)"
)
result = subprocess.run(
[sys.executable, "-c", check],
capture_output=True,
text=True,
timeout=120,
# Static scan of proxy_server.py source — catches any top-level
# `from <lazy_module> import` that would defeat lazy loading.
# Importing proxy_server in a subprocess and diffing sys.modules
# would also work, but takes 60-120 s and flakes on slow CI runners.
import re
from pathlib import Path

from litellm.proxy._lazy_features import LAZY_FEATURES

proxy_server_src = (
Path(__file__).resolve().parents[3] / "litellm/proxy/proxy_server.py"
).read_text()

leaks = []
for feat in LAZY_FEATURES:
# Anchor at column 0 — indented imports inside function bodies
# are fine (deferred until the function runs).
pattern = (
rf"^(from\s+{re.escape(feat.module_path)}\s+import|"
rf"import\s+{re.escape(feat.module_path)})"
)
if re.search(pattern, proxy_server_src, re.MULTILINE):
leaks.append(feat.module_path)

assert not leaks, (
"proxy_server.py top-level imports a lazy feature module — these "
f"should be loaded via LazyFeatureMiddleware: {leaks}"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Static scan doesn't catch transitive imports — test no longer verifies its own docstring

The class docstring states the test ensures "gated feature modules must NOT be present in sys.modules immediately after proxy_server imports," but the new implementation only checks for direct import X / from X import statements at column 0 in proxy_server.py. It misses two real failure modes:

  1. Transitive imports: if any module that proxy_server.py imports at the top level itself imports a lazy feature, the heavy module will appear in sys.modules at startup, but this scan won't detect it.
  2. Partial-path form: from litellm.proxy.guardrails import guardrail_endpoints causes the same startup load as the matched patterns but is undetected because the regex only anchors on the full module_path in the from clause.

Rule Used: What: Flag any modifications to existing tests and... (source)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is intentional.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Got it — the trade-off is intentional. A fast, partial check that catches direct top-level imports is a reasonable pragmatic choice over a correct-but-slow subprocess check that flakes on CI.

Tip: You can give me more context with .greptile/rules.md so I get this right next time.

@Michael-RZ-Berri
Michael-RZ-Berri merged commit e810d87 into litellm_internal_staging Apr 30, 2026
108 of 116 checks passed
@Michael-RZ-Berri
Michael-RZ-Berri deleted the litellm_lazyStartupTestFix branch April 30, 2026 23:42
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
[Fix] Replace subprocess startup-import diff with static source scan
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants