Skip to content

fix(deps): move pydantic-settings into the base dependencies - #35518

Merged
yuneng-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_/windows-litellm-import-fail-4acb08
Aug 1, 2026
Merged

fix(deps): move pydantic-settings into the base dependencies#35518
yuneng-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_/windows-litellm-import-fail-4acb08

Conversation

@yuneng-berri

Copy link
Copy Markdown
Collaborator

TLDR

Problem this solves:

  • pip install litellm then import litellm fails
  • pydantic-settings is declared only in the proxy extra
  • The base import path needs it, so every non-proxy install breaks
  • Only the Windows job installs without extras, so this was caught by luck

How it solves it:

  • Move pydantic-settings into [project].dependencies
  • Add a CI job that installs the built wheel with no extras
  • Smoke-check import, completion, embedding, pricing data, token counter

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
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • 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)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Both runs build a wheel from the repo, install it into a clean venv with no extras, and make the same real Anthropic call. No mocks; the call costs real money

Before, at b1fd20f4cd

uv build --wheel --out-dir beforedist
uv venv proof_before --python 3.13
VIRTUAL_ENV=proof_before uv pip install beforedist/*.whl
proof_before/bin/python -c "
import litellm
r = litellm.completion(model='claude-opus-5', messages=[{'role':'user','content':'Reply with exactly: base install works'}], max_tokens=20)
print('content:', r.choices[0].message.content)
"
  File ".../site-packages/litellm/integrations/otel/model/config.py", line 8, in <module>
    from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict
ModuleNotFoundError: No module named 'pydantic_settings'

After, at 7447f9babc

Same three commands against a wheel built at the fix commit:

content: base install works
model: claude-opus-5
usage: 17 in / 5 out
cost USD: 0.00021

The same break in a published artifact

The last two dev releases on PyPI carry it, so this is reproducible without building anything:

pip install litellm==1.96.0.dev2 && python -c "import litellm"
  File ".../litellm/integrations/opentelemetry.py", line 30, in <module>
    from litellm.integrations.otel.model.semconv import Metric
  File ".../litellm/integrations/otel/__init__.py", line 16, in <module>
    from litellm.integrations.otel.model.config import (
  File ".../litellm/integrations/otel/model/config.py", line 8, in <module>
    from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict
ModuleNotFoundError: No module named 'pydantic_settings'

Current PyPI stable is 1.94.1 and imports fine, and the Docker images install --extra proxy, so neither is affected

The new CI job, run end to end in the pinned CI image

Red against b1fd20f4cd, which is the tail of the log a reviewer would actually read:

    from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict
ModuleNotFoundError: No module named 'pydantic_settings'

A base `pip install litellm` is broken at: import litellm
Something needed at import or call time is missing from [project].dependencies
in pyproject.toml. Declaring it only in an extra is what causes this.
### exit: 1

Green against 7447f9babc:

PASS  environment is base-only: no extras-only packages present (fastapi, boto3, uvicorn)
PASS  import litellm: imported litellm 1.96.0
PASS  chat completion: mock completion round-trips
PASS  embedding: mock embedding round-trips
PASS  bundled model metadata: bundled pricing metadata readable (gpt-4o max_input_tokens=128000)
PASS  token counter: token_counter returned 2

all 6 checks passed
### exit: 0

Type

🐛 Bug Fix

✅ Test

Changes

import litellm reaches litellm/integrations/otel/model/config.py through litellm_core_utils/litellm_logging.py, which imports integrations/agentops, which imports integrations/opentelemetry, which imports a submodule of the otel package and therefore runs its __init__. Every link is unconditional and at module level, so pydantic-settings is required to import the SDK at all. It was declared only in the proxy extra, which left the base install and every other extra unimportable on all platforms

tests/base_sdk_tests/check_base_sdk_install.py is the guard. The CI job builds the wheel, installs it into a fresh venv with no extras, and runs the script with that venv's interpreter. It is stdlib-only on purpose: installing pytest into that venv would add packaging, pluggy and iniconfig and could mask the class of undeclared dependency it exists to catch. Its first check asserts fastapi, boto3 and uvicorn are absent, so a job misconfiguration that installed extras fails loudly instead of passing as a no-op. It stops at the first failure because cascading import errors bury the real cause at the bottom of a CI log

get_model_info is in the check for packaging rather than logic; it only passes when the bundled pricing JSON actually shipped inside the wheel

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

`import litellm` reaches litellm/integrations/otel/model/config.py via
litellm_core_utils/litellm_logging.py, so pydantic-settings is needed at import
time. It was declared only in the `proxy` extra, which left a plain
`pip install litellm` unimportable on every platform.

Adds tests/base_sdk_tests/check_base_sdk_install.py and a base_sdk_install
CircleCI job that builds the wheel, installs it into a clean venv with no extras,
and smoke-checks the import, a mock completion, a mock embedding, the bundled
pricing metadata and the token counter. The check is stdlib-only on purpose;
installing pytest into that venv would add packaging, pluggy and iniconfig and
could mask the class of undeclared dependency it exists to catch.

Previously the Windows job was the only one installing without extras, so this
class of break was caught by accident rather than by design.
@yuneng-berri
yuneng-berri requested a review from a team August 1, 2026 22:32
@greptile-apps

greptile-apps Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR promotes pydantic-settings from the proxy extra to the base SDK dependencies and adds a wheel-level CI smoke test for no-extras installations.

  • Updates project and lockfile dependency metadata consistently.
  • Builds and installs the wheel in a clean virtual environment.
  • Verifies import, mocked completion and embedding, bundled pricing metadata, and token counting.

Confidence Score: 5/5

The PR appears safe to merge, with the dependency promotion and no-extras wheel validation aligned with the reported base-install failure.

The manifest and lockfile consistently make the import-time dependency unconditional, while the new CI job validates the built artifact without installing proxy extras; no actionable regression remains.

Important Files Changed

Filename Overview
pyproject.toml Moves the existing compatible pydantic-settings range into unconditional base dependencies.
uv.lock Consistently promotes pydantic-settings from the proxy extra to the base package dependency metadata.
tests/base_sdk_tests/check_base_sdk_install.py Adds a focused stdlib-only smoke test for a wheel installed without extras.
.circleci/config.yml Adds the base-wheel build, installation, and smoke-check job to the primary workflow.

Reviews (1): Last reviewed commit: "fix(deps): move pydantic-settings into t..." | Re-trigger Greptile

@yuneng-berri
yuneng-berri enabled auto-merge August 1, 2026 22:39
@codecov

codecov Bot commented Aug 1, 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 merged commit 68b1e03 into litellm_internal_staging Aug 1, 2026
79 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_/windows-litellm-import-fail-4acb08 branch August 1, 2026 22:45
@codspeed-hq

codspeed-hq Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_/windows-litellm-import-fail-4acb08 (7447f9b) with litellm_internal_staging (b1fd20f)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (7447f9b) during the generation of this report, so 90ee82d was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

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