Coverage for src/signalk_cli/_cli.py: 100%
43 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-06 00:17 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-06 00:17 +0000
1"""Click helpers shared by the history and stream CLIs. Not part of the library API."""
3import contextlib
4import io
5import logging
6from collections.abc import Iterator
8import click
10from . import net
12logger = logging.getLogger("signalk_cli")
15class _ClickHandler(logging.Handler):
16 """Send library log messages to stderr as plain text, like the CLI's own messages."""
18 def emit(self, record: logging.LogRecord) -> None:
19 click.echo(self.format(record), err=True)
22def host_option(f):
23 return click.option(
24 "--host",
25 default=None,
26 envvar="SIGNALK_HOST",
27 help="SignalK server base URL. http:// added if scheme omitted. "
28 "Discovered via mDNS if omitted.",
29 )(f)
32def bare_option(f):
33 return click.option(
34 "--bare",
35 is_flag=True,
36 help="Suppress all informational messages, outputting data only.",
37 )(f)
40@contextlib.contextmanager
41def stderr_ctx(bare: bool) -> Iterator[None]:
42 """Route library log messages to stderr for one command, or discard them all if bare."""
43 handler = _ClickHandler()
44 previous_level = logger.level
45 logger.addHandler(handler)
46 logger.setLevel(logging.INFO)
47 try:
48 with (
49 contextlib.redirect_stderr(io.StringIO())
50 if bare
51 else contextlib.nullcontext()
52 ):
53 yield
54 finally:
55 logger.removeHandler(handler)
56 logger.setLevel(previous_level)
59def resolve_host(host: str | None, no_cache: bool = False) -> str:
60 """Return a normalised host URL, discovering via mDNS if none provided."""
61 if host:
62 return net.normalise_host(host)
63 if not no_cache:
64 cached = net.get_cached_host()
65 if cached:
66 click.echo(f"Using cached host: {cached}", err=True)
67 return cached
68 if net.Zeroconf is None:
69 raise click.UsageError(
70 "No host specified and mDNS discovery unavailable (zeroconf not "
71 "installed). Use --host or set SIGNALK_HOST."
72 )
73 click.echo("No host specified — searching for SignalK via mDNS...", err=True)
74 discovered = net.discover_host()
75 if not discovered:
76 raise click.UsageError(
77 "No SignalK server found via mDNS. Use --host or set SIGNALK_HOST."
78 )
79 click.echo(f"Discovered: {discovered}", err=True)
80 if not no_cache:
81 net.save_cached_host(discovered)
82 return discovered