Skip to content

Commit 6984c5a

Browse files
committed
Format code
1 parent e94c325 commit 6984c5a

5 files changed

Lines changed: 137 additions & 103 deletions

File tree

src/claude_top/auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def get_claude_code_credentials() -> Optional[dict[str, Any]]:
4040
"access_token": oauth.get("accessToken"),
4141
"refresh_token": oauth.get("refreshToken"),
4242
"expires_at": expires_at,
43-
"source": "claude_code"
43+
"source": "claude_code",
4444
}
4545
except (OSError, json.JSONDecodeError):
4646
continue

src/claude_top/cli.py

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -47,43 +47,63 @@ def compact_trend(values: list[int]) -> str:
4747
total_color = "#52A66A" if daily_pct < 70 else "#E8A84D" if daily_pct < 90 else "#D96B6B"
4848

4949
# Summary (color total metrics by usage)
50-
console.print(f"\n[bold #CC785C]Total Tokens:[/bold #CC785C] [{total_color}]{usage_data['total_tokens']:,}[/{total_color}]")
51-
console.print(f"[bold #CC785C]Total Requests:[/bold #CC785C] [{total_color}]{usage_data['total_requests']:,}[/{total_color}]")
50+
console.print(
51+
f"\n[bold #CC785C]Total Tokens:[/bold #CC785C] [{total_color}]{usage_data['total_tokens']:,}[/{total_color}]"
52+
)
53+
console.print(
54+
f"[bold #CC785C]Total Requests:[/bold #CC785C] [{total_color}]{usage_data['total_requests']:,}[/{total_color}]"
55+
)
5256

5357
# Explicit alerts in normal view for threshold visibility.
5458
if status.get("tier_available"):
5559
daily_pct = status.get("daily_tokens_percentage", 0)
5660
weekly_pct = status.get("weekly_tokens_percentage", 0)
5761
if daily_pct >= 90 or weekly_pct >= 90:
58-
console.print("[bold #D96B6B]ALERT:[/bold #D96B6B] Usage is above 90% of one or more limits.")
62+
console.print(
63+
"[bold #D96B6B]ALERT:[/bold #D96B6B] Usage is above 90% of one or more limits."
64+
)
5965
elif daily_pct >= 80 or weekly_pct >= 80:
60-
console.print("[bold #E8A84D]Warning:[/bold #E8A84D] Usage is above 80% of one or more limits.")
66+
console.print(
67+
"[bold #E8A84D]Warning:[/bold #E8A84D] Usage is above 80% of one or more limits."
68+
)
6169

6270
# Cache stats and extra details when in detailed view
6371
if show_detailed:
64-
cache_read = usage_data.get('total_cache_read_tokens', 0)
65-
cache_creation = usage_data.get('total_cache_creation_tokens', 0)
72+
cache_read = usage_data.get("total_cache_read_tokens", 0)
73+
cache_creation = usage_data.get("total_cache_creation_tokens", 0)
6674
if cache_read > 0 or cache_creation > 0:
6775
console.print("\n[bold #CC785C]Cache Statistics:[/bold #CC785C]")
6876
if cache_creation > 0:
69-
console.print(f" [dim]Cache Writes:[/dim] [#E8A84D]{cache_creation:,}[/#E8A84D] tokens")
77+
console.print(
78+
f" [dim]Cache Writes:[/dim] [#E8A84D]{cache_creation:,}[/#E8A84D] tokens"
79+
)
7080
if cache_read > 0:
71-
console.print(f" [dim]Cache Reads:[/dim] [#52A66A]{cache_read:,}[/#52A66A] tokens [dim italic](saved!)[/dim italic]")
81+
console.print(
82+
f" [dim]Cache Reads:[/dim] [#52A66A]{cache_read:,}[/#52A66A] tokens [dim italic](saved!)[/dim italic]"
83+
)
7284

7385
total_cache_ops = cache_read + cache_creation
7486
if total_cache_ops > 0:
7587
hit_rate = (cache_read / total_cache_ops) * 100
76-
console.print(f"[bold #CC785C]Cache hit rate:[/bold #CC785C] [#52A66A]{hit_rate:.1f}%[/#52A66A]")
88+
console.print(
89+
f"[bold #CC785C]Cache hit rate:[/bold #CC785C] [#52A66A]{hit_rate:.1f}%[/#52A66A]"
90+
)
7791

7892
insights = usage_data.get("insights", {})
79-
total_reqs = usage_data.get('total_requests', 0) or 1
80-
avg_tokens = insights.get("avg_tokens_per_request", usage_data.get('total_tokens', 0) / total_reqs)
81-
console.print(f"[bold #CC785C]Avg tokens/request:[/bold #CC785C] [#E8956D]{avg_tokens:.1f}[/#E8956D]")
93+
total_reqs = usage_data.get("total_requests", 0) or 1
94+
avg_tokens = insights.get(
95+
"avg_tokens_per_request", usage_data.get("total_tokens", 0) / total_reqs
96+
)
97+
console.print(
98+
f"[bold #CC785C]Avg tokens/request:[/bold #CC785C] [#E8956D]{avg_tokens:.1f}[/#E8956D]"
99+
)
82100

83101
# Informational cost estimate
84102
total_cost = insights.get("cost_estimate_usd", 0.0)
85103
cost_breakdown = insights.get("cost_breakdown_usd", {})
86-
console.print(f"[bold #CC785C]Estimated cost:[/bold #CC785C] [#E8956D]${total_cost:.2f}[/#E8956D] [dim](approx)[/dim]")
104+
console.print(
105+
f"[bold #CC785C]Estimated cost:[/bold #CC785C] [#E8956D]${total_cost:.2f}[/#E8956D] [dim](approx)[/dim]"
106+
)
87107
if cost_breakdown:
88108
console.print(
89109
f" [dim]input ${cost_breakdown.get('input', 0.0):.2f} | output ${cost_breakdown.get('output', 0.0):.2f} | cache write ${cost_breakdown.get('cache_write', 0.0):.2f} | cache read ${cost_breakdown.get('cache_read', 0.0):.2f}[/dim]"
@@ -94,7 +114,9 @@ def compact_trend(values: list[int]) -> str:
94114
if trend:
95115
token_values = [int(day.get("tokens", 0)) for day in trend]
96116
trend_line = compact_trend(token_values)
97-
console.print(f"[bold #CC785C]7-day trend:[/bold #CC785C] [#E8956D]{trend_line}[/#E8956D]")
117+
console.print(
118+
f"[bold #CC785C]7-day trend:[/bold #CC785C] [#E8956D]{trend_line}[/#E8956D]"
119+
)
98120

99121
# Historical comparison: this week vs last week
100122
comparison = usage_data.get("weekly_comparison", {})
@@ -120,21 +142,25 @@ def compact_trend(values: list[int]) -> str:
120142
)
121143

122144
# Top 3 models
123-
models = usage_data.get('models', {})
145+
models = usage_data.get("models", {})
124146
if models:
125-
top = sorted(models.items(), key=lambda it: it[1].get('tokens', 0), reverse=True)[:3]
147+
top = sorted(models.items(), key=lambda it: it[1].get("tokens", 0), reverse=True)[:3]
126148
console.print()
127149
for m, s in top:
128150
console.print(f" [#E8956D]{m}[/#E8956D] — {s.get('tokens',0):,} tokens")
129151

130152
# At this point 'status' was computed earlier
131153
if status.get("tier_available"):
132-
console.print(f"\n[bold #E8956D]Tier:[/bold #E8956D] {status['tier_name']} ({status['subscription_type']})")
154+
console.print(
155+
f"\n[bold #E8956D]Tier:[/bold #E8956D] {status['tier_name']} ({status['subscription_type']})"
156+
)
133157

