Coverage for .venv/lib/python3.13/site-packages/litellm/proxy/client/cli/commands/credentials.py: 0%
90 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 12:01 +0000
1import json
2from collections.abc import Sequence
3from typing import Final, Literal
5import click
6import requests
7import rich
8from rich.table import Table
9from typing_extensions import NotRequired, ReadOnly, TypedDict
11from ...credentials import CredentialsManagementClient
12from ._cli_context import cli_context_values
15class _CredentialInfo(TypedDict):
16 custom_llm_provider: ReadOnly[NotRequired[str]]
19class _CredentialItem(TypedDict):
20 credential_name: ReadOnly[NotRequired[str]]
21 credential_info: ReadOnly[NotRequired[_CredentialInfo]]
24class _CredentialsListView(TypedDict):
25 credentials: ReadOnly[Sequence[_CredentialItem]]
28class _JsonObjectView(TypedDict):
29 value: ReadOnly[dict[str, object]]
32class _JsonBodyView(TypedDict):
33 body: ReadOnly[object]
36@click.group()
37def credentials():
38 """Manage credentials for the LiteLLM proxy server"""
41@credentials.command()
42@click.option(
43 "--format",
44 "output_format",
45 type=click.Choice(["table", "json"]),
46 default="table",
47 help="Output format (table or json)",
48)
49@click.pass_context
50def list(ctx: click.Context, output_format: Literal["table", "json"]):
51 """List all credentials"""
52 context: Final = cli_context_values(ctx)
53 client: Final = CredentialsManagementClient(context["base_url"], context["api_key"])
54 response: Final = client.list()
55 assert isinstance(response, dict)
57 if output_format == "json":
58 rich.print_json(data=response)
59 else: # table format
60 table: Final = Table(title="Credentials")
62 # Add columns
63 table.add_column("Credential Name", style="cyan")
64 table.add_column("Custom LLM Provider", style="green")
66 # Add rows
67 listed: Final[_CredentialsListView] = {"credentials": response.get("credentials", [])}
68 for cred in listed["credentials"]:
69 info = cred.get("credential_info", {})
70 table.add_row(
71 str(cred.get("credential_name", "")),
72 str(info.get("custom_llm_provider", "")),
73 )
75 rich.print(table)
78@credentials.command()
79@click.argument("credential_name")
80@click.option(
81 "--info",
82 type=str,
83 help="JSON string containing credential info",
84 required=True,
85)
86@click.option(
87 "--values",
88 type=str,
89 help="JSON string containing credential values",
90 required=True,
91)
92@click.pass_context
93def create(ctx: click.Context, credential_name: str, info: str, values: str):
94 """Create a new credential"""
95 context: Final = cli_context_values(ctx)
96 client: Final = CredentialsManagementClient(context["base_url"], context["api_key"])
97 try:
98 credential_info: Final[_JsonObjectView] = {"value": json.loads(info)}
99 credential_values: Final[_JsonObjectView] = {"value": json.loads(values)}
100 except json.JSONDecodeError as e:
101 raise click.BadParameter(f"Invalid JSON: {e}")
103 try:
104 response: Final = client.create(credential_name, credential_info["value"], credential_values["value"])
105 rich.print_json(data=response)
106 except requests.exceptions.HTTPError as e:
107 click.echo(f"Error: HTTP {e.response.status_code}", err=True)
108 try:
109 error_body: Final[_JsonBodyView] = {"body": e.response.json()}
110 rich.print_json(data=error_body["body"])
111 except json.JSONDecodeError:
112 click.echo(e.response.text, err=True)
113 raise click.Abort()
116@credentials.command()
117@click.argument("credential_name")
118@click.pass_context
119def delete(ctx: click.Context, credential_name: str):
120 """Delete a credential by name"""
121 context: Final = cli_context_values(ctx)
122 client: Final = CredentialsManagementClient(context["base_url"], context["api_key"])
123 try:
124 response: Final = client.delete(credential_name)
125 rich.print_json(data=response)
126 except requests.exceptions.HTTPError as e:
127 click.echo(f"Error: HTTP {e.response.status_code}", err=True)
128 try:
129 error_body: Final[_JsonBodyView] = {"body": e.response.json()}
130 rich.print_json(data=error_body["body"])
131 except json.JSONDecodeError:
132 click.echo(e.response.text, err=True)
133 raise click.Abort()
136@credentials.command()
137@click.argument("credential_name")
138@click.pass_context
139def get(ctx: click.Context, credential_name: str):
140 """Get a credential by name"""
141 context: Final = cli_context_values(ctx)
142 client: Final = CredentialsManagementClient(context["base_url"], context["api_key"])
143 response: Final = client.get(credential_name)
144 rich.print_json(data=response)