Skip to content

test: unshadow the module handles the F811 sweep left behind - #37914

Merged
yuneng-berri merged 11 commits into
litellm_internal_stagingfrom
litellm_/cci-red-tests-regression-8cc5e8
Aug 22, 2026
Merged

test: unshadow the module handles the F811 sweep left behind#37914
yuneng-berri merged 11 commits into
litellm_internal_stagingfrom
litellm_/cci-red-tests-regression-8cc5e8

Conversation

@yuneng-berri

@yuneng-berri yuneng-berri commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

How it solves it:

  • Drop the inner import litellm.proxy.proxy_server the hasattr guard makes redundant
  • Enable F823 in ruff-tests.toml, which flags all four sites
  • Fix the stale completion read and patch the router via monkeypatch
  • Inject a rejecting AsyncOpenAI client for the content policy test
  • Tolerate a failed batch only on the org token-limit error, log the errors

User Flow

Before: whoever promotes staging to main opens the PR and cannot trust the CircleCI result

  1. They open chore(ci): promote internal staging to main #37913 and see six ci/circleci checks red
  2. They open llm_responses_api_testing, litellm_router_unit_testing and litellm_mapped_enterprise_tests and every test reads UnboundLocalError: cannot access local variable 'litellm' at fixture setup, 0 tests executed
  3. They open local_testing_part2 and see module 'litellm.proxy' has no attribute 'proxy_server' and 'function' object has no attribute 'choices'
  4. They open local_testing_part1 and see DID NOT RAISE ContentPolicyViolationError on a live gpt-3.5-turbo lyrics prompt
  5. They open batches_testing and see 409 Cannot cancel a batch with status 'failed', with no record of why the batch failed

After: the same promotion PR shows the six checks green and the three setup-blocked suites actually ran

  1. They open the promotion PR and the six ci/circleci checks are green
  2. The three previously blocked suites report their full test counts instead of setup errors
  3. make lint on the test tree now fails on any fixture that reads a module-level name before shadowing it, with ruff naming the line

Relevant issues

Linear ticket

Pre-Submission checklist

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

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Screenshots / Proof of Fix

The change is test-only, so the end-to-end proof is the CircleCI workflow itself, plus the lint rule firing on the exact lines the sweep broke

Before (7481649)

CircleCI on the promotion PR at 49da936

  1. https://app.circleci.com/workflow/7c1ce323-57cc-49cd-9df8-f1976d06b799
  2. llm_responses_api_testing, litellm_router_unit_testing, litellm_mapped_enterprise_tests: every test errors at setup with UnboundLocalError: cannot access local variable 'litellm' where it is not associated with a value
  3. local_testing_part2: test_openai_moderation_error_raising fails with AttributeError: module 'litellm.proxy' has no attribute 'proxy_server', test_stream_chunk_builder_openai_audio_output_usage fails with AttributeError: 'function' object has no attribute 'choices'
  4. local_testing_part1: test_content_policy_exception_openai fails with DID NOT RAISE <class 'litellm.exceptions.ContentPolicyViolationError'>
  5. batches_testing: test_async_create_batch[openai] fails with openai.ConflictError: Error code: 409 - Cannot cancel a batch with status 'failed'

F823 on the four conftests at the merge base

  1. ruff check --isolated --select F823 tests/llm_responses_api_testing/conftest.py tests/router_unit_tests/conftest.py tests/enterprise/conftest.py tests/vector_store_tests/conftest.py
  2. Four findings, one per file, each F823 Local variable 'litellm' referenced before assignment at the importlib.reload(litellm) line

After (8529c71)

CircleCI on this PR

  1. https://app.circleci.com/workflow/c5f572dd-cd89-4801-983b-db1fa0c28c31
  2. 47 of 47 jobs green
  3. llm_responses_api_testing executed 170 tests, litellm_router_unit_testing 319, litellm_mapped_enterprise_tests 244, where the promotion run executed 0 in each
  4. local_testing_part1, local_testing_part2 and batches_testing green

F823 on the test tree

  1. ruff check --config ruff-tests.toml tests
  2. All checks passed!

