fablazing-cli 0.1.0__tar.gz → 0.1.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.
Files changed (19) hide show
  1. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/PKG-INFO +1 -1
  2. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/pyproject.toml +1 -1
  3. fablazing_cli-0.1.1/src/fablazing_cli/__init__.py +1 -0
  4. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/commands/hero.py +2 -2
  5. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/commands/matchup.py +2 -2
  6. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/config.py +1 -1
  7. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/main.py +26 -1
  8. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/resolve.py +17 -0
  9. fablazing_cli-0.1.0/src/fablazing_cli/__init__.py +0 -1
  10. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/.gitignore +0 -0
  11. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/README.md +0 -0
  12. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/client.py +0 -0
  13. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/commands/__init__.py +0 -0
  14. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/commands/auth.py +0 -0
  15. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/commands/card.py +0 -0
  16. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/commands/meta.py +0 -0
  17. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/commands/tournaments.py +0 -0
  18. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/output.py +0 -0
  19. {fablazing_cli-0.1.0 → fablazing_cli-0.1.1}/src/fablazing_cli/reference.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fablazing-cli
3
- Version: 0.1.0
3
+ Version: 0.1.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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fablazing-cli"
7
- version = "0.1.0"
7
+ version = "0.1.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.1.1"
@@ -25,7 +25,7 @@ def list_heroes(
25
25
 
26
26
  @app.command()
27
27
  def show(
28
- hero: str = typer.Argument(..., help="Hero id or name"),
28
+ hero: str = typer.Argument(..., help="Hero id or name", autocompletion=resolve.complete_hero),
29
29
  json_: bool = typer.Option(False, "--json"),
30
30
  csv_: bool = typer.Option(False, "--csv"),
31
31
  ):
@@ -44,7 +44,7 @@ def show(
44
44
 
45
45
  @app.command()
46
46
  def aggregate(
47
- hero: str = typer.Argument(..., help="Hero id or name"),
47
+ hero: str = typer.Argument(..., help="Hero id or name", autocompletion=resolve.complete_hero),
48
48
  format_type: str = typer.Option("cc", "--format"),
49
49
  source: str = typer.Option("online", "--source", help="online | paper"),
50
50
  period: str = typer.Option("14d", "--period", help="7d | 14d | 30d"),
@@ -8,8 +8,8 @@ from ..output import emit, pct, set_mode
8
8
 
9
9
 
10
10
  def matchup(
11
- hero1: str = typer.Argument(..., help="Deck 1 hero (id or name)"),
12
- hero2: str = typer.Argument(..., help="Deck 2 hero (id or name)"),
11
+ hero1: str = typer.Argument(..., help="Deck 1 hero (id or name)", autocompletion=resolve.complete_hero),
12
+ hero2: str = typer.Argument(..., help="Deck 2 hero (id or name)", autocompletion=resolve.complete_hero),
13
13
  format_type: str = typer.Option("cc", "--format"),
14
14
  days: int = typer.Option(30, "--days", min=1, max=365),
15
15
  start_date: str = typer.Option(None, "--start", help="YYYY-MM-DD (overrides --days)"),
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
  from platformdirs import user_cache_dir, user_config_dir
7
7
 
8
8
  APP_NAME = "fablazing"
9
- DEFAULT_API_URL = "https://fablazing.com/api/v1"
9
+ DEFAULT_API_URL = "https://api.fablazingdata.com/api/v1"
10
10
 
11
11
 
12
12
  def config_path() -> Path:
@@ -1,10 +1,14 @@
1
1
  """Fablazing CLI entry point. `fablazing` and `fabz` both land here."""
2
+ import os
3
+ import sys
4
+
2
5
  import typer
3
6
 
4
7
  from . import __version__
5
8
  from .commands import auth, card, hero, meta, tournaments
6
9
  from .commands.matchup import matchup
7
- from .output import console
10
+ from .config import load_config, save_config
11
+ from .output import console, err_console
8
12
  from .reference import REFERENCE
9
13
 
10
14
  app = typer.Typer(
@@ -17,6 +21,27 @@ app = typer.Typer(
17
21
  context_settings={"help_option_names": ["-h", "--help"]},
18
22
  )
19
23
 
24
+ @app.callback()
25
+ def _main():
26
+ _completion_tip()
27
+
28
+
29
+ def _completion_tip():
30
+ """One-time hint about tab completion. Skipped during shell completion
31
+ itself and when not on a terminal."""
32
+ if any(k.endswith("_COMPLETE") for k in os.environ):
33
+ return
34
+ cfg = load_config()
35
+ if cfg.get("completion_tip_shown") or not sys.stderr.isatty():
36
+ return
37
+ err_console.print(
38
+ "[dim]tip: run `fablazing --install-completion` once to enable tab "
39
+ "completion (takes effect in a new terminal)[/dim]"
40
+ )
41
+ cfg["completion_tip_shown"] = True
42
+ save_config(cfg)
43
+
44
+
20
45
  app.add_typer(auth.app, name="auth")
21
46
  app.add_typer(hero.app, name="hero")
22
47
  app.add_typer(meta.app, name="meta")
@@ -61,6 +61,23 @@ def hero_id(text: str) -> str:
61
61
  fail(f"ambiguous hero '{text}' - did you mean: {options}", 2)
62
62
 
63
63
 
64
+ def complete_hero(incomplete: str):
65
+ """Tab completion for hero arguments. Reads the local cache only; a
66
+ completer must never hit the network or it makes TAB feel broken."""
67
+ path = cache_path(_HEROES_CACHE_FILE)
68
+ try:
69
+ heroes = json.loads(path.read_text(encoding="utf-8"))["heroes"]
70
+ except (OSError, ValueError, KeyError):
71
+ return
72
+ query = incomplete.lower()
73
+ for h in heroes:
74
+ name = h.get("hero_name", "")
75
+ if name.lower().startswith(query):
76
+ yield (name, h["hero_id"])
77
+ elif h["hero_id"].lower().startswith(query):
78
+ yield (h["hero_id"], name)
79
+
80
+
64
81
  def card_id(text: str, allow_spec: bool = False) -> str:
65
82
  """Resolve a card name or id; optionally preserve a :gte2-style suffix."""
66
83
  candidate = text.strip()
@@ -1 +0,0 @@
1
- __version__ = "0.1.0"
File without changes
File without changes