85 lines
3.0 KiB
Python
85 lines
3.0 KiB
Python
"""`dashboard` CLI subcommand (spec §5, task t_b38e9af2).
|
|
|
|
Wires the dashboard server into the shared `scraper/cli.py` ADDITIVELY +
|
|
DEFENSIVELY, mirroring parser/correlate/analyze (the guarded `register()`
|
|
pattern): `cli.py` calls `register(sub)` inside a try/except and adds its
|
|
handler without touching any sibling handler. The `dashboard` name does not
|
|
collide.
|
|
|
|
This is the CLI/app entry point per the task contract. The server itself lives
|
|
in `scraper/dashboard/server.py`; this module just parses flags and calls
|
|
`server.serve(...)`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from .. import relational
|
|
from . import server as _server
|
|
|
|
log = logging.getLogger("scraper.dashboard_cli")
|
|
|
|
|
|
def _already_registered(sub, name: str) -> bool:
|
|
actions = getattr(sub, "_choices_actions", [])
|
|
return any(getattr(a, "name", None) == name for a in actions)
|
|
|
|
|
|
def register(sub) -> None:
|
|
"""Register the `dashboard` subcommand (guarded — skip if a sibling owns it)."""
|
|
if _already_registered(sub, "dashboard"):
|
|
return
|
|
pd = sub.add_parser(
|
|
"dashboard",
|
|
help="serve the legislative dashboard (API + static UI)",
|
|
description=("Serve the legislative dashboard. Reads the relational DB "
|
|
"(bills/committees/members + bill_tags) and serves the "
|
|
"API_CONTRACT.md endpoints + the static frontend."),
|
|
)
|
|
pd.add_argument("--host", default="127.0.0.1",
|
|
help="bind host (default 127.0.0.1)")
|
|
pd.add_argument("--port", type=int, default=8000,
|
|
help="bind port (default 8000)")
|
|
pd.add_argument("--db", default=relational.DEFAULT_DB,
|
|
help="SQLite path (default db/daily_file.sqlite)")
|
|
pd.add_argument("--prefs", default="out/prefs.json",
|
|
help="preferences JSON file (default out/prefs.json)")
|
|
pd.add_argument("--auth", default="out/auth.json",
|
|
help="local-auth JSON file (default out/auth.json)")
|
|
pd.add_argument("--no-static", dest="static", action="store_false",
|
|
help="API only, no static frontend")
|
|
pd.add_argument("--log", action="store_true",
|
|
help="log HTTP requests to stderr")
|
|
pd.set_defaults(func=handle_dashboard)
|
|
|
|
|
|
def handle_dashboard(args) -> int:
|
|
"""CLI handler for the `dashboard` subcommand."""
|
|
return _server.serve(
|
|
host=args.host,
|
|
port=args.port,
|
|
db_path=args.db,
|
|
prefs_path=args.prefs,
|
|
auth_path=args.auth,
|
|
serve_static=getattr(args, "static", True),
|
|
log_on=getattr(args, "log", False),
|
|
)
|
|
|
|
|
|
def main(argv=None) -> int:
|
|
"""Direct invocation: `python -m scraper.dashboard_cli`."""
|
|
import argparse
|
|
p = argparse.ArgumentParser(
|
|
prog="scraper.dashboard_cli",
|
|
description="Serve the legislative dashboard.")
|
|
sub = p.add_subparsers(dest="command", required=True)
|
|
register(sub)
|
|
args = p.parse_args(argv)
|
|
return args.func(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
sys.exit(main())
|