refactor(types): keep /cache/delete on main's behavior

Restores the cache delete route and its test to main, so this types PR changes no response. Rejecting a non-list keys is left for its own change, since an object keys deletes its keys on main today.
This commit is contained in:
mateo-berri 2026-10-28 21:25:21 -07:00
parent bd31b30c21
commit 2dfc9b93d4
2 changed files with 2 additions and 46 deletions

View file

@ -2,8 +2,6 @@ from collections.abc import Mapping
from typing import Final
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import ConfigDict, TypeAdapter, ValidationError, with_config
from typing_extensions import NotRequired, ReadOnly, TypedDict
import litellm
from litellm._logging import verbose_proxy_logger
@ -14,14 +12,6 @@ from litellm.proxy._types import ProxyErrorTypes, ProxyException
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.types.caching import CachePingResponse, HealthCheckCacheParams
@with_config(ConfigDict(extra="allow", strict=True))
class _CacheDeleteRequest(TypedDict):
keys: ReadOnly[NotRequired[list[str | int | float] | None]]
_CACHE_DELETE_REQUEST: Final = TypeAdapter(_CacheDeleteRequest)
masker: Final = SensitiveDataMasker()
router: Final = APIRouter(
@ -159,8 +149,8 @@ async def cache_delete(request: Request):
if litellm.cache is None:
raise HTTPException(status_code=503, detail="Cache not initialized. litellm.cache is None")
request_data: Final = _CACHE_DELETE_REQUEST.validate_python(await request.json())
keys: Final = request_data.get("keys")
request_data: Final = await request.json()
keys: Final = request_data.get("keys", None)
if litellm.cache.type == "redis":
await litellm.cache.delete_cache_keys(keys=keys)
@ -172,8 +162,6 @@ async def cache_delete(request: Request):
status_code=500,
detail=f"Cache type {litellm.cache.type} does not support deleting a key. only `redis` is supported",
)
except ValidationError as e:
raise HTTPException(status_code=400, detail=e.errors(include_url=False, include_input=False))
except Exception as e:
raise HTTPException(
status_code=500,

View file

@ -1,11 +1,8 @@
import json
from typing import Final
from unittest.mock import MagicMock
import pytest
from fastapi.testclient import TestClient
from pydantic import ValidationError
from pytest_mock import MockerFixture
@ -55,35 +52,6 @@ def mock_redis_failure(mocker):
return mock_cache
@pytest.fixture
def mock_redis_delete(mocker: MockerFixture) -> MagicMock:
mock_cache: Final = mocker.MagicMock()
mock_cache.type = "redis"
mock_cache.delete_cache_keys = mocker.AsyncMock()
mocker.patch.object(litellm, "cache", mock_cache)
return mock_cache
@pytest.mark.parametrize("keys", [["a-key", "b-key"], [12345, 1.5]])
def test_cache_delete_passes_string_and_numeric_keys_to_the_cache(
mock_redis_delete: MagicMock, keys: list[str | int | float]
) -> None:
response: Final = client.post("/cache/delete", headers={"Authorization": "Bearer sk-9876"}, json={"keys": keys})
assert response.status_code == 200
assert response.json() == {"status": "success"}
mock_redis_delete.delete_cache_keys.assert_awaited_once_with(keys=keys)
def test_cache_delete_rejects_keys_that_are_not_a_list_with_a_400_that_hides_them(mock_redis_delete: MagicMock) -> None:
response: Final = client.post("/cache/delete", headers={"Authorization": "Bearer sk-9876"}, json={"keys": "sk-secret-key"})
assert response.status_code == 400
assert response.json()["detail"][0]["loc"] == ["keys"]
assert "sk-secret-key" not in response.text
mock_redis_delete.delete_cache_keys.assert_not_awaited()
def test_cache_ping_success(mock_redis_success):
"""Test successful cache ping with regular response"""
response = client.get("/cache/ping", headers={"Authorization": "Bearer sk-9876"})