test(cost): cover the gpt-image data_residency uplift

Added tests to validate data residency uplift for gpt-image costs.
This commit is contained in:
Mrunmayee Daware 2026-10-14 15:41:13 +05:30 • committed by GitHub
parent 83669a1336
commit bdaf38e361
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -10,6 +10,8 @@ gpt-image-1 uses token-based pricing:
- Image Output: $40.00/1M tokens
"""
from typing import Final
import pytest
import litellm
@ -18,6 +20,7 @@ from litellm.types.utils import (
ImageResponse,
ImageUsage,
ImageUsageInputTokensDetails,
ModelInfo,
)
@ -91,7 +94,6 @@ class TestGPTImageCostRouting:
"""Test that gpt-image models are properly routed to the token-based calculator"""
class TestGPTImage15OutputImageTokens:
"""
Test for GitHub issue #19508:
@ -120,3 +122,141 @@ class TestGPTImage2OutputImageTokensNoBreakdown:
if __name__ == "__main__":
pytest.main([__file__, "-v"])
class TestGPTImageDataResidencyUplift:
"""
Test for GitHub issue #46407:
gpt-image cost ignored the OpenAI regional-processing (data residency) uplift.
The chat path applies ``regional_processing_uplift_multiplier_<region>`` from
the resolved price table inside ``generic_cost_per_token``; the image route
never received ``data_residency``, so the uplift could never reach gpt-image
calls. These tests pin the uplift on the image path using a price table that
carries the multiplier key (same mechanism the chat path uses with cost-map
entries).
"""
_MODEL_INFO: Final[ModelInfo] = {
"input_cost_per_token": 5e-06,
"output_cost_per_token": 1e-05,
"input_cost_per_image_token": 1e-05,
"output_cost_per_image_token": 4e-05,
"regional_processing_uplift_multiplier_eu": 1.1,
"regional_processing_uplift_multiplier_us": 1.1,
}
@staticmethod
def _image_response() -> ImageResponse:
return ImageResponse(
created=1234567890,
data=[ImageObject(url="http://example.com/image.jpg")],
usage=ImageUsage(
input_tokens=1000,
input_tokens_details=ImageUsageInputTokensDetails(image_tokens=600, text_tokens=400),
output_tokens=500,
total_tokens=1500,
),
)
def test_data_residency_uplift_applies_to_gpt_image_cost(self) -> None:
from litellm.llms.openai.image_generation.cost_calculator import cost_calculator
base: Final = cost_calculator(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=self._MODEL_INFO,
)
eu: Final = cost_calculator(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=self._MODEL_INFO,
data_residency="eu",
)
assert base > 0
assert abs(eu - base * 1.1) < 1e-12
def test_data_residency_uplift_via_calculate_image_response_cost_from_usage(self) -> None:
from litellm.litellm_core_utils.llm_cost_calc.utils import calculate_image_response_cost_from_usage
base: Final = calculate_image_response_cost_from_usage(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=self._MODEL_INFO,
)
eu: Final = calculate_image_response_cost_from_usage(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=self._MODEL_INFO,
data_residency="eu",
)
assert base is not None and eu is not None
assert abs(eu - base * 1.1) < 1e-12
def test_no_uplift_when_model_carries_no_multiplier(self) -> None:
from litellm.llms.openai.image_generation.cost_calculator import cost_calculator
model_info: Final[ModelInfo] = {
"input_cost_per_token": 5e-06,
"output_cost_per_token": 1e-05,
"input_cost_per_image_token": 1e-05,
"output_cost_per_image_token": 4e-05,
}
base: Final = cost_calculator(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=model_info,
)
eu: Final = cost_calculator(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=model_info,
data_residency="eu",
)
assert eu == base
def test_no_uplift_when_data_residency_absent(self) -> None:
from litellm.llms.openai.image_generation.cost_calculator import cost_calculator
none_region: Final = cost_calculator(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=self._MODEL_INFO,
data_residency=None,
)
base: Final = cost_calculator(
model="gpt-image-1",
image_response=self._image_response(),
custom_llm_provider="openai",
model_info=self._MODEL_INFO,
)
assert none_region == base
def test_completion_cost_threads_data_residency_to_image_route(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""End-to-end: completion_cost's image branch must hand data_residency to the route."""
from litellm.cost_calculator import completion_cost
monkeypatch.setitem(litellm.model_cost["gpt-image-1"], "regional_processing_uplift_multiplier_eu", 1.1)
base: Final = completion_cost(
completion_response=self._image_response(),
model="gpt-image-1",
custom_llm_provider="openai",
call_type="image_generation",
)
eu: Final = completion_cost(
completion_response=self._image_response(),
model="gpt-image-1",
custom_llm_provider="openai",
call_type="image_generation",
data_residency="eu",
)
assert base > 0
assert abs(eu - base * 1.1) < 1e-12