mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
chore(otel/v2): satisfy tightened lint budgets after merge
The merge inherited upstream's lowered strict and LIT ceilings, which our PR's own new-file code sat just above. Modernize our annotations (Optional[X] to X | None), give the noqa suppressions the reason comments the LIT003 gate requires, and drop the inert `# type: ignore` comments that pyright already disables under this repo's config (LIT009). Every gate is back within its ceiling with no net budget bump
This commit is contained in:
parent
312a9b605a
commit
14e6737290
11 changed files with 56 additions and 63 deletions
|
|
@ -348,7 +348,7 @@ class TenantFanOutSpanProcessor(SpanProcessor):
|
|||
continue
|
||||
try:
|
||||
processor.on_end(_with_destination_resource(span, destination))
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc: # noqa: BLE001 # best-effort fan-out; one destination's failure must not break the others or the request
|
||||
verbose_logger.debug(
|
||||
"OTel V2 fan-out: forwarding span to %s failed: %s",
|
||||
destination.endpoint,
|
||||
|
|
@ -359,7 +359,7 @@ class TenantFanOutSpanProcessor(SpanProcessor):
|
|||
for processor in self._processors.values():
|
||||
try:
|
||||
processor.shutdown()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc: # noqa: BLE001 # a single processor's shutdown failure must not abort shutting down the rest
|
||||
verbose_logger.debug("OTel V2 fan-out: processor shutdown failed: %s", exc)
|
||||
self._processors.clear()
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ class TenantFanOutSpanProcessor(SpanProcessor):
|
|||
try:
|
||||
if not processor.force_flush(timeout_millis):
|
||||
all_ok = False
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception: # noqa: BLE001 # a single processor's flush failure must not fail the whole force_flush
|
||||
all_ok = False
|
||||
return all_ok
|
||||
|
||||
|
|
@ -381,9 +381,11 @@ class TenantFanOutSpanProcessor(SpanProcessor):
|
|||
return cached
|
||||
from litellm.integrations.otel.plumbing.providers import (
|
||||
_exporter_from_spec,
|
||||
_processor_for as _build_processor,
|
||||
default_otlp_kind_for_backend,
|
||||
)
|
||||
from litellm.integrations.otel.plumbing.providers import (
|
||||
_processor_for as _build_processor,
|
||||
)
|
||||
|
||||
try:
|
||||
spec = ExporterSpec(
|
||||
|
|
@ -394,7 +396,7 @@ class TenantFanOutSpanProcessor(SpanProcessor):
|
|||
)
|
||||
exporter = _exporter_from_spec(spec)
|
||||
processor = _build_processor(exporter, use_simple=False)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc: # noqa: BLE001 # a malformed destination spec must not break fan-out; skip this destination
|
||||
verbose_logger.debug(
|
||||
"OTel V2 fan-out: failed to build processor for %s: %s",
|
||||
destination.endpoint,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ credential values only.
|
|||
"""
|
||||
|
||||
import os
|
||||
from typing import Callable, Mapping, Optional
|
||||
from typing import Callable, Mapping
|
||||
|
||||
from litellm.constants import LITELLM_LOGGING_CREDENTIAL_NAME_KEY
|
||||
from litellm.integrations.langfuse.langfuse_otel import (
|
||||
|
|
@ -37,7 +37,7 @@ def _langfuse_endpoint(host: str) -> str:
|
|||
return f"{normalized.rstrip('/')}/api/public/otel"
|
||||
|
||||
|
||||
def _langfuse_destination(values: Mapping[str, str]) -> Optional[OtelDestination]:
|
||||
def _langfuse_destination(values: Mapping[str, str]) -> OtelDestination | None:
|
||||
public_key = values.get("langfuse_public_key")
|
||||
secret_key = values.get("langfuse_secret_key")
|
||||
if not public_key or not secret_key:
|
||||
|
|
@ -48,7 +48,7 @@ def _langfuse_destination(values: Mapping[str, str]) -> Optional[OtelDestination
|
|||
return OtelDestination(endpoint=endpoint, headers={"Authorization": auth})
|
||||
|
||||
|
||||
def _arize_destination(values: Mapping[str, str]) -> Optional[OtelDestination]:
|
||||
def _arize_destination(values: Mapping[str, str]) -> OtelDestination | None:
|
||||
space = values.get("arize_space_id") or values.get("arize_space_key")
|
||||
api_key = values.get("arize_api_key")
|
||||
if not space or not api_key:
|
||||
|
|
@ -69,7 +69,7 @@ def _arize_destination(values: Mapping[str, str]) -> Optional[OtelDestination]:
|
|||
)
|
||||
|
||||
|
||||
def _weave_destination(values: Mapping[str, str]) -> Optional[OtelDestination]:
|
||||
def _weave_destination(values: Mapping[str, str]) -> OtelDestination | None:
|
||||
api_key = values.get("wandb_api_key")
|
||||
if not api_key:
|
||||
return None
|
||||
|
|
@ -94,7 +94,7 @@ def _weave_destination(values: Mapping[str, str]) -> Optional[OtelDestination]:
|
|||
return OtelDestination(endpoint=endpoint, headers=headers)
|
||||
|
||||
|
||||
def _generic_destination(values: Mapping[str, str]) -> Optional[OtelDestination]:
|
||||
def _generic_destination(values: Mapping[str, str]) -> OtelDestination | None:
|
||||
"""Any OTLP backend: an explicit endpoint plus raw headers. The catch-all that
|
||||
makes the registry cover self-hosted collectors / Phoenix / Honeycomb / etc."""
|
||||
endpoint = values.get("otel_endpoint")
|
||||
|
|
@ -103,7 +103,7 @@ def _generic_destination(values: Mapping[str, str]) -> Optional[OtelDestination]
|
|||
return OtelDestination(endpoint=endpoint, headers=_parse_header_string(values.get("otel_headers", "")))
|
||||
|
||||
|
||||
_ADAPTERS: dict[str, Callable[[Mapping[str, str]], Optional[OtelDestination]]] = {
|
||||
_ADAPTERS: dict[str, Callable[[Mapping[str, str]], OtelDestination | None]] = {
|
||||
"langfuse_otel": _langfuse_destination,
|
||||
"arize": _arize_destination,
|
||||
"weave_otel": _weave_destination,
|
||||
|
|
@ -113,7 +113,7 @@ _ADAPTERS: dict[str, Callable[[Mapping[str, str]], Optional[OtelDestination]]] =
|
|||
OTEL_V2_DESTINATION_CALLBACKS = frozenset(_ADAPTERS)
|
||||
|
||||
|
||||
def build_destination(callback_name: str, values: Mapping[str, str]) -> Optional[OtelDestination]:
|
||||
def build_destination(callback_name: str, values: Mapping[str, str]) -> OtelDestination | None:
|
||||
"""Map an admin credential's ``values`` to an ``OtelDestination`` for
|
||||
``callback_name``, falling back to the generic OTLP passthrough.
|
||||
|
||||
|
|
|
|||
|
|
@ -4003,7 +4003,7 @@ def _init_custom_logger_compatible_class(
|
|||
# ``generic`` destination gets the full trace (incl. the gen-AI span), not
|
||||
# just proxy-internal spans. Only meaningful as an admin-owned destination,
|
||||
# so there is no legacy fallback: None when no v2 logger is constructed.
|
||||
return _maybe_construct_otel_v2("generic", _in_memory_loggers) # type: ignore
|
||||
return _maybe_construct_otel_v2("generic", _in_memory_loggers)
|
||||
elif logging_integration == "pagerduty":
|
||||
for callback in _in_memory_loggers:
|
||||
if isinstance(callback, PagerDutyAlerting):
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ These are the canonical credential types for the proxy. They live in the model
|
|||
layer; ``litellm.types.utils`` re-exports them for backwards compatibility.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
|
||||
|
|
@ -20,8 +18,8 @@ class CredentialItem(CredentialBase):
|
|||
|
||||
|
||||
class CreateCredentialItem(CredentialBase):
|
||||
credential_values: Optional[dict] = None
|
||||
model_id: Optional[str] = None
|
||||
credential_values: dict | None = None
|
||||
model_id: str | None = None
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
|
|
@ -40,9 +38,9 @@ class UpdateCredentialItem(BaseModel):
|
|||
access). ``credential_name`` is optional because most patches don't rename.
|
||||
"""
|
||||
|
||||
credential_name: Optional[str] = None
|
||||
credential_values: Optional[dict] = None
|
||||
credential_info: Optional[dict] = None
|
||||
credential_name: str | None = None
|
||||
credential_values: dict | None = None
|
||||
credential_info: dict | None = None
|
||||
|
||||
|
||||
class CredentialAccess(BaseModel):
|
||||
|
|
@ -71,9 +69,9 @@ class CredentialInfo(BaseModel):
|
|||
|
||||
model_config = ConfigDict(extra="allow")
|
||||
|
||||
credential_type: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
host: Optional[str] = None
|
||||
endpoint: Optional[str] = None
|
||||
access: Optional[CredentialAccess] = None
|
||||
credential_type: str | None = None
|
||||
description: str | None = None
|
||||
host: str | None = None
|
||||
endpoint: str | None = None
|
||||
access: CredentialAccess | None = None
|
||||
auto_enable: bool = False
|
||||
|
|
|
|||
|
|
@ -1030,9 +1030,9 @@ async def _hoist_request_destinations(request: Request, user_api_key_dict: UserA
|
|||
set_request_destinations(destinations)
|
||||
try:
|
||||
request.state.otel_destinations = destinations_raw
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception: # noqa: BLE001 # request.state mirror is best-effort; the ContextVar is the source of truth
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc: # noqa: BLE001 # destination hoist is best-effort telemetry setup; it must never fail auth
|
||||
verbose_proxy_logger.debug("OTel V2: hoist destination resolution failed: %s", exc)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -140,16 +140,14 @@ async def _caller_admin_scope(
|
|||
if m.organization_id and m.user_role == LitellmUserRoles.ORG_ADMIN.value
|
||||
)
|
||||
org_teams = (
|
||||
await prisma_client.db.litellm_teamtable.find_many( # type: ignore[union-attr]
|
||||
where={"organization_id": {"in": list(org_admin_of)}}
|
||||
)
|
||||
await prisma_client.db.litellm_teamtable.find_many(where={"organization_id": {"in": list(org_admin_of)}})
|
||||
if org_admin_of
|
||||
else []
|
||||
)
|
||||
org_grantable = frozenset(t.team_id for t in org_teams if t.team_id)
|
||||
|
||||
return CallerAdminScope(team_admin_of | org_grantable, org_admin_of)
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception: # noqa: BLE001 # fail closed to an empty admin scope so a lookup error never widens access
|
||||
verbose_proxy_logger.exception("caller admin-scope lookup failed")
|
||||
return CallerAdminScope(frozenset(), frozenset())
|
||||
|
||||
|
|
@ -185,10 +183,8 @@ async def _credential_for_admin_gate(credential_name: str, prisma_client: object
|
|||
if prisma_client is None:
|
||||
return None
|
||||
try:
|
||||
return await CredentialsRepository(
|
||||
prisma_client # type: ignore[arg-type]
|
||||
).find_by_name(credential_name)
|
||||
except Exception: # noqa: BLE001
|
||||
return await CredentialsRepository(prisma_client).find_by_name(credential_name)
|
||||
except Exception: # noqa: BLE001 # treat any lookup failure as credential-not-found
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ async def _union_logging_exporter_names(user_api_key_dict: UserAPIKeyAuth, org_i
|
|||
proxy_logging_obj=proxy_server.proxy_logging_obj,
|
||||
)
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception: # noqa: BLE001 # best-effort identity enrichment; a failed lookup must not block the request
|
||||
pass
|
||||
|
||||
if user_api_key_dict.team_id:
|
||||
|
|
@ -619,7 +619,7 @@ async def _union_logging_exporter_names(user_api_key_dict: UserAPIKeyAuth, org_i
|
|||
proxy_logging_obj=proxy_server.proxy_logging_obj,
|
||||
)
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception: # noqa: BLE001 # best-effort identity enrichment; a failed lookup must not block the request
|
||||
pass
|
||||
|
||||
if org_id:
|
||||
|
|
@ -633,7 +633,7 @@ async def _union_logging_exporter_names(user_api_key_dict: UserAPIKeyAuth, org_i
|
|||
proxy_logging_obj=proxy_server.proxy_logging_obj,
|
||||
)
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception: # noqa: BLE001 # best-effort identity enrichment; a failed lookup must not block the request
|
||||
pass
|
||||
|
||||
return names
|
||||
|
|
@ -676,6 +676,7 @@ async def _resolve_logging_exporters(
|
|||
from litellm.proxy.management_endpoints.logging_exporter_access import (
|
||||
_has_explicit_access_grants,
|
||||
)
|
||||
|
||||
if _has_explicit_access_grants(info.access):
|
||||
return access_grants(info.access, team_ids, org_ids)
|
||||
return True # no grants = proxy-wide auto
|
||||
|
|
|
|||
|
|
@ -2538,7 +2538,7 @@ async def _validate_update_key_data(
|
|||
|
||||
@router.post("/key/update", tags=["key management"], dependencies=[Depends(user_api_key_auth)])
|
||||
@management_endpoint_wrapper
|
||||
async def update_key_fn( # noqa: C901
|
||||
async def update_key_fn( # noqa: C901 # single endpoint handling many optional key-update fields; decomposition is out of scope here
|
||||
request: Request,
|
||||
data: UpdateKeyRequest,
|
||||
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
|
||||
|
|
@ -4632,7 +4632,7 @@ async def _execute_virtual_key_regeneration(
|
|||
dependencies=[Depends(user_api_key_auth)],
|
||||
)
|
||||
@management_endpoint_wrapper
|
||||
async def regenerate_key_fn( # noqa: C901
|
||||
async def regenerate_key_fn( # noqa: C901 # single endpoint handling many optional key-regeneration fields; decomposition is out of scope here
|
||||
key: Optional[str] = None,
|
||||
data: Optional[RegenerateKeyRequest] = None,
|
||||
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
|
||||
|
|
|
|||
|
|
@ -15,14 +15,12 @@ admin scope is the given set of team ids and org ids. Single-identity callers
|
|||
and orgs, passes the full scope.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import ValidationError
|
||||
|
||||
from litellm.models.credentials import CredentialAccess, CredentialInfo
|
||||
|
||||
|
||||
def parse_credential_info(raw: object) -> Optional[CredentialInfo]:
|
||||
def parse_credential_info(raw: object) -> CredentialInfo | None:
|
||||
"""Parse stored ``credential_info`` into the typed model, or ``None`` when it is
|
||||
absent or malformed.
|
||||
|
||||
|
|
@ -38,7 +36,7 @@ def parse_credential_info(raw: object) -> Optional[CredentialInfo]:
|
|||
return None
|
||||
|
||||
|
||||
def identity_scope(team_id: Optional[str], org_id: Optional[str]) -> tuple[frozenset[str], frozenset[str]]:
|
||||
def identity_scope(team_id: str | None, org_id: str | None) -> tuple[frozenset[str], frozenset[str]]:
|
||||
"""A single request identity's admin scope as ``(team_ids, org_ids)`` for
|
||||
``access_grants`` / ``is_destination_visible``."""
|
||||
return (
|
||||
|
|
@ -48,7 +46,7 @@ def identity_scope(team_id: Optional[str], org_id: Optional[str]) -> tuple[froze
|
|||
|
||||
|
||||
def access_grants(
|
||||
access: Optional[CredentialAccess],
|
||||
access: CredentialAccess | None,
|
||||
team_ids: frozenset[str],
|
||||
org_ids: frozenset[str],
|
||||
) -> bool:
|
||||
|
|
@ -68,7 +66,7 @@ def access_grants(
|
|||
return not org_ids.isdisjoint(access.orgs)
|
||||
|
||||
|
||||
def _has_explicit_access_grants(access: Optional[CredentialAccess]) -> bool:
|
||||
def _has_explicit_access_grants(access: CredentialAccess | None) -> bool:
|
||||
"""True when ``access`` contains at least one explicit grant (global, team, or org).
|
||||
|
||||
Used to distinguish "access intentionally left empty" (proxy-wide fallback) from
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ what enables it. The resolver (``litellm_pre_call_utils``) re-checks visibility
|
|||
request time, so this gate and the resolver agree on what "visible" means.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
import litellm
|
||||
|
|
@ -26,7 +24,7 @@ from litellm.proxy.management_endpoints.logging_exporter_access import (
|
|||
LOGGING_EXPORTERS_KEY = "logging_exporters"
|
||||
|
||||
|
||||
def is_admin_gated_credential_info(credential_info: Optional[dict]) -> bool:
|
||||
def is_admin_gated_credential_info(credential_info: dict | None) -> bool:
|
||||
"""Whether a credential write must be proxy-admin only.
|
||||
|
||||
True when the credential is a logging destination or carries an ``access`` grant,
|
||||
|
|
@ -37,7 +35,7 @@ def is_admin_gated_credential_info(credential_info: Optional[dict]) -> bool:
|
|||
return credential_info.get("credential_type") == "logging" or "access" in credential_info
|
||||
|
||||
|
||||
def validate_credential_access(credential_info: Optional[dict]) -> None:
|
||||
def validate_credential_access(credential_info: dict | None) -> None:
|
||||
"""Validate ``credential_info.access`` shape when the write sets one.
|
||||
|
||||
No-op when ``access`` is absent. Otherwise it must be an object whose ``global`` (if
|
||||
|
|
@ -87,8 +85,8 @@ def _logging_credential_names() -> set[str]:
|
|||
def _reject_unassignable_destinations(
|
||||
exporters: list[str],
|
||||
*,
|
||||
scope_team_id: Optional[str],
|
||||
scope_org_id: Optional[str],
|
||||
scope_team_id: str | None,
|
||||
scope_org_id: str | None,
|
||||
) -> None:
|
||||
"""Reject names a non-proxy-admin cannot assign in this scope.
|
||||
|
||||
|
|
@ -142,8 +140,8 @@ def _validate_exporters_shape_and_names(exporters: object) -> None:
|
|||
|
||||
|
||||
def _exporter_value_changes(
|
||||
requested_metadata: Optional[dict],
|
||||
existing_metadata: Optional[dict],
|
||||
requested_metadata: dict | None,
|
||||
existing_metadata: dict | None,
|
||||
) -> bool:
|
||||
"""True if the effective ``metadata.logging_exporters`` value would change.
|
||||
|
||||
|
|
@ -173,14 +171,14 @@ def _exporter_value_changes(
|
|||
|
||||
|
||||
def validate_logging_exporter_field(
|
||||
requested_exporters: Optional[list],
|
||||
requested_exporters: list | None,
|
||||
user_api_key_dict: UserAPIKeyAuth,
|
||||
*,
|
||||
caller_is_team_admin: bool = False,
|
||||
caller_is_org_admin: bool = False,
|
||||
existing_exporters: Optional[list] = None,
|
||||
scope_team_id: Optional[str] = None,
|
||||
scope_org_id: Optional[str] = None,
|
||||
existing_exporters: list | None = None,
|
||||
scope_team_id: str | None = None,
|
||||
scope_org_id: str | None = None,
|
||||
) -> None:
|
||||
"""Authorize a typed ``logging_exporters`` write (the column-backed field).
|
||||
|
||||
|
|
@ -205,14 +203,14 @@ def validate_logging_exporter_field(
|
|||
|
||||
|
||||
def validate_logging_exporter_assignment(
|
||||
metadata: Optional[dict],
|
||||
metadata: dict | None,
|
||||
user_api_key_dict: UserAPIKeyAuth,
|
||||
*,
|
||||
caller_is_team_admin: bool = False,
|
||||
caller_is_org_admin: bool = False,
|
||||
existing_metadata: Optional[dict] = None,
|
||||
scope_team_id: Optional[str] = None,
|
||||
scope_org_id: Optional[str] = None,
|
||||
existing_metadata: dict | None = None,
|
||||
scope_team_id: str | None = None,
|
||||
scope_org_id: str | None = None,
|
||||
) -> None:
|
||||
"""Validate a ``metadata.logging_exporters`` write on key / team / org endpoints.
|
||||
|
||||
|
|
|
|||
|
|
@ -3638,7 +3638,7 @@ from litellm.models.credentials import CredentialItem as CredentialItem # noqa:
|
|||
from litellm.models.credentials import ( # noqa: E402
|
||||
CreateCredentialItem as CreateCredentialItem,
|
||||
)
|
||||
from litellm.models.credentials import ( # noqa: E402
|
||||
from litellm.models.credentials import ( # noqa: E402 # at file end to avoid a circular import with litellm.models.credentials
|
||||
UpdateCredentialItem as UpdateCredentialItem,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue