mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-08 22:21:35 +00:00
test(cost): move off-peak tests beside the related cost tests
They sat at the end of the file, which is where everyone else appends too, so this branch picked up a conflict there on nearly every rebase. Grouping them with the other _get_token_base_cost test keeps them clear of that churn and next to the code they cover. Pure move, no test changes
This commit is contained in:
parent
c813386bb2
commit
d302301a4e
1 changed files with 164 additions and 164 deletions
|
|
@ -410,6 +410,170 @@ def test_get_token_base_cost_picks_highest_crossed_tier():
|
|||
assert prompt_base_cost == 9e-6
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_same_day():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
window = "09:00-17:00"
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 8, 59, tzinfo=timezone.utc)) is False
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 9, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 17, 0, tzinfo=timezone.utc)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_wraps_midnight():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
window = "16:30-00:30"
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 0, 15, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 16, 30, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 0, 30, tzinfo=timezone.utc)) is False
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_multiple_windows():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Providers like DeepSeek V4 have more than one daily peak/off-peak window.
|
||||
windows = ["01:00-05:00", "13:00-16:00"]
|
||||
assert _is_within_off_peak_window(windows, datetime(2026, 1, 1, 3, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(windows, datetime(2026, 1, 1, 14, 30, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(windows, datetime(2026, 1, 1, 9, 0, tzinfo=timezone.utc)) is False
|
||||
# a malformed entry in the list is ignored, valid entries still match
|
||||
assert _is_within_off_peak_window(["bad", "13:00-16:00"], datetime(2026, 1, 1, 14, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window([], datetime(2026, 1, 1, 14, 0, tzinfo=timezone.utc)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_normalizes_timezone_aware_input():
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
# A caller may pass a non-UTC aware datetime; the window is UTC and must be
|
||||
# evaluated in UTC, not against the caller's wall-clock. 09:00 at UTC+8 is
|
||||
# 01:00 UTC, inside the 01:00-05:00 window.
|
||||
tz_plus_8 = timezone(timedelta(hours=8))
|
||||
assert _is_within_off_peak_window("01:00-05:00", datetime(2026, 1, 1, 9, 0, tzinfo=tz_plus_8)) is True
|
||||
assert _is_within_off_peak_window("01:00-05:00", datetime(2026, 1, 1, 12, 0, tzinfo=tz_plus_8)) is True
|
||||
# 06:00 at UTC+8 is 22:00 UTC the previous day, outside the window
|
||||
assert _is_within_off_peak_window("01:00-05:00", datetime(2026, 1, 1, 6, 0, tzinfo=tz_plus_8)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_malformed_returns_false():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
now = datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc)
|
||||
assert _is_within_off_peak_window("not-a-window", now) is False
|
||||
assert _is_within_off_peak_window("16:30", now) is False
|
||||
assert _is_within_off_peak_window("25:00-26:00", now) is False
|
||||
|
||||
|
||||
def test_get_token_base_cost_applies_off_peak_pricing():
|
||||
from datetime import datetime, timezone
|
||||
from typing import cast
|
||||
|
||||
from litellm.types.utils import ModelInfo
|
||||
|
||||
model_info = cast(
|
||||
ModelInfo,
|
||||
{
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"cache_read_input_token_cost": 1e-7,
|
||||
"off_peak_pricing": {
|
||||
"hours_utc": "16:30-00:30",
|
||||
"input_cost_per_token": 5e-7,
|
||||
"output_cost_per_token": 1e-6,
|
||||
"cache_read_input_token_cost": 5e-8,
|
||||
},
|
||||
},
|
||||
)
|
||||
usage = Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150)
|
||||
|
||||
off_peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc))
|
||||
assert off_peak[0] == 5e-7
|
||||
assert off_peak[1] == 1e-6
|
||||
assert off_peak[4] == 5e-8
|
||||
|
||||
peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc))
|
||||
assert peak[0] == 1e-6
|
||||
assert peak[1] == 2e-6
|
||||
assert peak[4] == 1e-7
|
||||
|
||||
|
||||
def test_get_token_base_cost_off_peak_falls_back_to_standard_when_unset():
|
||||
from datetime import datetime, timezone
|
||||
from typing import cast
|
||||
|
||||
from litellm.types.utils import ModelInfo
|
||||
|
||||
model_info = cast(
|
||||
ModelInfo,
|
||||
{
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"off_peak_pricing": {"hours_utc": "16:30-00:30", "input_cost_per_token": 5e-7},
|
||||
},
|
||||
)
|
||||
usage = Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150)
|
||||
|
||||
result = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc))
|
||||
assert result[0] == 5e-7
|
||||
assert result[1] == 2e-6
|
||||
|
||||
|
||||
def test_get_token_base_cost_off_peak_wins_over_threshold():
|
||||
from datetime import datetime, timezone
|
||||
from typing import cast
|
||||
|
||||
from litellm.types.utils import ModelInfo
|
||||
|
||||
model_info = cast(
|
||||
ModelInfo,
|
||||
{
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"input_cost_per_token_above_200k_tokens": 3e-6,
|
||||
"output_cost_per_token_above_200k_tokens": 4e-6,
|
||||
"off_peak_pricing": {
|
||||
"hours_utc": "16:30-00:30",
|
||||
"input_cost_per_token": 5e-7,
|
||||
"output_cost_per_token": 1e-6,
|
||||
},
|
||||
},
|
||||
)
|
||||
usage = Usage(prompt_tokens=250000, completion_tokens=250000, total_tokens=500000)
|
||||
|
||||
off_peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc))
|
||||
assert off_peak[0] == 5e-7
|
||||
assert off_peak[1] == 1e-6
|
||||
|
||||
peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc))
|
||||
assert peak[0] == 3e-6
|
||||
assert peak[1] == 4e-6
|
||||
|
||||
|
||||
def test_get_model_info_propagates_off_peak_fields():
|
||||
model_name = "test-off-peak-model"
|
||||
off_peak_pricing = {
|
||||
"hours_utc": "16:30-00:30",
|
||||
"input_cost_per_token": 5e-7,
|
||||
"output_cost_per_token": 1e-6,
|
||||
"cache_read_input_token_cost": 5e-8,
|
||||
}
|
||||
litellm.register_model(
|
||||
{
|
||||
model_name: {
|
||||
"litellm_provider": "openai",
|
||||
"mode": "chat",
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"off_peak_pricing": off_peak_pricing,
|
||||
}
|
||||
}
|
||||
)
|
||||
info = litellm.get_model_info(model=model_name)
|
||||
assert info["off_peak_pricing"] == off_peak_pricing
|
||||
|
||||
|
||||
def test_generic_cost_per_token_gpt54_above_272k_tokens(_local_model_cost_map):
|
||||
"""GPT-5.4/5.4-pro: prompts >272K input tokens priced at 2x input, 1.5x output."""
|
||||
model = "gpt-5.4"
|
||||
|
|
@ -3947,167 +4111,3 @@ def test_route_image_generation_cost_falls_back_to_requested_size(monkeypatch, r
|
|||
)
|
||||
|
||||
assert cost == expected_cost
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_same_day():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
window = "09:00-17:00"
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 8, 59, tzinfo=timezone.utc)) is False
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 9, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 17, 0, tzinfo=timezone.utc)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_wraps_midnight():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
window = "16:30-00:30"
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 0, 15, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 16, 30, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 0, 30, tzinfo=timezone.utc)) is False
|
||||
assert _is_within_off_peak_window(window, datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_multiple_windows():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Providers like DeepSeek V4 have more than one daily peak/off-peak window.
|
||||
windows = ["01:00-05:00", "13:00-16:00"]
|
||||
assert _is_within_off_peak_window(windows, datetime(2026, 1, 1, 3, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(windows, datetime(2026, 1, 1, 14, 30, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window(windows, datetime(2026, 1, 1, 9, 0, tzinfo=timezone.utc)) is False
|
||||
# a malformed entry in the list is ignored, valid entries still match
|
||||
assert _is_within_off_peak_window(["bad", "13:00-16:00"], datetime(2026, 1, 1, 14, 0, tzinfo=timezone.utc)) is True
|
||||
assert _is_within_off_peak_window([], datetime(2026, 1, 1, 14, 0, tzinfo=timezone.utc)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_normalizes_timezone_aware_input():
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
# A caller may pass a non-UTC aware datetime; the window is UTC and must be
|
||||
# evaluated in UTC, not against the caller's wall-clock. 09:00 at UTC+8 is
|
||||
# 01:00 UTC, inside the 01:00-05:00 window.
|
||||
tz_plus_8 = timezone(timedelta(hours=8))
|
||||
assert _is_within_off_peak_window("01:00-05:00", datetime(2026, 1, 1, 9, 0, tzinfo=tz_plus_8)) is True
|
||||
assert _is_within_off_peak_window("01:00-05:00", datetime(2026, 1, 1, 12, 0, tzinfo=tz_plus_8)) is True
|
||||
# 06:00 at UTC+8 is 22:00 UTC the previous day, outside the window
|
||||
assert _is_within_off_peak_window("01:00-05:00", datetime(2026, 1, 1, 6, 0, tzinfo=tz_plus_8)) is False
|
||||
|
||||
|
||||
def test_is_within_off_peak_window_malformed_returns_false():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
now = datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc)
|
||||
assert _is_within_off_peak_window("not-a-window", now) is False
|
||||
assert _is_within_off_peak_window("16:30", now) is False
|
||||
assert _is_within_off_peak_window("25:00-26:00", now) is False
|
||||
|
||||
|
||||
def test_get_token_base_cost_applies_off_peak_pricing():
|
||||
from datetime import datetime, timezone
|
||||
from typing import cast
|
||||
|
||||
from litellm.types.utils import ModelInfo
|
||||
|
||||
model_info = cast(
|
||||
ModelInfo,
|
||||
{
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"cache_read_input_token_cost": 1e-7,
|
||||
"off_peak_pricing": {
|
||||
"hours_utc": "16:30-00:30",
|
||||
"input_cost_per_token": 5e-7,
|
||||
"output_cost_per_token": 1e-6,
|
||||
"cache_read_input_token_cost": 5e-8,
|
||||
},
|
||||
},
|
||||
)
|
||||
usage = Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150)
|
||||
|
||||
off_peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc))
|
||||
assert off_peak[0] == 5e-7
|
||||
assert off_peak[1] == 1e-6
|
||||
assert off_peak[4] == 5e-8
|
||||
|
||||
peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc))
|
||||
assert peak[0] == 1e-6
|
||||
assert peak[1] == 2e-6
|
||||
assert peak[4] == 1e-7
|
||||
|
||||
|
||||
def test_get_token_base_cost_off_peak_falls_back_to_standard_when_unset():
|
||||
from datetime import datetime, timezone
|
||||
from typing import cast
|
||||
|
||||
from litellm.types.utils import ModelInfo
|
||||
|
||||
model_info = cast(
|
||||
ModelInfo,
|
||||
{
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"off_peak_pricing": {"hours_utc": "16:30-00:30", "input_cost_per_token": 5e-7},
|
||||
},
|
||||
)
|
||||
usage = Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150)
|
||||
|
||||
result = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc))
|
||||
assert result[0] == 5e-7
|
||||
assert result[1] == 2e-6
|
||||
|
||||
|
||||
def test_get_token_base_cost_off_peak_wins_over_threshold():
|
||||
from datetime import datetime, timezone
|
||||
from typing import cast
|
||||
|
||||
from litellm.types.utils import ModelInfo
|
||||
|
||||
model_info = cast(
|
||||
ModelInfo,
|
||||
{
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"input_cost_per_token_above_200k_tokens": 3e-6,
|
||||
"output_cost_per_token_above_200k_tokens": 4e-6,
|
||||
"off_peak_pricing": {
|
||||
"hours_utc": "16:30-00:30",
|
||||
"input_cost_per_token": 5e-7,
|
||||
"output_cost_per_token": 1e-6,
|
||||
},
|
||||
},
|
||||
)
|
||||
usage = Usage(prompt_tokens=250000, completion_tokens=250000, total_tokens=500000)
|
||||
|
||||
off_peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc))
|
||||
assert off_peak[0] == 5e-7
|
||||
assert off_peak[1] == 1e-6
|
||||
|
||||
peak = _get_token_base_cost(model_info, usage, current_time=datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc))
|
||||
assert peak[0] == 3e-6
|
||||
assert peak[1] == 4e-6
|
||||
|
||||
|
||||
def test_get_model_info_propagates_off_peak_fields():
|
||||
model_name = "test-off-peak-model"
|
||||
off_peak_pricing = {
|
||||
"hours_utc": "16:30-00:30",
|
||||
"input_cost_per_token": 5e-7,
|
||||
"output_cost_per_token": 1e-6,
|
||||
"cache_read_input_token_cost": 5e-8,
|
||||
}
|
||||
litellm.register_model(
|
||||
{
|
||||
model_name: {
|
||||
"litellm_provider": "openai",
|
||||
"mode": "chat",
|
||||
"input_cost_per_token": 1e-6,
|
||||
"output_cost_per_token": 2e-6,
|
||||
"off_peak_pricing": off_peak_pricing,
|
||||
}
|
||||
}
|
||||
)
|
||||
info = litellm.get_model_info(model=model_name)
|
||||
assert info["off_peak_pricing"] == off_peak_pricing
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue