mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-13 08:52:02 +00:00
greptile bug fixes
This commit is contained in:
parent
0d7de1c744
commit
80d96628b4
5 changed files with 125 additions and 6 deletions
|
|
@ -587,7 +587,9 @@ def process_callback(
|
|||
|
||||
|
||||
def normalize_callback_names(
|
||||
callbacks: Iterable[Union[str, object]],
|
||||
callbacks: Iterable[Union[str, object]] | None,
|
||||
) -> List[Union[str, object]]:
|
||||
"""Lowercase string callback names; pass through non-strings (e.g. from config) unchanged."""
|
||||
if callbacks is None:
|
||||
return []
|
||||
return [c.lower() if isinstance(c, str) else c for c in callbacks]
|
||||
|
|
|
|||
|
|
@ -3620,9 +3620,13 @@ class ProxyConfig:
|
|||
merged_failure = list(
|
||||
dict.fromkeys(failure_from_settings + (failure_callbacks or []))
|
||||
)
|
||||
merged_callbacks = list(
|
||||
dict.fromkeys(callbacks_from_settings + (callbacks or []))
|
||||
)
|
||||
seen_both = {c if isinstance(c, str) else next(iter(c)) for c in callbacks_from_settings}
|
||||
merged_callbacks: list = list(callbacks_from_settings)
|
||||
for c in (callbacks or []):
|
||||
name = c if isinstance(c, str) else next(iter(c.keys()))
|
||||
if name not in seen_both:
|
||||
merged_callbacks.append(c)
|
||||
seen_both.add(name)
|
||||
|
||||
for success_callback in merged_success:
|
||||
self._add_callback_from_db_to_in_memory_litellm_callbacks(
|
||||
|
|
@ -11666,7 +11670,11 @@ async def get_config(): # noqa: PLR0915
|
|||
(_callback_name, _callback_params), = _callback.items()
|
||||
_callback = _callback_name
|
||||
elif isinstance(_callback, str) and _callback in _callback_settings:
|
||||
_callback_params = _callback_settings.get(_callback)
|
||||
_raw = _callback_settings.get(_callback) or {}
|
||||
_callback_params = (
|
||||
{k: v for k, v in _raw.items() if k not in ("callback_type", "event_types")}
|
||||
or None
|
||||
)
|
||||
_data_to_return.append(
|
||||
process_callback(
|
||||
_callback,
|
||||
|
|
|
|||
|
|
@ -122,6 +122,12 @@ def test_normalize_callback_names_lowercases_strings():
|
|||
assert normalize_callback_names(["SQS", "S3", "CUSTOM_CALLBACK"]) == ["sqs", "s3", "custom_callback"]
|
||||
|
||||
|
||||
def test_normalize_callback_names_none_returns_empty_list():
|
||||
"""None and empty list return [] to support callers that may pass unguarded None."""
|
||||
assert normalize_callback_names(None) == []
|
||||
assert normalize_callback_names([]) == []
|
||||
|
||||
|
||||
def test_remaining_tokens_requests_returns_empty_when_metadata_empty_or_missing():
|
||||
"""Empty or missing metadata returns {}."""
|
||||
assert get_remaining_tokens_and_requests_from_request_data({}) == {}
|
||||
|
|
|
|||
|
|
@ -2985,6 +2985,109 @@ def test_root_redirect_when_docs_url_not_root_and_redirect_url_set(monkeypatch):
|
|||
assert response.headers["location"] == test_redirect_url
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_image_non_root_uses_var_lib_assets_dir(monkeypatch):
|
||||
"""
|
||||
Test that get_image uses /var/lib/litellm/assets when LITELLM_NON_ROOT is true.
|
||||
get_image only calls makedirs when the assets dir does not exist, so we must
|
||||
have exists() return False for that path to trigger the create-dir branch.
|
||||
"""
|
||||
from unittest.mock import patch
|
||||
|
||||
from litellm.proxy.proxy_server import get_image
|
||||
|
||||
# Set LITELLM_NON_ROOT to true
|
||||
monkeypatch.setenv("LITELLM_NON_ROOT", "true")
|
||||
monkeypatch.delenv("UI_LOGO_PATH", raising=False)
|
||||
|
||||
def exists_side_effect(path):
|
||||
# Return False for the assets dir so get_image calls makedirs()
|
||||
if path == "/var/lib/litellm/assets":
|
||||
return False
|
||||
return True
|
||||
|
||||
with patch("litellm.proxy.proxy_server.os.makedirs") as mock_makedirs, \
|
||||
patch("litellm.proxy.proxy_server.os.path.exists", side_effect=exists_side_effect), \
|
||||
patch("litellm.proxy.proxy_server.os.getenv") as mock_getenv, \
|
||||
patch("litellm.proxy.proxy_server.FileResponse") as mock_file_response:
|
||||
|
||||
# Setup mock_getenv to return empty string for UI_LOGO_PATH
|
||||
def getenv_side_effect(key, default=""):
|
||||
if key == "UI_LOGO_PATH":
|
||||
return ""
|
||||
elif key == "LITELLM_NON_ROOT":
|
||||
return "true"
|
||||
return default
|
||||
|
||||
mock_getenv.side_effect = getenv_side_effect
|
||||
|
||||
# Call the function
|
||||
await get_image()
|
||||
|
||||
# Verify makedirs was called with /var/lib/litellm/assets
|
||||
mock_makedirs.assert_called_once_with("/var/lib/litellm/assets", exist_ok=True)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_image_non_root_fallback_to_default_logo(monkeypatch):
|
||||
"""
|
||||
Test that get_image falls back to default_site_logo when logo doesn't exist
|
||||
in /var/lib/litellm/assets for non-root case.
|
||||
get_image only calls makedirs when the assets dir does not exist, so we must
|
||||
have exists() return False for that path to trigger the create-dir branch.
|
||||
"""
|
||||
from unittest.mock import patch
|
||||
|
||||
from litellm.proxy.proxy_server import get_image
|
||||
|
||||
# Set LITELLM_NON_ROOT to true
|
||||
monkeypatch.setenv("LITELLM_NON_ROOT", "true")
|
||||
monkeypatch.delenv("UI_LOGO_PATH", raising=False)
|
||||
|
||||
# Track path.exists calls to verify it checks /var/lib/litellm/assets/logo.jpg
|
||||
exists_calls = []
|
||||
|
||||
def exists_side_effect(path):
|
||||
exists_calls.append(path)
|
||||
# Return False for assets dir so get_image calls makedirs()
|
||||
if path == "/var/lib/litellm/assets":
|
||||
return False
|
||||
# Return False for /var/lib/litellm/assets/logo.jpg to trigger fallback
|
||||
if "/var/lib/litellm/assets/logo.jpg" in path or path == "/var/lib/litellm/assets/logo.jpg":
|
||||
return False
|
||||
return True
|
||||
|
||||
# Mock os.path operations
|
||||
with patch("litellm.proxy.proxy_server.os.makedirs") as mock_makedirs, \
|
||||
patch("litellm.proxy.proxy_server.os.path.exists", side_effect=exists_side_effect), \
|
||||
patch("litellm.proxy.proxy_server.os.getenv") as mock_getenv, \
|
||||
patch("litellm.proxy.proxy_server.FileResponse") as mock_file_response:
|
||||
|
||||
# Setup mock_getenv
|
||||
def getenv_side_effect(key, default=""):
|
||||
if key == "UI_LOGO_PATH":
|
||||
return ""
|
||||
elif key == "LITELLM_NON_ROOT":
|
||||
return "true"
|
||||
return default
|
||||
|
||||
mock_getenv.side_effect = getenv_side_effect
|
||||
|
||||
# Call the function
|
||||
await get_image()
|
||||
|
||||
# Verify makedirs was called with /var/lib/litellm/assets
|
||||
mock_makedirs.assert_called_once_with("/var/lib/litellm/assets", exist_ok=True)
|
||||
|
||||
# Verify that exists was called to check /var/lib/litellm/assets/logo.jpg
|
||||
assets_logo_path = "/var/lib/litellm/assets/logo.jpg"
|
||||
assert any(assets_logo_path in str(call) for call in exists_calls), \
|
||||
f"Should check if {assets_logo_path} exists"
|
||||
|
||||
# Verify FileResponse was called (with fallback logo)
|
||||
assert mock_file_response.called, "FileResponse should be called"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_image_root_case_uses_current_dir(monkeypatch):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ const Settings: React.FC<SettingsPageProps> = ({ accessToken, userRole, userID,
|
|||
setIsAddingCallback(true);
|
||||
}
|
||||
|
||||
const payload = buildCallbackPayload(formValues, callbackName, callbacks, isEdit, undefined, callbackSettings);
|
||||
const payload = buildCallbackPayload(formValues, callbackName, callbacks, isEdit, selectedEditCallback?.type as "success" | "failure" | "success_and_failure" | undefined, callbackSettings);
|
||||
|
||||
try {
|
||||
await setCallbacksCall(accessToken, payload);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue