Skip to content

refactor(lint): apply every safe ruff autofix and zero 28 strict-rule budgets - #35495

Merged
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_up035_abc_imports
Aug 1, 2026
Merged

refactor(lint): apply every safe ruff autofix and zero 28 strict-rule budgets#35495
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_up035_abc_imports

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

How it solves it:

  • applies every ruff fix marked safe across 32 rules
  • moves the 323 abc-movable typing imports to collections.abc
  • ratchets 28 rule budgets to 0, 9 more sharply down

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)

The sweep is guarded by the strict-rule gate itself (scripts/ruff_strict_gate.py fails CI on the first reintroduced violation of any zeroed rule once this merges and becomes the base), and the one behavioral regression the sweep surfaced (annotation introspection on X | None) is covered by the existing test_get_config_list_* suite, which fails with the AttributeError if the introspection fix is removed, plus the updated test_customer_routes_declare_response_model expectation

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

All "after" legs captured on a live proxy at the branch head 85f367b545 (python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml, port 27833), hitting real provider APIs. The "before" leg proxy runs litellm_internal_staging at b1fd20f4cd (port 26991)

All three LLM endpoints against real providers:

$ curl -s -X POST http://localhost:27833/v1/chat/completions -H 'Authorization: Bearer sk-1234' \
    -d '{"model":"gpt-5.5","messages":[{"role":"user","content":"Reply with exactly: sweep ok"}]}'
HTTP 200  {"model": "gpt-5.5", "content": "sweep ok", "total_tokens": 29}

$ curl -s -X POST http://localhost:27833/v1/responses -H 'Authorization: Bearer sk-1234' \
    -d '{"model":"gpt-5.5","input":"Reply with exactly: responses ok"}'
HTTP 200  {"model": "gpt-5.5", "output_text": ["responses ok"], "status": "completed"}

$ curl -s -X POST http://localhost:27833/v1/messages -H 'Authorization: Bearer sk-1234' \
    -d '{"model":"anthropic-haiku-4-5","max_tokens":50,"stream":true,"messages":[{"role":"user","content":"Reply with exactly: stream ok"}]}'
event: message_start
data: {"type":"message_start","message":{"model":"claude-haiku-4-5-20251001","id":"msg_011CdctDDxCZSN5qMKqjWmRj",...}}
event: content_block_start
...

DB-backed management routes:

$ curl -s -X POST http://localhost:27833/customer/new -H 'Authorization: Bearer sk-1234' \
    -d '{"user_id":"sweep-proof-85f367b5","max_budget":5}'
HTTP 200  {"user_id":"sweep-proof-85f367b5","blocked":false,...,"litellm_budget_table":{...,"max_budget":5.0,...}}

$ curl -s 'http://localhost:27833/customer/info?end_user_id=sweep-proof-85f367b5' -H 'Authorization: Bearer sk-1234'
HTTP 200  (same object back)

The one runtime surface the sweep touched: /config/list introspects the rewritten annotations. Both legs return 200; the nested field_type strings show the annotations actually changed at runtime. Without the UnionType hand-fix in this push, the after leg 500s with AttributeError: 'types.UnionType' object has no attribute '__name__' (that is what test_get_config_list_* now guards)

$ curl -s 'http://localhost:26991/config/list?config_type=general_settings' -H 'Authorization: Bearer sk-1234'   # before, b1fd20f4cd
HTTP 200  ..."field_name":"timeout","field_type":"Optional"...

$ curl -s 'http://localhost:27833/config/list?config_type=general_settings' -H 'Authorization: Bearer sk-1234'   # after, 85f367b545
HTTP 200  ..."field_name":"timeout","field_type":"float | None"..."field_type":"str | None"..."field_type":"list[str] | None"...

The ratchet doing its job (simulating the post-merge world by pointing the gate's base at this branch):

$ printf '\nfrom typing import List\n\ndemo_regression: List[int] = []\n' >> litellm/_redis.py
$ python scripts/ruff_strict_gate.py --base HEAD
FAIL: strict-rule totals exceed their limit (base HEAD):
  TID251: total 1171 over limit 0 (this change added 1)
    litellm/_redis.py:813
  UP006: total 1 over limit 0 (this change added 1)
    litellm/_redis.py:815
  UP035: total 1 over limit 0 (this change added 1)
    litellm/_redis.py:813

Type

🧹 Refactoring

Changes

Two mechanical passes and a handful of hand fixes for what the fixers could not see

Commit 397e8e4918 (the original scope): ruff check litellm --config ruff-strict.toml --select UP035 --fix moved every abc-movable name (Mapping, Sequence, Iterable, Callable, Generator, and friends) from typing to collections.abc across 321 files, plus a scoped I001 re-sort

Commit b604e2b20c extends that to every safely auto-fixable rule. ruff --fix over 32 rules applied about 35,000 fixes ruff marks safe (UP006 List[x] -> list[x], UP045 Optional[x] -> x | None, UP007 Union -> |, UP037 quote removal, UP032 f-strings, RUF010 f-string conversions, PIE790, SIM114, SIM118, RET501, and friends). A targeted pass then removed the 1,296 typing imports the rewrite orphaned (filtered to typing.* names only, so no unrelated F401 removals), and 16 dead typing imports shielded by per-file F401 ignores in main.py, utils.py, proxy_server.py, and proxy/utils.py were removed by hand after confirming their only remaining "usages" were docstrings

Hand fixes for fallout the fixers could not see:

  • five files freeloaded Optional/Dict/List through from litellm.proxy._types import * (F403/F405 are ignored repo-wide, so no linter sees this); their usages are now spelled with builtins and an AST scan asserts zero remaining star-freeloaded typing names across litellm/, tests/, and enterprise/
  • two F823s where UP037/UP045 unquoted annotations whose class is imported later in the function; the imports are hoisted above the annotation
  • /config/list introspection crashed on X | None (types.UnionType has no __name__) and its origin is Union checks missed the new union form; both handle UnionType now
  • in ui_sso.py, unquoting Optional["RoleMappings"] exposed two redundant function-local RoleMappings imports that shadowed the module-level import and left the new annotation statically unbound; the local imports are removed
  • one FURB168 rewrite left a tautology (arg is not None and not (arg is None)), collapsed to a single check
  • one typing.Optional orphan in bedrock/chat/__init__.py the import pass missed, removed

Merge commit 85f367b545 brings litellm_internal_staging back in and re-applies the sweep to the merged-in code (the same ruff --fix pass plus the orphaned-typing-import removal), so the zeroed rules stay at an actual 0 after the merge. The five conflicted files were resolved by taking the incoming side's logic and re-running the sweep over it; every merge-touched module was import-smoke-tested and its mapped test files pass

Four fixable rules are excluded on purpose. B009/B010 (getattr(x, "attr")/setattr(...) to direct attribute access), PIE804 (f(**{...}) to keyword arguments), and RUF019 ("k" in d and d["k"] to d.get("k")) have "safe" fixes that are runtime-neutral but convert type-checker escape hatches into static errors: applying their 326 fixes added 283 basedpyright errors (226 reportAttributeAccessIssue, 44 reportCallIssue, 13 reportTypedDictNotRequiredAccess from narrowing loss on later lines). Those fixes were applied, measured, and reverted; the four budgets stay at base values. Also excluded: RUF100 (its unused-noqa verdicts are config-relative, so a strict-config fix would strip directives the main config needs) and blanket F401 removal (import side effects; only the typing names the rewrite itself orphaned were removed)

ruff-strict-budget.json is ratcheted by 39,579 in b604e2b20c (39,968 across the branch). 28 rules now sit at an actual 0 (UP006, UP008, UP012, UP018, UP024, UP034, UP035, UP045, I001, RUF010, RUF023, RUF051, PIE790, PIE800, PLC0208, PLR0402, PLR1711, PLR1730, PLR2044, PYI030, PYI041, PYI064, RET501, SIM114, TC005, B033, FURB136, FURB168), so once this merges the gate fails on the first new violation of any of them with no offsetting possible. 9 partially-fixable rules dropped sharply: UP007 2526 -> 66, TID251 2649 -> 1170, SIM118 114 -> 44, UP032 626 -> 1, UP037 104 -> 2, RUF022 85 -> 6, FURB188 52 -> 1, RUF046 8 -> 4, C901 down 2. Net effect on basedpyright: 144 fewer errors than base

type-discipline-budget.json moves too: LIT002 -19, LIT006 -1, LIT009 -2 via the official --update ratchet, and LIT001 goes 23191 -> 23350 by hand. That last one is a ceiling raise, so to be explicit about why: the LIT001 checker pattern-matches the spelling set but not the alias Set, so the 160 typing.Set[...] annotations this sweep rewrote to set[...] were always mutable-set annotations and only now count. The debt is pre-existing, the measurement got honest, and the new limit sits exactly at the measured total with zero headroom (the old limit had 1). Teaching the checker the Set alias instead was considered and rejected: after this sweep collections.abc.Set (the read-only ABC) is the only UP035-clean spelling of an abstract set, and a name-based checker cannot tell it apart from typing.Set

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

Note

Low Risk
Changes are mechanical typing and lint-budget ratchets with targeted runtime fixes for config introspection; proxy/LLM paths were smoke-tested per the PR description.

Overview
This PR applies safe ruff autofixes across a large swath of litellm/ (~35k+ edits): Optional[T]T | None, List/Dictlist/dict, Union|, ABC imports moved to collections.abc, f-strings, and similar style-only cleanups. Behavior is intended to stay the same; the diff is overwhelmingly annotation and import spelling.

Hand fixes address what the fixers could not handle safely: /config/list (and related introspection) now treats types.UnionType (X | None) so field_type strings like float | None work instead of 500ing; star-import typing freeloaders are removed; a few forward-ref / import-order and tautology fixes from the sweep.

Lint policy ratchets 28 strict-rule budgets to 0 (e.g. UP006, UP035, UP045, I001) so CI blocks reintroducing those patterns; four “safe” rules stay excluded where fixes break type-checking. type-discipline-budget.json is updated (including an honest LIT001 ceiling after typing.Set[...]set[...]).

Reviewed by Cursor Bugbot for commit 85f367b. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (1480 files found, 500 file limit)

@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_up035_abc_imports (85f367b) with litellm_internal_staging (68b1e03)1

Open in CodSpeed

Footnotes

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

… budgets

About 35,000 fixes ruff marks safe across 32 rules (UP006/UP045/UP007
modern annotations, UP032 f-strings, SIM114/SIM118, RET501, and
friends), removal of the 1,296 typing imports the rewrite orphaned, and
hand fixes for what the fixers could not see: five star-import
freeloaders of typing names, two F823 late-import annotations, the
/get/config/list introspection crash on types.UnionType, redundant
function-local RoleMappings imports in ui_sso.py that shadowed the
module-level name once the annotation lost its quotes, and one FURB168
tautology.

B009/B010/PIE804/RUF019 are excluded on purpose: their safe fixes
rewrite getattr/setattr/**-splat/key-in-dict escape hatches into forms
basedpyright then rejects (283 new errors measured), so their budgets
stay at base values.

ruff-strict-budget.json drops by 39,579 this commit (39,968 across the
branch) with 28 rules at an actual 0 and 9 more sharply down.
type-discipline-budget.json ratchets LIT002/LIT006/LIT009 down; LIT001
moves to the now-honest total: the checker matches the spelling `set`
but not the alias `Set`, so the 160 typing.Set annotations rewritten to
set[...] were always mutable-set annotations and only now count.
@mateo-berri mateo-berri changed the title refactor(imports): move collections.abc names out of typing and ratchet the lint budgets refactor(lint): apply every safe ruff autofix and zero 28 strict-rule budgets Aug 1, 2026
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

…itellm_up035_abc_imports

# Conflicts:
#	litellm/llms/bedrock/base_aws_llm.py
#	litellm/proxy/proxy_cli.py
#	litellm/proxy/proxy_server.py
#	litellm/repositories/model_repository.py
#	litellm/router.py
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 85f367b. Configure here.

@mateo-berri
mateo-berri merged commit e5a4911 into litellm_internal_staging Aug 1, 2026
83 of 84 checks passed
@mateo-berri
mateo-berri deleted the litellm_up035_abc_imports branch August 1, 2026 23:33
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.

2 participants