Mutation check on the rewritten content policy test

  1. Change the injected rejection's code to some_other_error and run pytest tests/local_testing/test_exceptions.py::test_content_policy_exception_openai
  2. 1 failed, with litellm.BadRequestError raised in place of ContentPolicyViolationError
  3. Restore the fix, rerun: 1 passed

Type

✅ Test

Caveats (if any)

  • The batch 409 reproduced only in CI's OpenAI org; it passes locally
  • The token-limit cause is inferred, the added log line confirms or refutes it on the next run

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

… the two live tests that went red with it

The F811 sweep in #37878 removed the fixture-local `import litellm` from four
conftests, but the bare `import litellm.proxy.proxy_server` a few lines below
still binds `litellm` as a function local, so `importlib.reload(litellm)` runs
before the name is assigned and every test in those directories errors at
setup. The `hasattr` guard on the line above already proves the module is
loaded, so the import only ever bound the name. Drop it, and enable F823 in
ruff-tests.toml, which flags all four sites at the failing line and would have
blocked the sweep

The same sweep renamed the `check_non_streaming_response` parameter but left
one read of `completion`, which now resolves to `litellm.completion`, and
removed an import whose side effect was the only thing making
`litellm.proxy.proxy_server` reachable in the moderation hook test. That test
already takes `monkeypatch`, so patch the router through it and stop leaking
the router into later tests

`test_content_policy_exception_openai` passed vacuously until #37887 turned it
into a real `pytest.raises`, and OpenAI no longer rejects a lyrics prompt with
a content policy error. Inject an AsyncOpenAI client whose transport answers
with OpenAI's own `content_policy_violation` rejection so the mapping to
ContentPolicyViolationError is exercised every run

`test_async_create_batch` hit a 409 cancelling a batch OpenAI had already
marked failed. The cancel step tolerated a completed batch but not a failed
one. Fold both guards into one helper that tolerates a failed batch only when
OpenAI's recorded error is the org's enqueued token limit, and prints the
batch's errors so the reason is in the log either way
@greptile-apps

greptile-apps Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR repairs test failures introduced by the earlier lint sweep and makes the affected tests deterministic.

  • Removes function-local imports that shadow the module-level litellm handle and enables F823 lint enforcement.
  • Corrects stale response access and restores isolated proxy-router patching.
  • Replaces a live content-policy request with a mocked OpenAI rejection whose client resources are closed after use.
  • Handles expected terminal OpenAI batch states while validating the permitted failure reason.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
ruff-tests.toml Enables F823 to prevent local bindings from shadowing module-level names read earlier in test fixtures.
tests/batches_tests/test_openai_batches_and_files.py Centralizes terminal batch-cancellation handling and validates token-limit failures before tolerating them.
tests/enterprise/conftest.py Removes the inner proxy-server import that made litellm local and broke fixture setup.
tests/llm_responses_api_testing/conftest.py Removes the shadowing import while retaining guarded proxy-server reload behavior.
tests/local_testing/test_exceptions.py Makes the content-policy exception test deterministic with MockTransport and closes the wrapped async HTTP client through the AsyncOpenAI context manager.
tests/local_testing/test_openai_moderations_hook.py Imports the proxy-server module explicitly and uses monkeypatch to restore router state after the test.
tests/local_testing/test_stream_chunk_builder.py Fixes the assertion to inspect the response argument rather than the unrelated completion symbol.
tests/router_unit_tests/conftest.py Removes the function-local import responsible for fixture-wide UnboundLocalError failures.
tests/vector_store_tests/conftest.py Removes the same shadowing import from vector-store test setup.

Reviews (2): Last reviewed commit: "test: close the injected AsyncOpenAI cli..." | Re-trigger Greptile

Comment thread tests/local_testing/test_exceptions.py Outdated
@yuneng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@yuneng-berri
yuneng-berri enabled auto-merge (squash) August 22, 2026 16:11
@yuneng-berri
yuneng-berri merged commit de1bc29 into litellm_internal_staging Aug 22, 2026
66 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_/cci-red-tests-regression-8cc5e8 branch August 22, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants