test(lint): ban blind pytest.raises(Exception) with ruff B017 (#37731)

* test(lint): ban blind pytest.raises(Exception) with ruff B017

A bare pytest.raises(Exception) accepts whatever the body throws. The TypeError
a refactor introduces satisfies it exactly as well as the rejection the test was
written for, so the crash reads as a pass and the test never goes red.

All 111 existing sites are narrowed here. A runtime probe recorded the concrete
exception each one actually catches, and each site now names that type. Where
the code under test genuinely raises a bare Exception, the site pins a stable
slice of the message with match= instead.

Two sites tell on themselves. The shared responses-API cancel test raises
"custom_llm_provider is required but passed as None" rather than talking to a
provider at all, because cancel_responses takes a provider, not a model. And
test_bedrock_guardrails_with_streaming was the only test in its file still
passing without AWS credentials, because the NoCredentialsError boto3 raised
long before the guardrail ran satisfied the blind raises.

* fix(test): widen the openai batch-dispatch assertion to OpenAIError

The narrowed NotFoundError only holds where OPENAI_API_KEY is set. Without one
the SDK raises OpenAIError while building the client, long before any 404, so CI
went red. OpenAIError covers both and still rejects a TypeError from a refactor.
This commit is contained in:
ryan-crabbe-berri 2026-08-20 18:09:42 -07:00 committed by GitHub
parent 6eacdbfbf0
commit 680bcfd8aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
58 changed files with 151 additions and 116 deletions

View file

@ -14,6 +14,9 @@
# B018 a bare attribute access or literal, usually a call missing its parens
# PLW0127 `x = x` self-assignment, dead code that reads like a narrowing or a fixup
# PLR0133 comparison of two constants, e.g. `assert True == True`
# B017 `pytest.raises(Exception)` accepts the TypeError a refactor introduced just as
# readily as the rejection under test, so a crash reads as a pass. Narrow to the
# real type, or add `match=` where the code genuinely raises a bare Exception
#
# No target-version here on purpose: it resolves from requires-python (>=3.10), so
# 3.11-only builtins like BaseExceptionGroup are correctly flagged in a tree that
@ -21,4 +24,4 @@
line-length = 120
lint.select = ["F821", "B011", "B015", "B018", "PT015", "PLR0133", "PLW0127"]
lint.select = ["F821", "B011", "B015", "B017", "B018", "PT015", "PLR0133", "PLW0127"]

View file

@ -197,6 +197,7 @@ async def test_bedrock_guardrails_block_responses_api():
@pytest.mark.asyncio
async def test_bedrock_guardrails_with_streaming():
from fastapi import HTTPException
from litellm.proxy.utils import ProxyLogging
from litellm.types.guardrails import GuardrailEventHooks
@ -204,7 +205,7 @@ async def test_bedrock_guardrails_with_streaming():
mock_user_api_key_cache = MagicMock(spec=DualCache)
mock_user_api_key_dict = UserAPIKeyAuth()
with pytest.raises(Exception): # Assert that this raises an exception
with pytest.raises(HTTPException):
proxy_logging_obj = ProxyLogging(
user_api_key_cache=mock_user_api_key_cache,
premium_user=True,

View file

@ -20,6 +20,7 @@ from litellm.proxy.guardrails.guardrail_hooks.litellm_content_filter.content_fil
from litellm.types.proxy.guardrails.guardrail_hooks.litellm_content_filter import (
ContentFilterCategoryConfig,
)
from fastapi import HTTPException
# Test cases: (sentence, expected_result, reason)
@ -275,7 +276,7 @@ class TestEUAIActEdgeCases:
for sentence in sentences:
request_data = {"messages": [{"role": "user", "content": sentence}]}
with pytest.raises(Exception):
with pytest.raises(HTTPException):
await content_filter_guardrail.apply_guardrail(
inputs={"texts": [sentence]},
request_data=request_data,
@ -289,7 +290,7 @@ class TestEUAIActEdgeCases:
request_data = {"messages": [{"role": "user", "content": sentence}]}
# Should block (contains multiple violations)
with pytest.raises(Exception):
with pytest.raises(HTTPException):
await content_filter_guardrail.apply_guardrail(
inputs={"texts": [sentence]},
request_data=request_data,

View file

@ -19,6 +19,7 @@ from litellm.proxy.guardrails.guardrail_hooks.litellm_content_filter.content_fil
from litellm.types.proxy.guardrails.guardrail_hooks.litellm_content_filter import (
ContentFilterCategoryConfig,
)
from fastapi import HTTPException
@pytest.fixture
@ -228,7 +229,7 @@ class TestFrenchEdgeCases:
request_data = {"messages": [{"role": "user", "content": sentence}]}
# Should block (contains "build" and "système de crédit social")
with pytest.raises(Exception):
with pytest.raises(HTTPException):
await content_filter_guardrail.apply_guardrail(
inputs={"texts": [sentence]},
request_data=request_data,
@ -257,7 +258,7 @@ class TestFrenchEdgeCases:
request_data = {"messages": [{"role": "user", "content": sentence}]}
# Should block (case-insensitive)
with pytest.raises(Exception):
with pytest.raises(HTTPException):
await content_filter_guardrail.apply_guardrail(
inputs={"texts": [sentence]},
request_data=request_data,

View file

@ -10,6 +10,7 @@ sys.path.insert(0, os.path.abspath("../.."))
from unittest.mock import MagicMock
import pytest
from fastapi import HTTPException
class TestRouteLoader:
@ -307,7 +308,7 @@ class TestContentFilterSqlInjectionTemplate:
@pytest.mark.asyncio
async def test_sql_always_block(self, sql_injection_guardrail, sentence, reason):
request_data = {"messages": [{"role": "user", "content": sentence}]}
with pytest.raises(Exception):
with pytest.raises(HTTPException):
await sql_injection_guardrail.apply_guardrail(
inputs={"texts": [sentence]},
request_data=request_data,
@ -343,7 +344,7 @@ class TestContentFilterSqlInjectionTemplate:
self, sql_injection_guardrail, sentence, reason
):
request_data = {"messages": [{"role": "user", "content": sentence}]}
with pytest.raises(Exception):
with pytest.raises(HTTPException):
await sql_injection_guardrail.apply_guardrail(
inputs={"texts": [sentence]},
request_data=request_data,
@ -552,7 +553,7 @@ class TestContentFilterPromptInjectionTemplate:
@pytest.mark.asyncio
async def test_always_block(self, content_filter_guardrail, sentence, reason):
request_data = {"messages": [{"role": "user", "content": sentence}]}
with pytest.raises(Exception):
with pytest.raises(HTTPException):
await content_filter_guardrail.apply_guardrail(
inputs={"texts": [sentence]},
request_data=request_data,

View file

@ -444,7 +444,7 @@ async def test_azure_image_generation_request_body():
) as mock_post:
mock_post.side_effect = Exception("test")
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await aimage_generation(
model="azure/gpt-image-1",
prompt="test prompt",

View file

@ -1334,7 +1334,7 @@ def test_validate_chat_completion_user_messages(messages, expected_bool):
validate_chat_completion_user_messages(messages=messages)
else:
## Invalid message
with pytest.raises(Exception):
with pytest.raises(Exception, match="Invalid user message at index 0"):
validate_chat_completion_user_messages(messages=messages)
@ -1354,7 +1354,7 @@ def test_validate_chat_completion_tool_choice(tool_choice, expected_bool):
if expected_bool:
validate_chat_completion_tool_choice(tool_choice=tool_choice)
else:
with pytest.raises(Exception):
with pytest.raises(Exception, match="Invalid tool choice"):
validate_chat_completion_tool_choice(tool_choice=tool_choice)

View file

@ -28,6 +28,7 @@ from openai.types.responses.response_create_params import (
ResponseInputParam,
)
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler
import openai
def validate_responses_api_response(response, final_chunk: bool = False):
@ -700,12 +701,12 @@ class BaseResponsesAPITest(ABC):
base_completion_call_args = self.get_base_completion_call_args()
if sync_mode:
with pytest.raises(Exception):
with pytest.raises(openai.APIError):
litellm.cancel_responses(
response_id="invalid_response_id_12345", **base_completion_call_args
)
else:
with pytest.raises(Exception):
with pytest.raises(openai.APIError):
await litellm.acancel_responses(
response_id="invalid_response_id_12345", **base_completion_call_args
)

View file

@ -1243,7 +1243,7 @@ def test_convert_to_model_response_object_with_error_code_only():
},
}
with pytest.raises(Exception):
with pytest.raises(Exception) as exc_info: # noqa: B017 # bare Exception raised, so status_code is the assertion
convert_to_model_response_object(
model_response_object=ModelResponse(),
response_object=response_object,
@ -1255,6 +1255,8 @@ def test_convert_to_model_response_object_with_error_code_only():
convert_tool_call_to_json_mode=False,
)
assert exc_info.value.status_code == 500
def test_model_prefix_preservation():
"""
@ -2473,14 +2475,14 @@ class TestConvertToModelResponseObjectCompletion:
assert "reasoning_content" not in (message.provider_specific_fields or {})
def test_response_none_raises(self):
with pytest.raises(Exception):
with pytest.raises(Exception, match="Invalid response object"):
convert_to_model_response_object(
response_object=None,
model_response_object=ModelResponse(),
)
def test_model_response_none_raises(self):
with pytest.raises(Exception):
with pytest.raises(Exception, match="Invalid response object"):
convert_to_model_response_object(
response_object={
"choices": [

View file

@ -1458,7 +1458,7 @@ def test_responses_gpt54_with_xhigh_reasoning():
# Stop execution right after request generation to avoid external API calls.
mock_responses.side_effect = RuntimeError("stop_after_request_build")
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
litellm.completion(
model="openai/responses/gpt-5.4",
messages=[{"role": "user", "content": "What is 2+2?"}],

View file

@ -569,5 +569,5 @@ class TestClaudeModelPatternMatching:
)
set_fallback_generalizations([])
with pytest.raises(Exception):
with pytest.raises(litellm.BadRequestError):
litellm.get_llm_provider(model="claude-opus-4-9")

View file

@ -1,5 +1,5 @@
import httpx
from openai import OpenAI, BadRequestError
from openai import OpenAI, BadRequestError, APIStatusError
import pytest
@ -87,7 +87,7 @@ def test_basic_response():
print("DELETE response=", delete_response)
# expect an error when getting the response again since it was deleted
with pytest.raises(Exception):
with pytest.raises(APIStatusError):
get_response = client.responses.retrieve(response.id)
@ -195,6 +195,6 @@ def test_cancel_streaming_response():
def test_cancel_invalid_response_id():
client = get_test_client()
with pytest.raises(Exception):
with pytest.raises(APIStatusError):
# Try to cancel a non-existent response ID
client.responses.cancel("invalid_response_id_12345")

View file

@ -330,6 +330,7 @@ async def test_wildcard_access_after_cost_map_reload(key_models, model, expect_t
Fix: each reload now calls litellm.add_known_models(model_cost_map=new_map)
with the fetched map passed explicitly to avoid any reference ambiguity.
"""
from litellm.proxy._types import ProxyException
from litellm.proxy.auth.auth_checks import can_key_call_model
# Build a new cost map that includes the brand-new model — exactly what
@ -378,7 +379,7 @@ async def test_wildcard_access_after_cost_map_reload(key_models, model, expect_t
llm_router=router,
)
else:
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await can_key_call_model(
model=model,
llm_model_list=llm_model_list,

View file

@ -41,6 +41,7 @@ from litellm.proxy.auth.handle_jwt import JWTHandler, JWTAuthManager
from litellm.proxy.management_endpoints.team_endpoints import new_team
from litellm.proxy.proxy_server import chat_completion
from typing import Literal, Optional
from litellm.proxy._types import ProxyException
public_key = {
"kty": "RSA",
@ -1045,9 +1046,7 @@ async def test_allow_access_by_email(
assert result is not None # Adjust this based on your actual response check
else:
# Expect the call to fail
with pytest.raises(
Exception
): # Replace with the actual exception raised on failure
with pytest.raises(ProxyException):
resp = await user_api_key_auth(request=request, api_key=bearer_token)
print(resp)

View file

@ -53,7 +53,7 @@ async def test_read_config_from_bad_file_path():
"""
proxy_config_instance = ProxyConfig()
config_path = "non-existent-file.yaml"
with pytest.raises(Exception):
with pytest.raises(Exception, match="Config file not found"):
config = await proxy_config_instance.get_config(config_file_path=config_path)

View file

@ -29,6 +29,7 @@ from litellm.proxy.litellm_pre_call_utils import (
_get_dynamic_logging_metadata,
add_litellm_data_to_request,
)
from pydantic import ValidationError
pytestmark = pytest.mark.xdist_group("proxy_heavy")
@ -1695,13 +1696,13 @@ def test_update_key_request_validation():
"""
from litellm.proxy._types import UpdateKeyRequest
with pytest.raises(Exception):
with pytest.raises(ValidationError):
UpdateKeyRequest(
key="test_key",
temp_budget_increase=100,
)
with pytest.raises(Exception):
with pytest.raises(ValidationError):
UpdateKeyRequest(
key="test_key",
temp_budget_expiry="2024-01-20T00:00:00Z",
@ -1848,7 +1849,7 @@ async def test_end_user_transactions_reset():
mock_client.db.tx = AsyncMock(side_effect=Exception("DB Error"))
# Call function - should raise error
with pytest.raises(Exception):
with pytest.raises(TypeError):
await ProxyUpdateSpend.update_end_user_spend(
n_retry_times=0,
prisma_client=mock_client,
@ -1878,7 +1879,7 @@ async def test_spend_logs_cleanup_after_error():
original_logs = mock_client.spend_log_transactions.copy()
# Call function - should raise error
with pytest.raises(Exception):
with pytest.raises(TypeError):
await ProxyUpdateSpend.update_spend_logs(
n_retry_times=0,
prisma_client=mock_client,

View file

@ -26,6 +26,7 @@ from litellm.proxy import proxy_server
from litellm.proxy._types import UserAPIKeyAuth
from litellm.proxy.utils import PrismaClient, ProxyLogging
from litellm.types.utils import LlmProviders
import openai
proxy_logging_obj = ProxyLogging(user_api_key_cache=DualCache())
@ -254,7 +255,7 @@ async def test_delete_skill_sdk(prisma_client):
assert result.type == "skill_deleted"
# Verify skill no longer exists
with pytest.raises(Exception):
with pytest.raises(openai.APIError):
await aget_skill(
skill_id=created_skill.id,
custom_llm_provider=LlmProviders.LITELLM_PROXY.value,

View file

@ -436,7 +436,7 @@ def test_ui_token_route_access(route, user_role, should_be_allowed):
)
assert result is True
else:
with pytest.raises(Exception):
with pytest.raises(Exception, match="Only proxy admin can be used to generate"):
_is_api_route_allowed(
route=route,
request=request,

View file

@ -520,13 +520,15 @@ async def test_circuit_breaker_covers_lua_script_execution(redis_no_ping):
counted toward taking Redis out of the pool and kept paying a full socket timeout
each, which is the traffic the outage hurts most.
"""
from redis.exceptions import ConnectionError as RedisConnectionError
from litellm.constants import REDIS_CIRCUIT_BREAKER_FAILURE_THRESHOLD
cache = RedisCache(host="127.0.0.1", port=_closed_port(), socket_timeout=0.5)
run_script = cache.async_register_script("return 1")
for _ in range(REDIS_CIRCUIT_BREAKER_FAILURE_THRESHOLD):
with pytest.raises(Exception):
with pytest.raises(RedisConnectionError):
await run_script(keys=["lit4930"], args=[1])
with pytest.raises(Exception, match="circuit breaker is open"):
@ -603,8 +605,11 @@ async def test_only_connectivity_failures_open_the_breaker(error, opens_breaker)
async def failing_call():
raise raised
for _ in range(breaker.failure_threshold + 1):
with pytest.raises(Exception):
for _ in range(breaker.failure_threshold):
with pytest.raises(type(raised)):
await _run_under_circuit_breaker(breaker, "op", failing_call)
with pytest.raises(Exception, match="circuit breaker is open" if opens_breaker else "boom"):
await _run_under_circuit_breaker(breaker, "op", failing_call)
assert breaker.is_open() is opens_breaker

View file

@ -384,7 +384,7 @@ class TestContainerAPI:
"container_create_handler",
side_effect=Exception("API Error"),
):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
create_container(
name="Error Test Container", custom_llm_provider="openai"
)

View file

@ -314,7 +314,7 @@ class TestAsyncErrorWrapping:
handler.create_agent.side_effect = RuntimeError("kaboom")
with patch(_HANDLER_PATH, handler):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await acreate(name="waverunner", api_key="AIza")
@pytest.mark.asyncio
@ -323,7 +323,7 @@ class TestAsyncErrorWrapping:
handler.get_agent.side_effect = RuntimeError("kaboom")
with patch(_HANDLER_PATH, handler):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await aget(name="waverunner", api_key="AIza")
@pytest.mark.asyncio
@ -332,7 +332,7 @@ class TestAsyncErrorWrapping:
handler.list_agents.side_effect = RuntimeError("kaboom")
with patch(_HANDLER_PATH, handler):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await alist(api_key="AIza")
@pytest.mark.asyncio
@ -341,7 +341,7 @@ class TestAsyncErrorWrapping:
handler.delete_agent.side_effect = RuntimeError("kaboom")
with patch(_HANDLER_PATH, handler):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await adelete(name="waverunner", api_key="AIza")
@pytest.mark.asyncio
@ -350,5 +350,5 @@ class TestAsyncErrorWrapping:
handler.list_agent_versions.side_effect = RuntimeError("kaboom")
with patch(_HANDLER_PATH, handler):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await alist_versions(name="waverunner", api_key="AIza")

View file

@ -18,6 +18,7 @@ sys.path.insert(0, os.path.abspath("../../.."))
import litellm
import litellm.interactions as interactions
import openai
# Test API key - should be set in environment
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
@ -258,7 +259,7 @@ class TestGoogleInteractionsErrorHandling:
def test_invalid_model(self, api_key):
"""Test error handling for invalid model."""
with pytest.raises(Exception):
with pytest.raises(openai.APIError):
interactions.create(
model="gemini/invalid-model-name-xyz",
input="Hello",
@ -267,7 +268,7 @@ class TestGoogleInteractionsErrorHandling:
def test_missing_model_and_agent(self, api_key):
"""Test error when neither model nor agent is provided."""
with pytest.raises(Exception): # Can be ValueError or APIConnectionError
with pytest.raises((ValueError, litellm.APIConnectionError)):
interactions.create(
input="Hello",
api_key=api_key,

View file

@ -288,7 +288,7 @@ def test_capability_info_backfills_requested_provider(restore_generalizations):
def test_routing_only_match_does_not_resolve_model_info(restore_generalizations):
restore_generalizations([{"name": "route", "pattern": r"^ceeco-", "model_info": {"litellm_provider": "openai"}}])
litellm.get_model_info.cache_clear()
with pytest.raises(Exception):
with pytest.raises(Exception, match="This model isn't mapped yet"):
litellm.get_model_info("ceeco-fast-1", custom_llm_provider="openai")
@ -470,7 +470,7 @@ def test_shipped_adaptive_rule_requires_claude_prefix(shipped_cost_map):
model = "openai/team-sonnet-5-1-alias"
assert model not in litellm.model_cost
assert match_capability_generalizations("team-sonnet-5-1-alias") is None
with pytest.raises(Exception):
with pytest.raises(Exception, match="This model isn't mapped yet"):
litellm.get_model_info(model)
@ -496,7 +496,7 @@ def test_shipped_rules_lose_to_exact_entries_across_cost_ladder_variants(shipped
from litellm.types.utils import ModelResponse, Usage
assert "claude-haiku-4-5-20251001" in litellm.model_cost
with pytest.raises(Exception):
with pytest.raises(Exception, match="This model isn't mapped yet"):
litellm.get_model_info("claude-haiku-4-5-20251001", custom_llm_provider="bedrock")
entry = litellm.model_cost["us.anthropic.claude-haiku-4-5-20251001-v1:0"]

View file

@ -62,7 +62,7 @@ def test_realtime_streaming_store_message():
# Test 3: Invalid message format
invalid_msg = "invalid json"
with pytest.raises(Exception):
with pytest.raises(json.JSONDecodeError):
streaming.store_message(invalid_msg)
# Test 4: Message type not in logged events

View file

@ -4176,7 +4176,7 @@ async def test_stream_wrapper_anext_max_duration_timeout_restores_consumer_corre
wrapper._stream_created_time = time.time() - 10
with pytest.raises(Exception):
with pytest.raises(litellm.Timeout):
await wrapper.__anext__()
assert trace_id_var.get() == "outer-trace-max-duration"
@ -4323,7 +4323,9 @@ def test_handle_stream_fallback_error_restores_context_only_after_exception_mapp
monkeypatch.setattr("litellm.litellm_core_utils.streaming_handler.exception_type", fake_exception_type)
with pytest.raises(Exception):
from litellm.exceptions import MidStreamFallbackError
with pytest.raises(MidStreamFallbackError):
wrapper._handle_stream_fallback_error(RuntimeError("boom"))
# The mapper ran while the stream's own ids were still active.

View file

@ -61,7 +61,7 @@ def test_anthropic_messages_handler_skips_the_gateway_on_recursion():
"litellm.llms.anthropic.experimental_pass_through.messages.mcp_handler.anthropic_messages_with_mcp",
new=AsyncMock(return_value={"routed": True}),
) as routed:
with pytest.raises(Exception):
with pytest.raises(ValueError):
anthropic_messages_handler(
max_tokens=100,
messages=[{"role": "user", "content": "hi"}],
@ -80,7 +80,7 @@ def test_anthropic_messages_handler_leaves_native_tools_alone():
"litellm.llms.anthropic.experimental_pass_through.messages.mcp_handler.anthropic_messages_with_mcp",
new=AsyncMock(return_value={"routed": True}),
) as routed:
with pytest.raises(Exception):
with pytest.raises(ValueError):
anthropic_messages_handler(
max_tokens=100,
messages=[{"role": "user", "content": "hi"}],

View file

@ -19,6 +19,7 @@ from litellm.types.videos.main import (
VideoCreateOptionalRequestParams,
)
from litellm.types.router import GenericLiteLLMParams
from pydantic import ValidationError
class TestAzureVideoConfig:
@ -299,7 +300,7 @@ class TestAzureVideoConfig:
logging_obj = MagicMock()
# Test that error responses raise exceptions
with pytest.raises(Exception):
with pytest.raises(ValidationError):
self.config.transform_video_create_response(
model=self.model, raw_response=mock_response, logging_obj=logging_obj
)

View file

@ -270,7 +270,7 @@ async def test_asearch_does_not_leak_server_key_to_caller_api_base(
new_callable=AsyncMock,
) as mock_get,
):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await litellm.asearch(
query="secrets",
search_provider="serper",
@ -319,7 +319,7 @@ async def test_query_param_key_not_leaked_with_dummy_caller_key(
"litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.get",
fake_get,
):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
await litellm.asearch(
query="secrets",
search_provider=provider,

View file

@ -1077,7 +1077,7 @@ async def test_session_closed_retry_does_not_close_concurrent_replacement():
raise StopAsyncIteration("stop after retry dispatch")
with patch.object(transport, "_make_aiohttp_request", side_effect=fake_make_request):
with pytest.raises(Exception):
with pytest.raises(StopAsyncIteration):
await transport.handle_async_request(httpx.Request("GET", "http://example.com"))
try:

View file

@ -866,7 +866,7 @@ class TestGithubCopilotTransformResponse:
)
model_response = ModelResponse()
with pytest.raises(Exception):
with pytest.raises(json.JSONDecodeError):
config.transform_response(
model="github_copilot/claude-opus-4.7",
raw_response=raw_response,

View file

@ -232,7 +232,7 @@ def test_huggingface_rerank_error_handling(mock_post):
mock_response.text = "Unauthorized"
mock_post.return_value = mock_response
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
litellm.rerank(
model="huggingface/BAAI/bge-reranker-base",
query="hello",

View file

@ -233,7 +233,7 @@ def test_langflow_extra_body_cannot_inject_tweaks_into_run_payload():
return resp
with patch.object(HTTPHandler, "post", side_effect=fake_post):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
litellm.completion(
model="langflow/my-flow",
messages=[{"role": "user", "content": "hello"}],

View file

@ -40,6 +40,7 @@ from litellm.llms.vertex_ai.files.transformation import (
_openai_batch_jsonl_entry_to_vertex_rows,
)
from litellm.types.llms.openai import CreateFileRequest
from litellm.llms.vertex_ai.common_utils import VertexAIError
def _upload_stream(transformed) -> BaseFileUploadStream:
@ -561,7 +562,7 @@ class TestStreamingMediaUpload:
async def test_failed_upload_raises(self):
raw = _make_openai_jsonl_bytes(80)
with pytest.raises(Exception):
with pytest.raises(VertexAIError):
await self._run(raw, status=403)
async def test_request_timeout_is_forwarded(self):

View file

@ -556,7 +556,7 @@ def test_get_llm_provider_uses_single_xai_provider(monkeypatch):
def test_xai_oauth_alias_is_not_a_provider():
with pytest.raises(Exception):
with pytest.raises(litellm.BadRequestError):
get_llm_provider("xai_oauth/grok-4")

View file

@ -39,6 +39,7 @@ from litellm.models.verification_token import (
LiteLLM_DeletedVerificationToken,
LiteLLM_VerificationToken,
)
from pydantic import ValidationError
class TestBudget:
@ -421,7 +422,7 @@ class TestBudgetTableFull:
assert budget.max_budget == 10.0
def test_full_requires_created_at(self):
with pytest.raises(Exception):
with pytest.raises(ValidationError):
LiteLLM_BudgetTableFull(budget_id="b1")
@ -480,7 +481,7 @@ class TestMCPServerTable:
assert server.env == {}
def test_mcp_server_requires_transport(self):
with pytest.raises(Exception):
with pytest.raises(ValidationError):
LiteLLM_MCPServerTable(server_id="s1")
@ -538,7 +539,7 @@ class TestManagedTables:
assert table.flat_model_file_ids == ["file-abc"]
def test_managed_object_table_requires_purpose(self):
with pytest.raises(Exception):
with pytest.raises(ValidationError):
LiteLLM_ManagedObjectTable(
unified_object_id="o1", model_object_id="m1", file_object={}
)

View file

@ -4440,7 +4440,7 @@ async def test_call_mcp_tool_logs_failure_via_post_call_failure_hook():
proxy_logging_mock,
),
):
with pytest.raises(Exception):
with pytest.raises(Exception, match="boom"):
await call_mcp_tool(
name="test_server-any_tool",
arguments={"x": 1},

View file

@ -2809,7 +2809,7 @@ def test_team_update_gate_rejects_without_org_context():
request.method = "POST"
request.query_params = {}
with pytest.raises(Exception):
with pytest.raises(Exception, match="Only proxy admin can be used to generate"):
RouteChecks.non_proxy_admin_allowed_routes_check(
user_obj=user_obj,
_user_role=LitellmUserRoles.INTERNAL_USER.value,
@ -2829,7 +2829,7 @@ def test_team_update_gate_rejects_cross_org_admin_with_resolved_org():
request.method = "POST"
request.query_params = {}
with pytest.raises(Exception):
with pytest.raises(Exception, match="Only proxy admin can be used to generate"):
RouteChecks.non_proxy_admin_allowed_routes_check(
user_obj=user_obj,
_user_role=LitellmUserRoles.INTERNAL_USER.value,
@ -2951,7 +2951,7 @@ def test_patch_team_gate_rejects_regular_internal_user():
)
valid_token = UserAPIKeyAuth(user_id="regular-user", user_role=LitellmUserRoles.INTERNAL_USER.value)
with pytest.raises(Exception):
with pytest.raises(Exception, match="Only proxy admin can be used to generate"):
RouteChecks.non_proxy_admin_allowed_routes_check(
user_obj=user_obj,
_user_role=LitellmUserRoles.INTERNAL_USER.value,
@ -2967,7 +2967,7 @@ def test_patch_team_gate_rejects_cross_org_admin():
user_obj = _make_org_admin_user("org-1")
valid_token = UserAPIKeyAuth(user_id="org-admin-user", user_role=LitellmUserRoles.INTERNAL_USER.value)
with pytest.raises(Exception):
with pytest.raises(Exception, match="Only proxy admin can be used to generate"):
RouteChecks.non_proxy_admin_allowed_routes_check(
user_obj=user_obj,
_user_role=LitellmUserRoles.INTERNAL_USER.value,
@ -2987,7 +2987,7 @@ def test_patch_team_gate_rejects_view_only_admin():
)
valid_token = UserAPIKeyAuth(user_id="viewer", user_role=LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY.value)
with pytest.raises(Exception):
with pytest.raises(HTTPException):
RouteChecks.non_proxy_admin_allowed_routes_check(
user_obj=user_obj,
_user_role=LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY.value,

View file

@ -979,7 +979,7 @@ async def test_create__exception_calls_failure_hook(harness, openai_env_creds):
)
harness.litellm_acreate.side_effect = ValueError("provider boom")
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await call_create(harness)
harness.logging.post_call_failure_hook.assert_called_once()
@ -1437,7 +1437,7 @@ async def test_retrieve__uses_aretrieve_batch_route_type(retrieve_harness, opena
async def test_retrieve__exception_calls_failure_hook(retrieve_harness, openai_env_creds):
retrieve_harness.litellm_aretrieve.side_effect = ValueError("provider boom")
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await call_retrieve(retrieve_harness, "batch-raw-xyz")
retrieve_harness.logging.post_call_failure_hook.assert_called_once()
@ -1844,7 +1844,7 @@ async def test_list__uses_alist_batches_route_type(list_harness):
async def test_list__exception_calls_failure_hook(list_harness):
list_harness.litellm_alist.side_effect = ValueError("provider boom")
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await call_list(list_harness)
list_harness.logging.post_call_failure_hook.assert_called_once()
@ -2233,7 +2233,7 @@ async def test_cancel__uses_acancel_batch_route_type(cancel_harness, openai_env_
async def test_cancel__exception_calls_failure_hook(cancel_harness, openai_env_creds):
cancel_harness.litellm_acancel.side_effect = ValueError("provider boom")
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await call_cancel(cancel_harness, "batch-raw-xyz")
cancel_harness.logging.post_call_failure_hook.assert_called_once()

View file

@ -507,7 +507,7 @@ async def test_engine_confirmed_dead_persists_across_failed_heavy_reconnect(
client._reap_all_zombies = MagicMock()
with patch.dict(os.environ, {"DATABASE_URL": "postgresql://test"}):
with pytest.raises(Exception):
with pytest.raises(RuntimeError):
await client._run_reconnect_cycle(timeout_seconds=5.0)
# The flag must STILL be True so the next attempt re-enters the heavy

View file

@ -2113,7 +2113,7 @@ async def test_make_bedrock_api_request_forwards_guardrail_action():
):
mock_post.return_value = mock_bedrock_response
with pytest.raises(Exception):
with pytest.raises(Exception, match="blocked"):
await guardrail.make_bedrock_api_request(
source="INPUT",
messages=request_data["messages"],

View file

@ -22,6 +22,7 @@ from litellm.proxy.guardrails.guardrail_hooks.presidio import (
from litellm.exceptions import GuardrailRaisedException
from litellm.types.guardrails import LitellmParams, PiiAction, PiiEntityType
from litellm.types.utils import Choices, Message, ModelResponse
from litellm.exceptions import BlockedPiiEntityError
def _make_mock_session_iterator(
@ -1345,7 +1346,7 @@ def test_blocking_respects_threshold_filter():
{"entity_type": PiiEntityType.CREDIT_CARD, "score": 0.95, "start": 0, "end": 4}
]
filtered_high = guardrail.filter_analyze_results_by_score(high_score_results)
with pytest.raises(Exception):
with pytest.raises(BlockedPiiEntityError):
guardrail.raise_exception_if_blocked_entities_detected(filtered_high)

View file

@ -53,6 +53,7 @@ from litellm.types.proxy.management_endpoints.scim_v2 import (
SCIMUserGroup,
SCIMUserName,
)
from litellm.proxy._types import ProxyException
@pytest.mark.asyncio
@ -3216,7 +3217,7 @@ async def test_delete_user_surfaces_prune_failure_and_keeps_user(mocker):
AsyncMock(side_effect=Exception("database connection lost")),
)
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await delete_user(user_id=user_id)
mock_prisma_client.db.litellm_usertable.delete.assert_not_awaited()

View file

@ -668,6 +668,8 @@ def test_validate_sort_params():
"""
Test that validate_sort_params returns None if sort_by is None
"""
from fastapi import HTTPException
from litellm.proxy.management_endpoints.internal_user_endpoints import (
_validate_sort_params,
)
@ -676,7 +678,7 @@ def test_validate_sort_params():
assert _validate_sort_params(None, "desc") is None
assert _validate_sort_params("user_id", "asc") == {"user_id": "asc"}
assert _validate_sort_params("user_id", "desc") == {"user_id": "desc"}
with pytest.raises(Exception):
with pytest.raises(HTTPException):
_validate_sort_params("user_id", "invalid")

View file

@ -22,6 +22,7 @@ from litellm.proxy.management_helpers.team_metadata_validation import (
run_team_metadata_validation,
validate_team_metadata_if_configured,
)
from pydantic import ValidationError
def _registry_with(validator):
@ -634,7 +635,7 @@ def test_parse_schema_round_trips_fields_in_order():
],
)
def test_parse_schema_malformed_raises(raw):
with pytest.raises(Exception):
with pytest.raises(ValidationError):
parse_team_metadata_schema(raw)

View file

@ -350,7 +350,7 @@ async def test_pass_through_request_failure_handler():
mock_user_api_key_dict = MagicMock()
# Call the function with a target that will trigger an HTTPError
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await pass_through_request(
request=mock_request,
target="http://test.com",
@ -1154,7 +1154,7 @@ async def test_pass_through_request_uses_resolved_timeout():
mock_user_api_key_dict = MagicMock()
with pytest.raises(Exception):
with pytest.raises(TypeError):
await pass_through_request(
request=mock_request,
target="http://test.com",

View file

@ -18,6 +18,7 @@ from litellm.integrations.custom_guardrail import (
CustomGuardrail,
ModifyResponseException,
)
from litellm.proxy._types import ProxyException
_PT_MOD = "litellm.proxy.pass_through_endpoints.pass_through_endpoints"
_COLLECT = "litellm.proxy.pass_through_endpoints.passthrough_guardrails.PassthroughGuardrailHandler.collect_guardrails"
@ -251,7 +252,7 @@ class TestPassthroughPostCallGuardrails:
)
with _common_patches(mock_proxy_logging, mock_response):
with pytest.raises(Exception):
with pytest.raises(ProxyException):
await pass_through_request(
request=_make_mock_request(),
target="https://example.com/v1/generateContent",

View file

@ -28,6 +28,7 @@ from litellm.proxy.proxy_server import (
)
from .conftest import normalize
from pydantic import ValidationError
# ---------------------------------------------------------------------------
# _is_remote_module_url
@ -393,7 +394,7 @@ def test_ProxyConfig__load_yaml_file_returns_parsed_dict(tmp_path):
def test_ProxyConfig__load_yaml_file_raises_on_missing_file():
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(Exception, match="Error loading yaml file"):
pc._load_yaml_file("/no/such/file.yaml")
@ -418,7 +419,7 @@ async def test_ProxyConfig__get_config_from_file_loads_yaml(tmp_path):
@pytest.mark.asyncio
async def test_ProxyConfig__get_config_from_file_missing_path_raises():
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(Exception, match="Config file not found"):
await pc._get_config_from_file(config_file_path="/no/such/file.yaml")
@ -476,7 +477,7 @@ async def test_ProxyConfig_save_config_invalid_path_raises(monkeypatch):
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", False)
monkeypatch.setattr("litellm.proxy.proxy_server.general_settings", {})
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(FileNotFoundError):
await pc.save_config({"x": 1})
@ -641,7 +642,7 @@ def test_ProxyConfig__get_team_config_returns_match():
def test_ProxyConfig__get_team_config_missing_team_id_raises():
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(Exception, match="team_id missing from team"):
pc._get_team_config(team_id="t1", all_teams_config=[{"no_id_field": True}])
@ -671,7 +672,7 @@ def test_ProxyConfig_load_team_config_no_settings_returns_empty():
assert out == {}
# Error-style: a misconfigured team list without team_id raises.
pc.config = {"litellm_settings": {"default_team_settings": [{"no_id": True}]}}
with pytest.raises(Exception):
with pytest.raises(Exception, match="team_id missing from team"):
pc.load_team_config(team_id="anything")
@ -698,7 +699,7 @@ def test_ProxyConfig__init_cache_sets_litellm_cache(monkeypatch):
def test_ProxyConfig__init_cache_invalid_params_raises():
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(AttributeError):
pc._init_cache(cache_params={"type": "this-cache-type-does-not-exist"})
@ -765,7 +766,7 @@ async def test_ProxyConfig_get_config_missing_file_raises(monkeypatch):
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", False)
monkeypatch.delenv("LITELLM_CONFIG_BUCKET_NAME", raising=False)
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(Exception, match="Config file not found"):
await pc.get_config(config_file_path="/no/such/path.yaml")
@ -1041,7 +1042,7 @@ def test_ProxyConfig_load_credential_list_returns_items():
def test_ProxyConfig_load_credential_list_invalid_entry_raises():
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(ValidationError):
pc.load_credential_list({"credential_list": [{"missing_required": True}]})
@ -1381,7 +1382,7 @@ async def test_ProxyConfig_load_config_missing_file_raises(monkeypatch):
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", False)
monkeypatch.delenv("LITELLM_CONFIG_BUCKET_NAME", raising=False)
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(Exception, match="Config file not found"):
await pc.load_config(router=None, config_file_path="/no/file.yaml")
@ -1492,7 +1493,7 @@ async def test_ProxyConfig__init_non_llm_configs_empty_config():
async def test_ProxyConfig__init_non_llm_configs_premium_invalid_worker_registry_raises(monkeypatch):
monkeypatch.setattr("litellm.proxy.proxy_server.premium_user", True)
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(ValidationError):
await pc._init_non_llm_configs(
config={"worker_registry": [{"totally": "invalid"}]},
config_file_path=None,
@ -1572,7 +1573,7 @@ async def test_ProxyConfig__init_policy_engine_none_config_noop():
# None config returns early without raising.
await pc._init_policy_engine(config=None, prisma_client=None, llm_router=None)
# Error-style: invalid policies value should raise.
with pytest.raises(Exception):
with pytest.raises(AttributeError):
await pc._init_policy_engine(
config={"policies": "not-a-list"},
prisma_client=None,
@ -1601,7 +1602,7 @@ def test_ProxyConfig__load_alerting_settings_noop_when_no_alerting():
def test_ProxyConfig__load_alerting_settings_invalid_alerting_raises():
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(RuntimeError):
# alerting must be iterable — int triggers an error.
pc._load_alerting_settings({"alerting": 12345})
@ -1823,7 +1824,7 @@ async def test_ProxyConfig__delete_deployment_invalid_models_raises(monkeypatch)
fake_router.get_model_ids = MagicMock(return_value=[])
monkeypatch.setattr("litellm.proxy.proxy_server.llm_router", fake_router)
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(AttributeError):
# Non-model objects without expected attrs trigger an error.
await pc._delete_deployment(db_models=[{"not_a_model": True}])
@ -2721,7 +2722,7 @@ async def test_ProxyConfig__update_general_settings_none_input_noop():
result = await pc._update_general_settings(db_general_settings=None)
assert result is None
# Error-style: dict() will fail on non-mapping non-None input.
with pytest.raises(Exception):
with pytest.raises(TypeError):
await pc._update_general_settings(db_general_settings=12345) # type: ignore[arg-type]
@ -2743,7 +2744,7 @@ def test_ProxyConfig__update_config_fields_merges_dict():
def test_ProxyConfig__update_config_fields_invalid_param_raises():
pc = ProxyConfig()
with pytest.raises(Exception):
with pytest.raises(TypeError):
# Missing required arg.
pc._update_config_fields(current_config={}, param_name="general_settings") # type: ignore[call-arg]

View file

@ -1584,7 +1584,7 @@ async def test_prisma_health_check_failure_redacts_database_credentials(caplog):
client._report_health_check_failure = AsyncMock()
with caplog.at_level(logging.WARNING, logger="LiteLLM Proxy"):
with pytest.raises(Exception):
with pytest.raises(Exception, match="could not connect to"):
await PrismaClient.health_check(client)
emitted = [record.getMessage() for record in caplog.records if record.name == "LiteLLM Proxy"]

View file

@ -17,6 +17,7 @@ from litellm.llms.dashscope.image_generation.transformation import (
)
from litellm.types.utils import ImageObject, ImageResponse
from litellm.utils import get_llm_provider
from litellm.llms.base_llm.chat.transformation import BaseLLMException
# ---------------------------------------------------------------------------
@ -247,7 +248,7 @@ class TestDashScopeImageGenerationConfig:
"message": "Size not supported",
}
with pytest.raises(Exception):
with pytest.raises(BaseLLMException):
self.cfg.transform_image_generation_response(
model="qwen-image-2.0",
raw_response=mock_resp,
@ -268,7 +269,7 @@ class TestDashScopeImageGenerationConfig:
"message": "Size not supported",
}
with pytest.raises(Exception):
with pytest.raises(BaseLLMException):
self.cfg.transform_image_generation_response(
model="qwen-image-2.0",
raw_response=mock_resp,

View file

@ -12,6 +12,7 @@ from litellm.litellm_core_utils.get_blog_posts import (
GetBlogPosts,
get_blog_posts,
)
from xml.etree import ElementTree
SAMPLE_RSS = """\
<?xml version="1.0" encoding="UTF-8"?>
@ -71,7 +72,7 @@ def test_parse_rss_to_posts_multiple():
def test_parse_rss_to_posts_invalid_xml():
with pytest.raises(Exception):
with pytest.raises(ElementTree.ParseError):
GetBlogPosts.parse_rss_to_posts("not xml")

View file

@ -1,5 +1,6 @@
import pytest
from litellm.proxy._types import NewProjectRequest, UpdateProjectRequest
from pydantic import ValidationError
def test_new_project_request_tags():
@ -21,11 +22,11 @@ def test_update_project_request_tags():
def test_new_project_request_invalid_tags_type():
# tags must be a list — a string should raise a ValidationError
with pytest.raises(Exception):
with pytest.raises(ValidationError):
NewProjectRequest(project_id="test_proj", team_id="team_1", tags="not-a-list")
def test_update_project_request_invalid_tags_type():
# tags must be a list — a string should raise a ValidationError
with pytest.raises(Exception):
with pytest.raises(ValidationError):
UpdateProjectRequest(project_id="test_proj", tags="not-a-list")

View file

@ -234,7 +234,7 @@ class TestRouterFallbackFailureTracebackRedaction:
raise ValueError(f"primary deployment failed api_key={secret}")
except ValueError as original_exception:
with caplog.at_level(logging.DEBUG, logger="LiteLLM Router"):
with pytest.raises(Exception):
with pytest.raises(ValueError):
await router.async_function_with_fallbacks_common_utils(
e=original_exception,
disable_fallbacks=False,

View file

@ -23,6 +23,7 @@ import pytest
sys.path.insert(0, os.path.abspath("../.."))
import litellm # noqa: E402
import openai
ASYNC_INVOKE_ARN = "arn:aws:bedrock:us-west-2:123456789012:async-invoke/abc123def456"
MIJ_ARN = "arn:aws:bedrock:us-west-2:123456789012:model-invocation-job/abc1234567"
@ -134,7 +135,7 @@ def test_unrelated_bedrock_arn_falls_through_to_provider_config(mock_handlers):
# Use a plausible-but-unsupported Bedrock ARN family.
unrelated_arn = "arn:aws:bedrock:us-west-2:123456789012:provisioned-model/xyz"
with pytest.raises(Exception):
with pytest.raises(litellm.BadRequestError):
# Will raise because no provider_config exists for this path —
# that's fine, we just need to assert neither bedrock handler ran
# before the failure.
@ -152,7 +153,7 @@ def test_non_bedrock_id_skips_bedrock_dispatch_entirely(mock_handlers):
block they belong to other providers' retrieve flows."""
async_invoke, mij, _ = mock_handlers
with pytest.raises(Exception):
with pytest.raises(openai.OpenAIError):
litellm.retrieve_batch(
batch_id="batch_abc123",
custom_llm_provider="openai",

View file

@ -367,7 +367,7 @@ async def test_arouter_with_tags_and_fallbacks():
enable_tag_filtering=True,
)
with pytest.raises(Exception):
with pytest.raises(litellm.InternalServerError):
response = await router.acompletion(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Hello, world!"}],
@ -5707,7 +5707,7 @@ async def test_team_scoped_model_fallback_cross_team_blocked():
fallbacks=[{"primary-model": ["fallback-model"]}],
)
with pytest.raises(Exception):
with pytest.raises(litellm.InternalServerError):
await router.acompletion(
model="primary-model",
messages=[{"role": "user", "content": "Hello"}],

View file

@ -391,7 +391,7 @@ async def test_no_failover_when_flag_off():
# enable_weighted_failover defaults to False
)
with pytest.raises(Exception):
with pytest.raises(litellm.InternalServerError):
await router.acompletion(
model="test-model",
messages=[{"role": "user", "content": "hi"}],
@ -515,7 +515,7 @@ async def test_failover_exhausted_raises_original_error_class():
enable_weighted_failover=True,
)
with pytest.raises(Exception):
with pytest.raises(litellm.InternalServerError):
await router.acompletion(
model="test-model",
messages=[{"role": "user", "content": "hi"}],
@ -648,7 +648,7 @@ async def test_failover_skipped_for_non_simple_shuffle():
enable_weighted_failover=True,
)
with pytest.raises(Exception):
with pytest.raises(litellm.InternalServerError):
await router.acompletion(
model="test-model",
messages=[{"role": "user", "content": "hi"}],

View file

@ -151,7 +151,7 @@ class TestVideoGeneration:
"video_generation_handler",
side_effect=Exception("API Error"),
):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
video_generation(prompt="Test video", model="sora-2")
def test_video_generation_provider_config(self):
@ -739,7 +739,7 @@ class TestVideoGeneration:
"video_status_handler",
side_effect=Exception("API Error"),
):
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
video_status(video_id="test_video_id", model="sora-2")
def test_video_status_request_transformation(self):

View file

@ -321,7 +321,7 @@ def test_get_character__mock_response_short_circuits(seams):
def test_unsupported_provider_raises_without_dispatch(seams):
seams.get_config.return_value = None
with pytest.raises(Exception):
with pytest.raises(litellm.APIConnectionError):
videos_main.video_status(video_id=AZURE_VIDEO_ID)
seams.handler.video_status_handler.assert_not_called()

View file

@ -16,6 +16,7 @@ from tests.vector_store_tests.base_vector_store_test import BaseVectorStoreTest
from litellm.llms.ragflow.vector_stores.transformation import RAGFlowVectorStoreConfig
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.types.vector_stores import VectorStoreCreateOptionalRequestParams
from litellm.llms.base_llm.chat.transformation import BaseLLMException
class TestRAGFlowVectorStore(BaseVectorStoreTest):
@ -233,7 +234,7 @@ class TestRAGFlowVectorStore(BaseVectorStoreTest):
"message": "Dataset name 'test-dataset' already exists",
}
with pytest.raises(Exception): # Should raise BaseLLMException
with pytest.raises(BaseLLMException):
config.transform_create_vector_store_response(mock_response)
def test_transform_create_vector_store_response_missing_id(self):