litellm/tests/local_testing/test_router_pattern_matching.py
Krish Dholakia 1cd1d23fdf
LiteLLM Minor Fixes & Improvements (10/23/2024) (#6407)
* docs(bedrock.md): clarify bedrock auth in litellm docs

* fix(convert_dict_to_response.py): Fixes https://github.com/BerriAI/litellm/issues/6387

* feat(pattern_match_deployments.py): more robust handling for wildcard routes (model_name: custom_route/* -> openai/*)

Enables user to expose custom routes to users with dynamic handling

* test: add more testing

* docs(custom_pricing.md): add debug tutorial for custom pricing

* test: skip codestral test - unreachable backend

* test: fix test

* fix(pattern_matching_deployments.py): fix typing

* test: cleanup codestral tests - backend api unavailable

* (refactor) prometheus async_log_success_event to be under 100 LOC  (#6416)

* unit testig for prometheus

* unit testing for success metrics

* use 1 helper for _increment_token_metrics

* use helper for _increment_remaining_budget_metrics

* use _increment_remaining_budget_metrics

* use _increment_top_level_request_and_spend_metrics

* use helper for _set_latency_metrics

* remove noqa violation

* fix test prometheus

* test prometheus

* unit testing for all prometheus helper functions

* fix prom unit tests

* fix unit tests prometheus

* fix unit test prom

* (refactor) router - use static methods for client init utils  (#6420)

* use InitalizeOpenAISDKClient

* use InitalizeOpenAISDKClient static method

* fix  # noqa: PLR0915

* (code cleanup) remove unused and undocumented logging integrations - litedebugger, berrispend  (#6406)

* code cleanup remove unused and undocumented code files

* fix unused logging integrations cleanup

* bump: version 1.50.3 → 1.50.4

---------

Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
2024-10-24 19:01:41 -07:00

157 lines
4.7 KiB
Python

"""
This tests the pattern matching router
Pattern matching router is used to match patterns like openai/*, vertex_ai/*, anthropic/* etc. (wildcard matching)
"""
import sys, os, time
import traceback, asyncio
import pytest
sys.path.insert(
0, os.path.abspath("../..")
) # Adds the parent directory to the system path
import litellm
from litellm import Router
from litellm.router import Deployment, LiteLLM_Params, ModelInfo
from concurrent.futures import ThreadPoolExecutor
from collections import defaultdict
from dotenv import load_dotenv
load_dotenv()
from litellm.router_utils.pattern_match_deployments import PatternMatchRouter
def test_pattern_match_router_initialization():
router = PatternMatchRouter()
assert router.patterns == {}
def test_add_pattern():
"""
Tests that openai/* is added to the patterns
when we try to get the pattern, it should return the deployment
"""
router = PatternMatchRouter()
deployment = Deployment(
model_name="openai-1",
litellm_params=LiteLLM_Params(model="gpt-3.5-turbo"),
model_info=ModelInfo(),
)
router.add_pattern("openai/*", deployment.to_json(exclude_none=True))
assert len(router.patterns) == 1
assert list(router.patterns.keys())[0] == "openai/(.*)"
# try getting the pattern
assert router.route(request="openai/gpt-15") == [
deployment.to_json(exclude_none=True)
]
def test_add_pattern_vertex_ai():
"""
Tests that vertex_ai/* is added to the patterns
when we try to get the pattern, it should return the deployment
"""
router = PatternMatchRouter()
deployment = Deployment(
model_name="this-can-be-anything",
litellm_params=LiteLLM_Params(model="vertex_ai/gemini-1.5-flash-latest"),
model_info=ModelInfo(),
)
router.add_pattern("vertex_ai/*", deployment.to_json(exclude_none=True))
assert len(router.patterns) == 1
assert list(router.patterns.keys())[0] == "vertex_ai/(.*)"
# try getting the pattern
assert router.route(request="vertex_ai/gemini-1.5-flash-latest") == [
deployment.to_json(exclude_none=True)
]
def test_add_multiple_deployments():
"""
Tests adding multiple deployments for the same pattern
when we try to get the pattern, it should return the deployment
"""
router = PatternMatchRouter()
deployment1 = Deployment(
model_name="openai-1",
litellm_params=LiteLLM_Params(model="gpt-3.5-turbo"),
model_info=ModelInfo(),
)
deployment2 = Deployment(
model_name="openai-2",
litellm_params=LiteLLM_Params(model="gpt-4"),
model_info=ModelInfo(),
)
router.add_pattern("openai/*", deployment1.to_json(exclude_none=True))
router.add_pattern("openai/*", deployment2.to_json(exclude_none=True))
assert len(router.route("openai/gpt-4o")) == 2
def test_pattern_to_regex():
"""
Tests that the pattern is converted to a regex
"""
router = PatternMatchRouter()
assert router._pattern_to_regex("openai/*") == "openai/(.*)"
assert (
router._pattern_to_regex("openai/fo::*::static::*")
== "openai/fo::(.*)::static::(.*)"
)
def test_route_with_none():
"""
Tests that the router returns None when the request is None
"""
router = PatternMatchRouter()
assert router.route(None) is None
def test_route_with_multiple_matching_patterns():
"""
Tests that the router returns the first matching pattern when there are multiple matching patterns
"""
router = PatternMatchRouter()
deployment1 = Deployment(
model_name="openai-1",
litellm_params=LiteLLM_Params(model="gpt-3.5-turbo"),
model_info=ModelInfo(),
)
deployment2 = Deployment(
model_name="openai-2",
litellm_params=LiteLLM_Params(model="gpt-4"),
model_info=ModelInfo(),
)
router.add_pattern("openai/*", deployment1.to_json(exclude_none=True))
router.add_pattern("openai/gpt-*", deployment2.to_json(exclude_none=True))
assert router.route("openai/gpt-3.5-turbo") == [
deployment1.to_json(exclude_none=True)
]
# Add this test to check for exception handling
def test_route_with_exception():
"""
Tests that the router returns None when there is an exception calling router.route()
"""
router = PatternMatchRouter()
deployment = Deployment(
model_name="openai-1",
litellm_params=LiteLLM_Params(model="gpt-3.5-turbo"),
model_info=ModelInfo(),
)
router.add_pattern("openai/*", deployment.to_json(exclude_none=True))
router.patterns = (
[]
) # this will cause router.route to raise an exception, since router.patterns should be a dict
result = router.route("openai/gpt-3.5-turbo")
assert result is None