fix(utils): make prompt_token_calculator count claude models again

The claude branch called the anthropic SDK's `Anthropic().count_tokens`, which the
SDK removed, so every claude call raised AttributeError. Counting now goes through
litellm's own token_counter, which handles anthropic models offline and drops the
SDK dependency entirely.

Hiding that was a swallowed error: `except Exception: Exception("Anthropic import
failed please run `pip install anthropic`")` built the exception without raising
it, so an environment missing the SDK fell through to the unguarded
`from anthropic import ...` on the next line and got a bare ModuleNotFoundError
instead of the install hint.

That was the codebase's last PLW0133, so the rule graduates from the ratcheted
budget into ruff.toml where it hard-fails, and editors get the diagnostic inline.
This commit is contained in:
ryan-crabbe-berri 2026-08-24 12:19:03 -07:00
parent f818a48ae5
commit 6975b8ea4b
4 changed files with 25 additions and 21 deletions

View file

@ -6526,21 +6526,10 @@ def acreate(*args, **kwargs): ## Thin client to handle the acreate langchain ca
def prompt_token_calculator(model, messages):
# use tiktoken or anthropic's tokenizer depending on the model
text: Final = " ".join(message["content"] for message in messages)
num_tokens = 0
if "claude" in model:
try:
import anthropic
except Exception:
Exception("Anthropic import failed please run `pip install anthropic`")
from anthropic import AI_PROMPT, HUMAN_PROMPT, Anthropic
anthropic_obj: Final = Anthropic()
num_tokens = anthropic_obj.count_tokens(text)
else:
num_tokens = len(_get_default_encoding().encode(text))
return num_tokens
return token_counter(model=model, text=text)
return len(_get_default_encoding().encode(text))
def valid_model(model):

View file

@ -57,7 +57,7 @@
"limit": 3
},
"BLE001": {
"limit": 2920
"limit": 2919
},
"C401": {
"limit": 8
@ -108,7 +108,7 @@
"limit": 3
},
"F401": {
"limit": 17
"limit": 14
},
"LOG015": {
"limit": 5
@ -152,9 +152,6 @@
"PLW0127": {
"limit": 57
},
"PLW0133": {
"limit": 1
},
"PLW0602": {
"limit": 215
},

View file

@ -5,9 +5,9 @@ lint.ignore = ["F405", "E402", "F403"]
lint.extend-select = [
"T20", "PGH004", "RUF008", "RUF009", "RUF100",
"B033", "FURB136", "FURB168", "FURB188", "I001", "PERF402", "PIE790", "PIE800", "PLC0208",
"PLR0402", "PLR1711", "PLR1730", "PLR2044", "PYI030", "PYI041", "PYI064", "RET501", "RUF010",
"RUF022", "RUF023", "RUF051", "SIM114", "SIM118", "TC005", "UP006", "UP007", "UP008", "UP012",
"UP018", "UP024", "UP032", "UP034", "UP035", "UP037", "UP045",
"PLR0402", "PLR1711", "PLR1730", "PLR2044", "PLW0133", "PYI030", "PYI041", "PYI064", "RET501",
"RUF010", "RUF022", "RUF023", "RUF051", "SIM114", "SIM118", "TC005", "UP006", "UP007", "UP008",
"UP012", "UP018", "UP024", "UP032", "UP034", "UP035", "UP037", "UP045",
]
# RUF100 (unused-noqa) only knows the rules enabled in THIS config, so it would strip
# `# noqa` directives that protect rules enforced elsewhere. List those codes as external

View file

@ -1,6 +1,7 @@
import json
import logging
import os
import sys
from typing import Final
from unittest.mock import AsyncMock, MagicMock, patch
@ -41,6 +42,7 @@ from litellm.utils import (
get_prompt_cache_min_tokens,
is_cached_message,
is_prompt_caching_valid_prompt,
prompt_token_calculator,
)
# Adds the parent directory to the system path
@ -4973,3 +4975,19 @@ def test_completion_does_not_leak_rust_flag_into_provider_request_body():
create_kwargs = mock_client.chat.completions.with_raw_response.create.call_args.kwargs
assert "rust" not in create_kwargs
assert "rust" not in (create_kwargs.get("extra_body") or {})
def test_prompt_token_calculator_counts_claude_without_the_anthropic_sdk():
"""
The claude branch used to call the anthropic SDK's `count_tokens`, which the SDK
removed, so every claude call raised AttributeError. Counting must work with
`anthropic` unimportable.
"""
messages: Final = [{"role": "user", "content": "the quick brown fox jumps over the lazy dog"}]
with patch.dict(sys.modules, {"anthropic": None}):
claude_tokens = prompt_token_calculator("claude-sonnet-4-5", messages)
gpt_tokens = prompt_token_calculator("gpt-4o", messages)
assert claude_tokens == 9
assert gpt_tokens == 9