134158
# Session usage (5 hour window)
135-
daily_countdown = status.get('daily_reset_countdown', 'unknown')
136-
if daily_countdown and daily_countdown != 'unknown':
137-
console.print(f"\n[bold #CC785C]Current Session (5hr)[/bold #CC785C] [dim](resets in [italic]{daily_countdown}[/italic])[/dim]")
159+
daily_countdown = status.get("daily_reset_countdown", "unknown")
160+
if daily_countdown and daily_countdown != "unknown":
161+
console.print(
162+
f"\n[bold #CC785C]Current Session (5hr)[/bold #CC785C] [dim](resets in [italic]{daily_countdown}[/italic])[/dim]"
163+
)
138164
else:
139165
console.print("\n[bold #CC785C]Current Session (5hr)[/bold #CC785C]")
140166
daily_pct = status["daily_tokens_percentage"]
@@ -149,15 +175,19 @@ def compact_trend(values: list[int]) -> str:
149175
progress.add_task(
150176
f"Tokens: {status['daily_tokens_used']:,} / {status['daily_tokens_limit']:,}",
151177
total=100,
152-
completed=daily_pct
178+
completed=daily_pct,
153179
)
154180

155-
console.print(f" {status['daily_tokens_used']:,} / {status['daily_tokens_limit']:,} tokens [dim]({status['daily_tokens_remaining']:,} remaining)[/dim]")
181+
console.print(
182+
f" {status['daily_tokens_used']:,} / {status['daily_tokens_limit']:,} tokens [dim]({status['daily_tokens_remaining']:,} remaining)[/dim]"
183+
)
156184

157185
# Weekly usage
158-
weekly_countdown = status.get('weekly_reset_countdown', 'unknown')
159-
if weekly_countdown and weekly_countdown != 'unknown':
160-
console.print(f"\n[bold #CC785C]Weekly Session[/bold #CC785C] [dim](resets in [italic]{weekly_countdown}[/italic])[/dim]")
186+
weekly_countdown = status.get("weekly_reset_countdown", "unknown")
187+
if weekly_countdown and weekly_countdown != "unknown":
188+
console.print(
189+
f"\n[bold #CC785C]Weekly Session[/bold #CC785C] [dim](resets in [italic]{weekly_countdown}[/italic])[/dim]"
190+
)
161191
else:
162192
console.print("\n[bold #CC785C]Weekly Session[/bold #CC785C]")
163193
weekly_pct = status["weekly_tokens_percentage"]
@@ -172,16 +202,18 @@ def compact_trend(values: list[int]) -> str:
172202
progress.add_task(
173203
f"Tokens: {status['weekly_tokens_used']:,} / {status['weekly_tokens_limit']:,}",
174204
total=100,
175-
completed=weekly_pct
205+
completed=weekly_pct,
176206
)
177207

178-
console.print(f" {status['weekly_tokens_used']:,} / {status['weekly_tokens_limit']:,} tokens [dim]({status['weekly_tokens_remaining']:,} remaining)[/dim]")
208+
console.print(
209+
f" {status['weekly_tokens_used']:,} / {status['weekly_tokens_limit']:,} tokens [dim]({status['weekly_tokens_remaining']:,} remaining)[/dim]"
210+
)
179211

180212
if usage_data.get("period"):
181213
period = usage_data["period"]
182214
if isinstance(period, dict):
183-
start_str = period.get('start', 'N/A')
184-
end_str = period.get('end', 'N/A')
215+
start_str = period.get("start", "N/A")
216+
end_str = period.get("end", "N/A")
185217

186218
try:
187219
from dateutil import parser
@@ -198,9 +230,7 @@ def compact_trend(values: list[int]) -> str:
198230
)
199231
except Exception:
200232
# Fallback if timezone conversion fails
201-
console.print(
202-
f"\n[bold #CC785C]Period:[/bold #CC785C] {start_str} to {end_str}"
203-
)
233+
console.print(f"\n[bold #CC785C]Period:[/bold #CC785C] {start_str} to {end_str}")
204234

