fablazing-cli 0.1.1__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fablazing_cli-0.2.1/CHANGELOG.md +27 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/PKG-INFO +8 -1
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/README.md +7 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/pyproject.toml +1 -1
- fablazing_cli-0.2.1/src/fablazing_cli/__init__.py +1 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/commands/auth.py +8 -5
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/commands/matchup.py +18 -1
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/commands/meta.py +38 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/reference.py +16 -5
- fablazing_cli-0.1.1/src/fablazing_cli/__init__.py +0 -1
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/.gitignore +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/client.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/commands/__init__.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/commands/card.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/commands/hero.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/commands/tournaments.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/config.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/main.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/output.py +0 -0
- {fablazing_cli-0.1.1 → fablazing_cli-0.2.1}/src/fablazing_cli/resolve.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
- Matchup: when no card clears the tech-card significance bar (common in
|
|
6
|
+
close matchups), show the closest candidates with their scores instead
|
|
7
|
+
of an empty section
|
|
8
|
+
|
|
9
|
+
## 0.2.0
|
|
10
|
+
|
|
11
|
+
- `fabz meta matrix`: matchup matrix for the top-N heroes (win rate +
|
|
12
|
+
sample size per pairing) in a single API call
|
|
13
|
+
- `fabz auth status` now shows quota: used/remaining today, reset time,
|
|
14
|
+
burst limit
|
|
15
|
+
- Aggregated endpoints report `data_through` and their refresh schedule;
|
|
16
|
+
documented which commands are realtime vs daily in the reference
|
|
17
|
+
|
|
18
|
+
## 0.1.1
|
|
19
|
+
|
|
20
|
+
- Default API URL fixed to https://api.fablazingdata.com/api/v1
|
|
21
|
+
- Tab completion for hero names (after `--install-completion`)
|
|
22
|
+
- One-time first-run tip about installing completion
|
|
23
|
+
|
|
24
|
+
## 0.1.0
|
|
25
|
+
|
|
26
|
+
- First release: matchup, meta, hero, card, tournaments, auth, reference
|
|
27
|
+
- Table/JSON/CSV output, name-to-id resolution, shell completion support
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fablazing-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Fablazing analytics from your terminal - Flesh and Blood matchups, meta, cards, and tournaments.
|
|
5
5
|
Project-URL: Homepage, https://fablazing.com
|
|
6
6
|
Author: Fablazing
|
|
@@ -65,3 +65,10 @@ Exit codes: 0 ok, 1 api error, 2 usage error, 3 quota exceeded.
|
|
|
65
65
|
## Reference
|
|
66
66
|
|
|
67
67
|
`fablazing reference` prints the full command and data reference.
|
|
68
|
+
|
|
69
|
+
## Versioning
|
|
70
|
+
|
|
71
|
+
Semver. The JSON output shape (`schema_version`, `meta`, `data`), exit
|
|
72
|
+
codes, and existing command names/flags only change with a major version
|
|
73
|
+
bump. New commands and new response fields can appear in minor versions.
|
|
74
|
+
See CHANGELOG.md.
|
|
@@ -50,3 +50,10 @@ Exit codes: 0 ok, 1 api error, 2 usage error, 3 quota exceeded.
|
|
|
50
50
|
## Reference
|
|
51
51
|
|
|
52
52
|
`fablazing reference` prints the full command and data reference.
|
|
53
|
+
|
|
54
|
+
## Versioning
|
|
55
|
+
|
|
56
|
+
Semver. The JSON output shape (`schema_version`, `meta`, `data`), exit
|
|
57
|
+
codes, and existing command names/flags only change with a major version
|
|
58
|
+
bump. New commands and new response fields can appear in minor versions.
|
|
59
|
+
See CHANGELOG.md.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fablazing-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Fablazing analytics from your terminal - Flesh and Blood matchups, meta, cards, and tournaments."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.1"
|
|
@@ -33,11 +33,14 @@ def set_url(url: str = typer.Argument(..., help="API base URL (for self-hosted/d
|
|
|
33
33
|
|
|
34
34
|
@app.command()
|
|
35
35
|
def status():
|
|
36
|
-
"""Verify the
|
|
36
|
+
"""Verify the key and show today's usage and limits."""
|
|
37
37
|
key = api_key()
|
|
38
38
|
if not key:
|
|
39
39
|
fail("no API key configured. Run: fablazing auth set-key")
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
data = client.get("/me")["data"]
|
|
41
|
+
console.print(f"[green]OK[/green] key {data.get('key_prefix', '?')}... against {api_url()}")
|
|
42
|
+
console.print(
|
|
43
|
+
f"today: {data.get('used_today', '?')}/{data.get('daily_quota', '?')} requests used, "
|
|
44
|
+
f"{data.get('remaining_today', '?')} left, resets {data.get('resets_at_utc', '?')}"
|
|
45
|
+
)
|
|
46
|
+
console.print(f"burst limit: {data.get('burst_per_minute', '?')} requests/minute")
|
|
@@ -92,12 +92,29 @@ def matchup(
|
|
|
92
92
|
c.get("card_id", ""),
|
|
93
93
|
pct(c.get("frequency")),
|
|
94
94
|
pct(c.get("win_rate")),
|
|
95
|
-
f"
|
|
95
|
+
f"{c.get('wilson_improvement', 0) * 100:+.1f}%",
|
|
96
96
|
c.get("match_count", ""),
|
|
97
97
|
]
|
|
98
98
|
for c in tech[:top]
|
|
99
99
|
]
|
|
100
100
|
tables.append((f"{name} - tech cards (Wilson outperformers)", ["Card", "Freq", "WR", "Wilson delta", "Matches"], tech_rows))
|
|
101
|
+
candidates = data.get(f"{deck_key}_tech_candidates")
|
|
102
|
+
if not tech and candidates:
|
|
103
|
+
cand_rows = [
|
|
104
|
+
[
|
|
105
|
+
c.get("card_id", ""),
|
|
106
|
+
pct(c.get("frequency")),
|
|
107
|
+
pct(c.get("win_rate")),
|
|
108
|
+
f"{c.get('wilson_improvement', 0) * 100:+.1f}%",
|
|
109
|
+
c.get("match_count", ""),
|
|
110
|
+
]
|
|
111
|
+
for c in candidates[:top]
|
|
112
|
+
]
|
|
113
|
+
tables.append((
|
|
114
|
+
f"{name} - tech candidates (none met the significance bar)",
|
|
115
|
+
["Card", "Freq", "WR", "Wilson delta", "Matches"],
|
|
116
|
+
cand_rows,
|
|
117
|
+
))
|
|
101
118
|
|
|
102
119
|
game_length = data.get("game_length") or {}
|
|
103
120
|
turns = game_length.get("turns") or {}
|
|
@@ -74,3 +74,41 @@ def movers(
|
|
|
74
74
|
tables=[("Movers", ["Hero", "ID", "Trend", "Change", "Now", "Avg"], rows)],
|
|
75
75
|
summary=[f"[bold]Meta movers[/bold] - {format_type}/{source}, last {days}d, by {sort_by}"],
|
|
76
76
|
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@app.command()
|
|
80
|
+
def matrix(
|
|
81
|
+
format_type: str = typer.Option("cc", "--format"),
|
|
82
|
+
source: str = typer.Option("online", "--source"),
|
|
83
|
+
period: str = typer.Option("14d", "--period", help="7d | 14d | 30d"),
|
|
84
|
+
top: int = typer.Option(10, "--top", min=2, max=40, help="How many heroes"),
|
|
85
|
+
json_: bool = typer.Option(False, "--json"),
|
|
86
|
+
csv_: bool = typer.Option(False, "--csv"),
|
|
87
|
+
):
|
|
88
|
+
"""Matchup matrix for the top-N most played heroes: win rate and sample
|
|
89
|
+
size for every pairing, one API call."""
|
|
90
|
+
set_mode(json_, csv_)
|
|
91
|
+
payload = client.get(
|
|
92
|
+
"/meta/matrix",
|
|
93
|
+
{"format": format_type, "source": source, "period": period, "top": top},
|
|
94
|
+
)
|
|
95
|
+
heroes = payload["data"]["heroes"]
|
|
96
|
+
ids = [h["hero_id"] for h in heroes]
|
|
97
|
+
|
|
98
|
+
columns = ["Hero", "Games"] + ids
|
|
99
|
+
rows = []
|
|
100
|
+
for h in heroes:
|
|
101
|
+
cells = []
|
|
102
|
+
for opp in ids:
|
|
103
|
+
m = h["matchups"].get(opp)
|
|
104
|
+
cells.append(f"{m['win_rate'] * 100:.0f}%/{m['total_matches']}" if m else "-")
|
|
105
|
+
name = h.get("hero_name", h["hero_id"])
|
|
106
|
+
label = name if len(name) <= 22 else name[:20] + ".."
|
|
107
|
+
rows.append([f"{label} ({h['hero_id']})", h.get("total_matches", "")] + cells)
|
|
108
|
+
|
|
109
|
+
meta_info = payload.get("meta", {})
|
|
110
|
+
summary = [
|
|
111
|
+
f"[bold]Matchup matrix[/bold] - {format_type}/{source}/{period}, top {top}, "
|
|
112
|
+
f"cells are row-hero WR / games (data through {str(meta_info.get('data_through', '?'))[:10]})"
|
|
113
|
+
]
|
|
114
|
+
emit(payload, tables=[("Matrix", columns, rows)], summary=summary)
|
|
@@ -7,12 +7,14 @@ Terminal client for the Fablazing API: matchup stats, meta breakdowns, card
|
|
|
7
7
|
analytics and paper tournament results for competitive Flesh and Blood.
|
|
8
8
|
`fablazing` and `fabz` are the same binary.
|
|
9
9
|
|
|
10
|
-
## Auth
|
|
10
|
+
## Auth and limits
|
|
11
11
|
- `fablazing auth set-key fbl_live_...` stores your key, or set the
|
|
12
12
|
FABLAZING_API_KEY env var.
|
|
13
|
-
- `fablazing auth status`
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
- `fablazing auth status` shows usage: requests used/left today, reset
|
|
14
|
+
time, burst limit.
|
|
15
|
+
- Standard keys: 2000 requests/day, 60/minute (per-key overrides exist).
|
|
16
|
+
Every response carries X-RateLimit-Limit / -Remaining / -Reset headers.
|
|
17
|
+
Exceeding a limit exits with code 3 and a Retry-After.
|
|
16
18
|
|
|
17
19
|
## IDs and formats
|
|
18
20
|
- Hero ids look like `EVO001` (set code + number).
|
|
@@ -31,8 +33,15 @@ analytics and paper tournament results for competitive Flesh and Blood.
|
|
|
31
33
|
Teklovossen) are stored under their base hero id, with transform stats
|
|
32
34
|
in deck1_transform / deck2_transform.
|
|
33
35
|
- Tech cards are Wilson-scored against the matchup baseline, so a lucky
|
|
34
|
-
streak on a small sample doesn't make the list.
|
|
36
|
+
streak on a small sample doesn't make the list. In close matchups no
|
|
37
|
+
card may clear the bar - then `tech_candidates` lists the closest
|
|
38
|
+
near-misses with their scores, explicitly marked below-threshold.
|
|
35
39
|
- Tournament standings and decklists come from official paper events.
|
|
40
|
+
- Freshness: `matchup` queries live match data (ingested every ~5
|
|
41
|
+
minutes). Meta snapshot/movers and card trends/popular are daily
|
|
42
|
+
aggregates (previous day processed at 03:00 / 02:00 UTC) - their
|
|
43
|
+
responses carry `data_through` in meta so you can see exactly how
|
|
44
|
+
fresh the numbers are.
|
|
36
45
|
|
|
37
46
|
## Commands
|
|
38
47
|
- `fablazing matchup EVO001 "Jarl" --days 30`
|
|
@@ -41,6 +50,8 @@ analytics and paper tournament results for competitive Flesh and Blood.
|
|
|
41
50
|
cards only, not equipment). `--no-dynamics` skips game length stats.
|
|
42
51
|
- `fablazing meta snapshot --format cc --days 14`
|
|
43
52
|
- `fablazing meta movers --days 14`
|
|
53
|
+
- `fablazing meta matrix --top 10` - win rate + sample size for every
|
|
54
|
+
pairing of the top-N heroes, in one call (never loop matchup for this)
|
|
44
55
|
- `fablazing hero list` / `hero show EVO001`
|
|
45
56
|
- `fablazing hero aggregate EVO001 --period 14d --source online`
|
|
46
57
|
- `fablazing card search "sink"` / `card show sink_below_red`
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|