#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""``docs`` subcommand (argparse flavor) + the shared execution helpers.
``_run_docs_command`` / ``_print_page_list`` / ``_get_tldr`` are shared
with ``_docs_click.py`` (the Click flavor) -- both front-ends dispatch
into the SAME execution path so behavior never drifts between the two
CLI frameworks a downstream package might choose.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
import scitex_logging as slogging
log = slogging.getLogger(__name__)
console = slogging.getConsole(f"{__name__}.console")
[docs]
def register_docs_subcommand(
subparsers: argparse._SubParsersAction,
package: str,
) -> argparse.ArgumentParser:
"""Register ``docs`` with ``list`` and ``get`` verb subcommands.
Usage::
scitex-stats docs list # List doc pages
scitex-stats docs get # Show available pages
scitex-stats docs get api # Show specific page
"""
prog = package.replace("_", "-")
parser = subparsers.add_parser(
"docs",
help=f"View documentation for {package}",
description=f"Browse and query {package} documentation.",
epilog=(
f"Examples:\n"
f" {prog} docs list # List doc pages\n"
f" {prog} docs list --json # JSON output\n"
f" {prog} docs get # Show available pages\n"
f" {prog} docs get api # Show specific page\n"
f" {prog} docs get api --json # Page as JSON\n"
),
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"--help-recursive",
action="store_true",
help="Show help for all subcommands",
)
docs_sub = parser.add_subparsers(dest="docs_command", title="Commands")
# docs list
list_p = docs_sub.add_parser(
"list",
help="List available documentation pages",
epilog=(f"Examples:\n {prog} docs list\n {prog} docs list --json\n"),
formatter_class=argparse.RawDescriptionHelpFormatter,
)
list_p.add_argument("--json", action="store_true", dest="as_json")
list_p.set_defaults(
func=lambda args: _run_docs_command(
argparse.Namespace(
list_pages=True,
page=None,
as_json=args.as_json,
tldr=False,
format=None,
),
package=package,
)
)
# docs get [page]
get_p = docs_sub.add_parser(
"get",
help="Show a documentation page",
epilog=(
f"Examples:\n"
f" {prog} docs get # show overview\n"
f" {prog} docs get api # specific page\n"
f" {prog} docs get api --json\n"
),
formatter_class=argparse.RawDescriptionHelpFormatter,
)
get_p.add_argument(
"name", nargs="?", default=None, help="Page name (see 'docs list')"
)
get_p.add_argument("--json", action="store_true", dest="as_json")
get_p.add_argument("--format", type=str, default=None, choices=["html", "json"])
get_p.set_defaults(func=lambda args: _run_docs_get(args, package=package))
# bare `docs` → show help
def _default_handler(args):
if getattr(args, "help_recursive", False):
parser.print_help()
console.info("")
for sub_name, sub_p in [("list", list_p), ("get", get_p)]:
console.info(f"--- {sub_name} ---")
sub_p.print_help()
console.info("")
return
if args.docs_command is None:
parser.print_help()
parser.set_defaults(func=_default_handler)
return parser
def _run_docs_get(args: argparse.Namespace, package: str) -> None:
"""Handle 'docs get [name]' — show page or list available pages."""
if args.name is None:
ns = argparse.Namespace(
list_pages=True,
page=None,
as_json=getattr(args, "as_json", False),
tldr=False,
format=None,
)
else:
ns = argparse.Namespace(
list_pages=False,
page=args.name,
as_json=getattr(args, "as_json", False),
tldr=False,
format=getattr(args, "format", None),
)
_run_docs_command(ns, package=package)
def _run_docs_command(args: argparse.Namespace, package: str) -> None:
"""Execute the docs subcommand."""
import logging
slogging.getLogger("scitex_dev._core.discovery").setLevel(logging.ERROR)
from ..._docs.docs import get_docs
# --tldr: concise quick-start
if args.tldr:
tldr = _get_tldr(package)
if args.as_json:
slogging.getPlainConsole(__name__).emit(
json.dumps({"package": package, "tldr": tldr}), flush=False
)
else:
console.info(tldr)
return
# Determine format. Note: page listings always use the rich manifest
# (format=None) so the text and --json paths show the same data —
# downgrading to format="json" here would drop page titles.
fmt = args.format
if args.list_pages:
fetch_fmt = None
elif args.as_json and fmt is None:
fetch_fmt = "json"
else:
fetch_fmt = fmt
try:
result = get_docs(package=package, format=fetch_fmt, page=args.page)
except LookupError as e:
log.error(str(e))
sys.exit(2)
# --list: show page index
if args.list_pages:
_print_page_list(result, as_json=args.as_json)
return
# Default output
if args.as_json:
slogging.getPlainConsole(__name__).emit(
json.dumps(result, indent=2, default=str), flush=False
)
elif isinstance(result, dict):
slogging.getPlainConsole(__name__).emit(
json.dumps(result, indent=2, default=str), flush=False
)
elif isinstance(result, Path) and result.is_file():
# --page returns a file path — print its content
console.info(result.read_text(encoding="utf-8"))
else:
console.info(result)
def _print_page_list(result, as_json: bool = False) -> None:
"""Print a page listing from a manifest or page dict."""
if isinstance(result, dict):
pages = result.get("pages", [])
if as_json:
slogging.getPlainConsole(__name__).emit(
json.dumps({"pages": pages}), flush=False
)
else:
if isinstance(pages, list) and pages and isinstance(pages[0], dict):
for p in pages:
console.info(f" {p.get('name', '?'):20s} {p.get('title', '')}")
elif isinstance(pages, list):
for name in pages:
console.info(f" {name}")
else:
console.info(" (no pages found)")
else:
console.info(result)
def _get_tldr(package: str) -> str:
"""Get a concise quick-start summary for a package.
Tries to extract from built docs, falls back to a generic template.
"""
from ..._docs.docs import get_docs
try:
result = get_docs(package=package)
except LookupError:
return f"{package}: package not found in scitex ecosystem."
# Try to find a quick-start section in the docs
if isinstance(result, dict):
description = result.get("description", "")
version = result.get("version", "?")
pages = result.get("pages", [])
page_names = [p["name"] if isinstance(p, dict) else p for p in pages[:5]]
lines = [
f"{package} v{version}",
description[:100] if description else "(no description)",
"",
f" pip install {package}",
f' python -c "import {package.replace("-", "_")}"',
]
if page_names:
lines.append("")
lines.append(f"Docs pages: {', '.join(page_names)}")
return "\n".join(lines)
return f"{package}: documentation available via get_docs(package='{package}')"
__all__ = [
"register_docs_subcommand",
"_run_docs_get",
"_run_docs_command",
"_print_page_list",
"_get_tldr",
]