205235
# Models table
206236
if usage_data.get("models"):
@@ -224,24 +254,20 @@ def compact_trend(values: list[int]) -> str:
224254
@app.command()
225255
def main(
226256
once: Annotated[
227-
bool,
228-
typer.Option("--once", help="Display usage once and exit (default is to watch)")
257+
bool, typer.Option("--once", help="Display usage once and exit (default is to watch)")
229258
] = False,
230259
no_ui: Annotated[
231-
bool,
232-
typer.Option("--no-ui", help="Print usage table instead of TUI")
233-
] = False,
234-
json: Annotated[
235-
bool,
236-
typer.Option("--json", help="Print raw JSON and exit")
260+
bool, typer.Option("--no-ui", help="Print usage table instead of TUI")
237261
] = False,
262+
json: Annotated[bool, typer.Option("--json", help="Print raw JSON and exit")] = False,
238263
detailed: Annotated[
239-
bool,
240-
typer.Option("--detailed", help="Show detailed information (cache & model stats)")
264+
bool, typer.Option("--detailed", help="Show detailed information (cache & model stats)")
241265
] = False,
242266
watch: Annotated[
243267
Optional[int],
244-
typer.Option("--watch", help="Custom refresh interval in seconds (default: 1)", metavar="N")
268+
typer.Option(
269+
"--watch", help="Custom refresh interval in seconds (default: 1)", metavar="N"
270+
),
245271
] = None,
246272
) -> None:
247273
"""

src/claude_top/data.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
class UsageDataError(Exception):
2525
"""Error reading usage data from local files."""
26+
2627
pass
2728

2829

@@ -134,13 +135,11 @@ def fetch_usage_from_api(force_refresh: bool = False) -> Optional[dict[str, Any]
134135
headers = {
135136
"Authorization": f"Bearer {token}",
136137
"anthropic-beta": "oauth-2025-04-20",
137-
"Content-Type": "application/json"
138+
"Content-Type": "application/json",
138139
}
139140

140141
response = requests.get(
141-
"https://api.anthropic.com/api/oauth/usage",
142-
headers=headers,
143-
timeout=10
142+
"https://api.anthropic.com/api/oauth/usage", headers=headers, timeout=10
144143
)
145144

146145
if response.status_code == 200:
@@ -221,17 +220,21 @@ def extract_usage_from_events(events: list[dict[str, Any]]) -> dict[str, Any]:
221220
"total_output_tokens": 0,
222221
"total_cache_creation_tokens": 0,
223222
"total_cache_read_tokens": 0,
224-
"models": defaultdict(lambda: {
225-
"requests": 0,
226-
"input_tokens": 0,
227-
"output_tokens": 0,
228-
"cache_creation_tokens": 0,
229-
"cache_read_tokens": 0,
230-
}),
231-
"projects": defaultdict(lambda: {
232-
"requests": 0,
233-
"tokens": 0,
234-
}),
223+
"models": defaultdict(
224+
lambda: {
225+
"requests": 0,
226+
"input_tokens": 0,
227+
"output_tokens": 0,
228+
"cache_creation_tokens": 0,
229+
"cache_read_tokens": 0,
230+
}
231+
),
232+
"projects": defaultdict(
233+
lambda: {
234+
"requests": 0,
235+
"tokens": 0,
236+
}
237+
),
235238
"daily_trend": defaultdict(lambda: {"tokens": 0, "requests": 0}),
236239
"weekly_comparison": {
237240
"this_week_tokens": 0,
@@ -272,9 +275,7 @@ def extract_usage_from_events(events: list[dict[str, Any]]) -> dict[str, Any]:
272275
output_tokens = usage.get("output_tokens", 0)
273276
cache_creation = usage.get("cache_creation_input_tokens", 0)
274277
cache_read = usage.get("cache_read_input_tokens", 0)
275-
total_event_tokens = (
276-
input_tokens + output_tokens + cache_creation + cache_read
277-
)
278+
total_event_tokens = input_tokens + output_tokens + cache_creation + cache_read
278279

279280
# Update totals
280281
usage_data["total_input_tokens"] += input_tokens
@@ -384,10 +385,7 @@ def format_usage_data(data: dict[str, Any]) -> dict[str, Any]:
384385
Returns:
385386
Formatted usage data with standardized keys
386387
"""
387-
total_tokens = (
388-
data.get("total_input_tokens", 0) +
389-
data.get("total_output_tokens", 0)
390-
)
388+
total_tokens = data.get("total_input_tokens", 0) + data.get("total_output_tokens", 0)
391389

