mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-05 02:41:56 +00:00
Merge cd5d414c13 into 6684256136
This commit is contained in:
commit
b7cd59f7e6
5 changed files with 62 additions and 5 deletions
|
|
@ -38,7 +38,7 @@ RESPONSE_TYPES: Final[dict[str, type]] = {
|
|||
def _load_endpoints_config() -> dict:
|
||||
"""Load the endpoints configuration from JSON file."""
|
||||
config_path: Final = Path(__file__).parent / "endpoints.json"
|
||||
with open(config_path) as f:
|
||||
with open(config_path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ def load_snapshot() -> dict[str, dict] | None:
|
|||
if not SNAPSHOT_FILE.exists():
|
||||
return None
|
||||
try:
|
||||
with SNAPSHOT_FILE.open() as f:
|
||||
with SNAPSHOT_FILE.open(encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except (json.JSONDecodeError, OSError):
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ from litellm.proxy.container_endpoints.ownership import (
|
|||
def _load_endpoints_config() -> dict:
|
||||
"""Load the endpoints configuration from JSON file."""
|
||||
config_path: Final = Path(__file__).parent.parent.parent / "containers" / "endpoints.json"
|
||||
with open(config_path) as f:
|
||||
with open(config_path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5390,7 +5390,7 @@ class ProxyConfig:
|
|||
Load and parse a YAML file
|
||||
"""
|
||||
try:
|
||||
with open(file_path, "r") as file:
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
return yaml.safe_load(file) or {}
|
||||
except Exception as e:
|
||||
raise Exception(f"Error loading yaml file {file_path}: {e}")
|
||||
|
|
@ -5411,7 +5411,7 @@ class ProxyConfig:
|
|||
# Load existing config
|
||||
## Yaml
|
||||
if os.path.exists(f"{file_path}"):
|
||||
with open(f"{file_path}", "r") as config_file:
|
||||
with open(f"{file_path}", "r", encoding="utf-8") as config_file:
|
||||
config = yaml.safe_load(config_file)
|
||||
elif file_path is not None:
|
||||
raise Exception(f"Config file not found: {file_path}")
|
||||
|
|
|
|||
|
|
@ -14211,6 +14211,63 @@ async def test_ptu_rollup_job_not_registered_without_opt_in(monkeypatch):
|
|||
assert len(scheduler.get_jobs()) > 0
|
||||
|
||||
|
||||
CONFIG_WITH_NON_ASCII = """model_list:
|
||||
- model_name: café-gpt
|
||||
litellm_params:
|
||||
model: openai/gpt-4o
|
||||
api_key: sk-test
|
||||
"""
|
||||
|
||||
|
||||
def test_load_yaml_file_reads_non_ascii_config(tmp_path):
|
||||
"""A UTF-8 config decoded with the locale encoding silently yields café-gpt on a cp1252 host,
|
||||
so the wrong model name reaches routing with no error raised."""
|
||||
from litellm.proxy.proxy_server import ProxyConfig
|
||||
|
||||
config_path = tmp_path / "config.yaml"
|
||||
config_path.write_text(CONFIG_WITH_NON_ASCII, encoding="utf-8")
|
||||
|
||||
config = ProxyConfig()._load_yaml_file(str(config_path))
|
||||
|
||||
assert config["model_list"][0]["model_name"] == "café-gpt"
|
||||
|
||||
|
||||
def test_load_yaml_file_reads_config_with_byte_undefined_in_cp1252(tmp_path):
|
||||
"""Cafe plus U+0301 encodes to a 0x81 byte, which cp1252 has no mapping for, so this raised
|
||||
UnicodeDecodeError rather than merely mangling the name."""
|
||||
from litellm.proxy.proxy_server import ProxyConfig
|
||||
|
||||
config_path = tmp_path / "config.yaml"
|
||||
config_path.write_text("model_list:\n - model_name: Café\n", encoding="utf-8")
|
||||
|
||||
config = ProxyConfig()._load_yaml_file(str(config_path))
|
||||
|
||||
assert config["model_list"][0]["model_name"] == "Café"
|
||||
|
||||
|
||||
def test_load_yaml_file_specifies_an_encoding(tmp_path):
|
||||
"""Asserting the decoded value passes on any UTF-8 host regardless of the fix, and CI is Linux.
|
||||
Running the loader under warn_default_encoding fails on every platform instead."""
|
||||
config_path = tmp_path / "config.yaml"
|
||||
config_path.write_text(CONFIG_WITH_NON_ASCII, encoding="utf-8")
|
||||
|
||||
body = (
|
||||
"import warnings\n"
|
||||
"from litellm.proxy.proxy_server import ProxyConfig\n"
|
||||
'warnings.simplefilter("error", EncodingWarning)\n'
|
||||
f'config = ProxyConfig()._load_yaml_file(r"{config_path}")\n'
|
||||
'assert config["model_list"][0]["model_name"] == "caf\u00e9-gpt", config\n'
|
||||
'print("OK")\n'
|
||||
)
|
||||
proc = subprocess.run(
|
||||
[sys.executable, "-X", "warn_default_encoding", "-W", "error::EncodingWarning", "-c", body],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
assert "EncodingWarning" not in proc.stderr, proc.stderr
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
@pytest.mark.asyncio
|
||||
async def test_moderations_reraises_proxy_exception_unwrapped():
|
||||
"""A 400 ProxyException from request validation must surface as-is,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue