feat: group multi-browser output by source
Testing / remote-protocol-compat (0.9.3) (push) Successful in 52s
Testing / test (push) Successful in 1m2s
Testing / remote-protocol-compat (0.9.5) (push) Successful in 1m0s
Package Extension / package-extension (push) Successful in 1m11s
Build & Publish Package / publish (push) Successful in 1m7s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 52s
Testing / test (push) Successful in 1m2s
Testing / remote-protocol-compat (0.9.5) (push) Successful in 1m0s
Package Extension / package-extension (push) Successful in 1m11s
Build & Publish Package / publish (push) Successful in 1m7s
- Add browser source grouping metadata to SDK-created tabs, groups, list results, and aggregate count results. - Render grouped local/remote browser tables consistently for clients, tabs, groups, windows, sessions, and remote status output. - Document remote control, auth, HTTP gateway usage, and the refreshed project structure in the README. - Add coverage for grouped output and BrowserCounts browser_groups. - Bump the Python package, extension manifest, and lockfile to 0.15.6. - Add a just publish helper for building and publishing release artifacts.
This commit is contained in:
@@ -22,60 +22,74 @@ tab_option = click.option("--tab", "tab_id", type=int, default=None, help="Tab I
|
||||
|
||||
|
||||
def gentle_mode_option(help_text: str):
|
||||
"""Reusable ``--gentle-mode`` Click option (throttle mode for large operations)."""
|
||||
return click.option(
|
||||
"--gentle-mode",
|
||||
type=click.Choice(GENTLE_MODES),
|
||||
default="auto",
|
||||
show_default=True,
|
||||
help=help_text,
|
||||
)
|
||||
"""Reusable ``--gentle-mode`` Click option (throttle mode for large operations)."""
|
||||
return click.option(
|
||||
"--gentle-mode",
|
||||
type=click.Choice(GENTLE_MODES),
|
||||
default="auto",
|
||||
show_default=True,
|
||||
help=help_text,
|
||||
)
|
||||
|
||||
def print_counts(result, noun: str, *, single_suffix: str = "") -> None:
|
||||
"""Render a count result.
|
||||
"""Render a count result.
|
||||
|
||||
In multi-browser mode (*result* is a :class:`~browser_cli.BrowserCounts`) print a
|
||||
per-browser table with a Total row; otherwise print a single ``N noun(s)`` line.
|
||||
"""
|
||||
if isinstance(result, BrowserCounts):
|
||||
table = Table(show_header=True, header_style="bold cyan")
|
||||
table.add_column("Browser")
|
||||
table.add_column(f"{noun.capitalize()}s", justify="right")
|
||||
for name, count in result.by_browser.items():
|
||||
table.add_row(name, str(count))
|
||||
table.add_row("Total", str(result.total))
|
||||
_console.print(table)
|
||||
else:
|
||||
_console.print(f"[bold]{result}[/bold] {noun}(s){single_suffix}")
|
||||
In multi-browser mode (*result* is a :class:`~browser_cli.BrowserCounts`) print a
|
||||
per-browser table with a Total row; otherwise print a single ``N noun(s)`` line.
|
||||
"""
|
||||
if isinstance(result, BrowserCounts):
|
||||
table = Table(show_header=True, header_style="bold cyan")
|
||||
table.add_column("Browser", no_wrap=True)
|
||||
table.add_column(f"{noun.capitalize()}s", justify="right")
|
||||
rendered_groups: set[str] = set()
|
||||
for name, count in result.by_browser.items():
|
||||
group = result.browser_groups.get(name)
|
||||
if group:
|
||||
if group not in rendered_groups:
|
||||
group_total = sum(
|
||||
browser_count
|
||||
for browser_name, browser_count in result.by_browser.items()
|
||||
if result.browser_groups.get(browser_name) == group
|
||||
)
|
||||
table.add_row(f"[bold]{group}[/bold]", str(group_total))
|
||||
rendered_groups.add(group)
|
||||
display_name = name.removeprefix(f"{group}:")
|
||||
table.add_row(f" {display_name}", str(count))
|
||||
else:
|
||||
table.add_row(name, str(count))
|
||||
table.add_row("Total", str(result.total))
|
||||
_console.print(table)
|
||||
else:
|
||||
_console.print(f"[bold]{result}[/bold] {noun}(s){single_suffix}")
|
||||
|
||||
def client_from_ctx() -> BrowserCLI:
|
||||
"""Build a BrowserCLI from the root context's global options.
|
||||
"""Build a BrowserCLI from the root context's global options.
|
||||
|
||||
Reads ``browser``/``remote``/``key`` set by the top-level ``main`` group.
|
||||
Falls back to an unconfigured client when a command group is invoked
|
||||
standalone (e.g. in unit tests).
|
||||
"""
|
||||
obj = click.get_current_context().find_root().obj or {}
|
||||
return BrowserCLI(browser=obj.get("browser"), remote=obj.get("remote"), key=obj.get("key"))
|
||||
Reads ``browser``/``remote``/``key`` set by the top-level ``main`` group.
|
||||
Falls back to an unconfigured client when a command group is invoked
|
||||
standalone (e.g. in unit tests).
|
||||
"""
|
||||
obj = click.get_current_context().find_root().obj or {}
|
||||
return BrowserCLI(browser=obj.get("browser"), remote=obj.get("remote"), key=obj.get("key"))
|
||||
|
||||
def handle_errors(fn):
|
||||
"""Decorate a CLI command so SDK exceptions become clean errors + exit(1).
|
||||
"""Decorate a CLI command so SDK exceptions become clean errors + exit(1).
|
||||
|
||||
Apply as the innermost decorator (directly above ``def``) so Click's option
|
||||
decorators attach their params to the wrapper.
|
||||
"""
|
||||
@functools.wraps(fn)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return fn(*args, **kwargs)
|
||||
except BrowserNotConnected as e:
|
||||
_console.print(f"[red]Error:[/red] {e}")
|
||||
raise SystemExit(1)
|
||||
except PermissionError as e:
|
||||
_console.print(f"[red]Blocked:[/red] {e}")
|
||||
raise SystemExit(1)
|
||||
except RuntimeError as e:
|
||||
_console.print(f"[red]Browser error:[/red] {e}")
|
||||
raise SystemExit(1)
|
||||
Apply as the innermost decorator (directly above ``def``) so Click's option
|
||||
decorators attach their params to the wrapper.
|
||||
"""
|
||||
@functools.wraps(fn)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return fn(*args, **kwargs)
|
||||
except BrowserNotConnected as e:
|
||||
_console.print(f"[red]Error:[/red] {e}")
|
||||
raise SystemExit(1)
|
||||
except PermissionError as e:
|
||||
_console.print(f"[red]Blocked:[/red] {e}")
|
||||
raise SystemExit(1)
|
||||
except RuntimeError as e:
|
||||
_console.print(f"[red]Browser error:[/red] {e}")
|
||||
raise SystemExit(1)
|
||||
|
||||
return wrapper
|
||||
return wrapper
|
||||
|
||||
Reference in New Issue
Block a user