chore: conform project budget code to staging lint gates

Staging's Final-annotation pass landed after this branch forked, so the
merged project-budget code breached three ratcheted ceilings:

- LIT010: annotate the new single-assignment locals Final, and rewrite
  _team_member_budget_check_for_key so the membership lookup and the
  cross-pod spend read are conditional expressions rather than rebinds
- ANN202: annotate _update_project_db's return type
- reportGeneralTypeIssues: staging declares user_api_key_cache Final in
  update_spend, so the project cache invalidation binds its own name
This commit is contained in:
Yuneng Jiang 2026-08-07 17:52:55 -07:00
parent 9710ae7ec9
commit ff58f8dc9c
No known key found for this signature in database
5 changed files with 36 additions and 29 deletions

View file

@ -4192,7 +4192,7 @@ async def _project_max_budget_check(
from litellm.proxy.proxy_server import get_current_spend
project_spend = await get_current_spend(
project_spend: Final = await get_current_spend(
counter_key=f"spend:project:{project_object.project_id}",
fallback_spend=project_object.spend or 0.0,
max_budget=max_budget,

View file

@ -1054,44 +1054,50 @@ async def _team_member_budget_check_for_key(
if prisma_client is None:
return
_cache_key = f"{valid_token.team_id}_{valid_token.user_id}"
_cache_key: Final = f"{valid_token.team_id}_{valid_token.user_id}"
team_member_info = await user_api_key_cache.async_get_cache(
cached_member: Final = await user_api_key_cache.async_get_cache(
key=_cache_key,
model_type=LiteLLM_TeamMembership,
)
if team_member_info is None and valid_token.user_id is not None and valid_token.team_id is not None:
_db_member = await TeamMembershipRepository(prisma_client).table.find_first(
_db_member: Final = (
await TeamMembershipRepository(prisma_client).table.find_first(
where={ # mutable-ok: prisma query argument shape
"user_id": valid_token.user_id,
"team_id": valid_token.team_id,
},
include={"litellm_budget_table": True}, # mutable-ok: prisma query argument shape
)
if _db_member is not None:
team_member_info = LiteLLM_TeamMembership(**_db_member.dict())
await user_api_key_cache.async_set_cache(
key=_cache_key,
value=team_member_info,
model_type=LiteLLM_TeamMembership,
ttl=5,
)
if cached_member is None and valid_token.user_id is not None and valid_token.team_id is not None
else None
)
fresh_member: Final = LiteLLM_TeamMembership(**_db_member.dict()) if _db_member is not None else None
if fresh_member is not None:
await user_api_key_cache.async_set_cache(
key=_cache_key,
value=fresh_member,
model_type=LiteLLM_TeamMembership,
ttl=5,
)
team_member_info: Final = cached_member if cached_member is not None else fresh_member
if team_member_info is None or team_member_info.litellm_budget_table is None:
return
team_member_budget = team_member_info.litellm_budget_table.max_budget
team_member_budget: Final = team_member_info.litellm_budget_table.max_budget
if team_member_budget is None or team_member_budget <= 0:
return
from litellm.proxy.proxy_server import get_current_spend
team_member_spend = valid_token.team_member_spend
if valid_token.user_id is not None and valid_token.team_id is not None:
team_member_spend = await get_current_spend(
team_member_spend: Final = (
await get_current_spend(
counter_key=f"spend:team_member:{valid_token.user_id}:{valid_token.team_id}",
fallback_spend=team_member_spend,
fallback_spend=valid_token.team_member_spend,
max_budget=team_member_budget,
)
if valid_token.user_id is not None and valid_token.team_id is not None
else valid_token.team_member_spend
)
if team_member_spend > team_member_budget:
raise litellm.BudgetExceededError(
current_cost=team_member_spend,

View file

@ -720,7 +720,7 @@ class DBSpendUpdateWriter:
response_cost: float | None,
project_id: str | None,
prisma_client: PrismaClient | None,
):
) -> None:
try:
if project_id is None or prisma_client is None:
return
@ -1390,7 +1390,7 @@ class DBSpendUpdateWriter:
)
### UPDATE PROJECT TABLE ###
project_list_transactions = db_spend_update_transactions.get("project_list_transactions")
project_list_transactions: Final = db_spend_update_transactions.get("project_list_transactions")
await DBSpendUpdateWriter._update_entity_spend_in_db(
entity_name="Project",
transactions=project_list_transactions,
@ -1401,10 +1401,10 @@ class DBSpendUpdateWriter:
proxy_logging_obj=proxy_logging_obj,
)
if project_list_transactions and proxy_logging_obj is not None:
user_api_key_cache = proxy_logging_obj.call_details.get("user_api_key_cache")
if user_api_key_cache is not None:
project_api_key_cache: Final = proxy_logging_obj.call_details.get("user_api_key_cache")
if project_api_key_cache is not None:
for project_id in project_list_transactions:
await user_api_key_cache.async_delete_cache(key=f"project_id:{project_id}")
await project_api_key_cache.async_delete_cache(key=f"project_id:{project_id}")
### UPDATE TAG TABLE ###
tag_list_transactions: Final = db_spend_update_transactions["tag_list_transactions"]

View file

@ -114,7 +114,8 @@ class SpendCounterReseed:
org_id: Final = counter_key[len("spend:org:") :]
row = await OrganizationRepository(prisma_client).table.find_unique(where={"organization_id": org_id})
elif counter_key.startswith("spend:project:"):
project_id = counter_key[len("spend:project:") :]
project_id: Final = counter_key[len("spend:project:") :]
# rebind-ok: one repository lookup per mutually exclusive counter-key branch
row = await ProjectRepository(prisma_client).table.find_unique(where={"project_id": project_id})
else:
return None

View file

@ -437,7 +437,7 @@ async def _get_budget_counters(
if org_counter is not None:
counters.append(org_counter)
project_counter = await _get_project_budget_counter(
project_counter: Final = await _get_project_budget_counter(
valid_token=valid_token,
user_api_key_cache=user_api_key_cache,
)
@ -583,13 +583,13 @@ async def _get_project_budget_counter(
if valid_token.project_id is None:
return None
source_cache_key = f"project_id:{valid_token.project_id}"
project_object = await user_api_key_cache.async_get_cache(key=source_cache_key)
source_cache_key: Final = f"project_id:{valid_token.project_id}"
project_object: Final = await user_api_key_cache.async_get_cache(key=source_cache_key)
if project_object is None:
return None
budget_table = _get_value(project_object, "litellm_budget_table")
max_budget = _to_float(_get_value(budget_table, "max_budget"))
budget_table: Final = _get_value(project_object, "litellm_budget_table")
max_budget: Final = _to_float(_get_value(budget_table, "max_budget"))
if max_budget is None or max_budget <= 0:
return None