mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-09 22:31:41 +00:00
* test: drop the cwd-relative sys.path.insert calls from the test suite
TQ003 stands at 1,077 across 1,058 files, and 1,015 of them are the same shape:
sys.path.insert(0, os.path.abspath("../..")) and its deeper siblings. The
argument resolves against the working directory rather than the file, so from
the repo root, where every job runs pytest, it inserts the directory two levels
above the checkout. It has never pointed at litellm. The package is installed
into the environment anyway, which is what actually makes the import work, and
what the rule's message has said all along.
Removing them leaves 1,634 imports of sys and os with no remaining reference,
and those go too, except where another test module imports the name back out of
the file. The rest of TQ003 is 62 call sites that resolve against __file__ or a
variable, which are a different question and are left alone.
Collection is identical either way: 45,871 tests and the same 51 pre-existing
collection errors before and after, and ruff reports no new undefined name.
* test: drop the duplicate imports the sys.path sweep exposed to F811
* test(pre-call-utils): restore the os import the new bedrock tests need
137 lines
4.6 KiB
Python
137 lines
4.6 KiB
Python
"""Test that cost calculation uses appropriate log levels"""
|
|
|
|
import logging
|
|
|
|
|
|
import litellm
|
|
from litellm import completion_cost
|
|
|
|
|
|
def test_cost_calculation_uses_debug_level():
|
|
"""
|
|
Test that cost calculation logs use DEBUG level instead of INFO.
|
|
This ensures cost calculation details don't appear in production logs.
|
|
Part of fix for issue #9815.
|
|
|
|
Note: This test uses a custom log handler instead of caplog because
|
|
caplog doesn't work reliably with pytest-xdist parallel execution.
|
|
"""
|
|
from litellm._logging import verbose_logger
|
|
|
|
# Create a custom handler to capture log records
|
|
class LogRecordHandler(logging.Handler):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.records = []
|
|
|
|
def emit(self, record):
|
|
self.records.append(record)
|
|
|
|
# Set up custom handler
|
|
handler = LogRecordHandler()
|
|
handler.setLevel(logging.DEBUG)
|
|
original_level = verbose_logger.level
|
|
verbose_logger.setLevel(logging.DEBUG)
|
|
verbose_logger.addHandler(handler)
|
|
|
|
try:
|
|
# Create a mock completion response
|
|
mock_response = {
|
|
"id": "test",
|
|
"object": "chat.completion",
|
|
"created": 1234567890,
|
|
"model": "gpt-3.5-turbo",
|
|
"choices": [
|
|
{
|
|
"index": 0,
|
|
"message": {"role": "assistant", "content": "Test response"},
|
|
"finish_reason": "stop",
|
|
}
|
|
],
|
|
"usage": {"prompt_tokens": 10, "completion_tokens": 20, "total_tokens": 30},
|
|
}
|
|
|
|
# Call completion_cost to trigger logs
|
|
try:
|
|
cost = completion_cost(
|
|
completion_response=mock_response, model="gpt-3.5-turbo"
|
|
)
|
|
except Exception:
|
|
pass # Cost calculation may fail, but we're checking log levels
|
|
|
|
# Find the cost calculation log records
|
|
cost_calc_records = [
|
|
record
|
|
for record in handler.records
|
|
if "selected model name for cost calculation" in record.getMessage()
|
|
]
|
|
|
|
# Verify that cost calculation logs are at DEBUG level
|
|
assert len(cost_calc_records) > 0, "No cost calculation logs found"
|
|
|
|
for record in cost_calc_records:
|
|
assert (
|
|
record.levelno == logging.DEBUG
|
|
), f"Cost calculation log should be DEBUG level, but was {record.levelname}"
|
|
finally:
|
|
# Clean up: remove handler and restore original logger level
|
|
verbose_logger.removeHandler(handler)
|
|
verbose_logger.setLevel(original_level)
|
|
|
|
|
|
def test_batch_cost_calculation_uses_debug_level():
|
|
"""
|
|
Test that batch cost calculation logs also use DEBUG level.
|
|
|
|
Note: This test uses a custom log handler instead of caplog because
|
|
caplog doesn't work reliably with pytest-xdist parallel execution.
|
|
"""
|
|
from litellm.cost_calculator import batch_cost_calculator
|
|
from litellm.types.utils import Usage
|
|
from litellm._logging import verbose_logger
|
|
|
|
# Create a custom handler to capture log records
|
|
class LogRecordHandler(logging.Handler):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.records = []
|
|
|
|
def emit(self, record):
|
|
self.records.append(record)
|
|
|
|
# Set up custom handler
|
|
handler = LogRecordHandler()
|
|
handler.setLevel(logging.DEBUG)
|
|
original_level = verbose_logger.level
|
|
verbose_logger.setLevel(logging.DEBUG)
|
|
verbose_logger.addHandler(handler)
|
|
|
|
try:
|
|
# Create a mock usage object
|
|
usage = Usage(prompt_tokens=100, completion_tokens=200, total_tokens=300)
|
|
|
|
# Call batch_cost_calculator to trigger logs
|
|
try:
|
|
batch_cost_calculator(
|
|
usage=usage, model="gpt-3.5-turbo", custom_llm_provider="openai"
|
|
)
|
|
except Exception:
|
|
pass # May fail, but we're checking log levels
|
|
|
|
# Find batch cost calculation log records
|
|
batch_cost_records = [
|
|
record
|
|
for record in handler.records
|
|
if "Calculating batch cost per token" in record.getMessage()
|
|
]
|
|
|
|
# Verify logs exist and are at DEBUG level
|
|
if batch_cost_records: # May not always log depending on the code path
|
|
for record in batch_cost_records:
|
|
assert (
|
|
record.levelno == logging.DEBUG
|
|
), f"Batch cost calculation log should be DEBUG level, but was {record.levelname}"
|
|
finally:
|
|
# Clean up: remove handler and restore original logger level
|
|
verbose_logger.removeHandler(handler)
|
|
verbose_logger.setLevel(original_level)
|