392390
formatted: dict[str, Any] = {
393391
"timestamp": datetime.now().isoformat(),
@@ -444,10 +442,18 @@ def format_usage_data(data: dict[str, Any]) -> dict[str, Any]:
444442
total_requests = formatted.get("total_requests", 0)
445443
avg_tokens_per_request = total_tokens / (total_requests or 1)
446444

447-
input_cost = (formatted["total_input_tokens"] / 1_000_000) * ESTIMATED_PRICING_USD_PER_MILLION["input_tokens"]
448-
output_cost = (formatted["total_output_tokens"] / 1_000_000) * ESTIMATED_PRICING_USD_PER_MILLION["output_tokens"]
449-
cache_write_cost = (formatted["total_cache_creation_tokens"] / 1_000_000) * ESTIMATED_PRICING_USD_PER_MILLION["cache_creation_tokens"]
450-
cache_read_cost = (formatted["total_cache_read_tokens"] / 1_000_000) * ESTIMATED_PRICING_USD_PER_MILLION["cache_read_tokens"]
445+
input_cost = (formatted["total_input_tokens"] / 1_000_000) * ESTIMATED_PRICING_USD_PER_MILLION[
446+
"input_tokens"
447+
]
448+
output_cost = (
449+
formatted["total_output_tokens"] / 1_000_000
450+
) * ESTIMATED_PRICING_USD_PER_MILLION["output_tokens"]
451+
cache_write_cost = (
452+
formatted["total_cache_creation_tokens"] / 1_000_000
453+
) * ESTIMATED_PRICING_USD_PER_MILLION["cache_creation_tokens"]
454+
cache_read_cost = (
455+
formatted["total_cache_read_tokens"] / 1_000_000
456+
) * ESTIMATED_PRICING_USD_PER_MILLION["cache_read_tokens"]
451457

452458
formatted["insights"] = {
453459
"avg_tokens_per_request": avg_tokens_per_request,

src/claude_top/limits.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ def _parse_countdown(resets_at: Optional[str], now: datetime) -> str:
5656
return "unknown"
5757

5858

59-
def get_time_until_reset(first_request_time: datetime, reset_type: str = "session") -> dict[str, Any]:
59+
def get_time_until_reset(
60+
first_request_time: datetime, reset_type: str = "session"
61+
) -> dict[str, Any]:
6062
"""
6163
Calculate time until the next limit reset based on first request time.
6264
@@ -141,11 +143,9 @@ def get_usage_status(usage_data: dict[str, Any]) -> dict[str, Any]:
141143
"tier_available": True,
142144
"tier_name": tier_name,
143145
"subscription_type": subscription_type,
144-
145146
# 5-hour session window
146147
"daily_tokens_percentage": float(five_hour.get("utilization", 0.0)),
147148
"daily_reset_countdown": _parse_countdown(five_hour.get("resets_at"), now),
148-
149149
# 7-day rolling window
150150
"weekly_tokens_percentage": float(seven_day.get("utilization", 0.0)),
151151
"weekly_reset_countdown": _parse_countdown(seven_day.get("resets_at"), now),

0 commit comments

Comments
 (0)