Files
computer-playbook/cli/core/help.py
T
kevinveenbirkenbachandClaude Opus 4.7 26ef3ff504 chore(ruff): enable strict ruleset (E/F/I/B/UP, py311) — 2819 → 0
Adds ``[tool.ruff.lint]`` with ``select = ["E", "F", "I", "B", "UP"]``
and ``target-version = "py311"``. ``E501`` is ignored because
``ruff format`` already reflows what it can; the remaining long lines
are unsplittable string literals / URLs.

Auto-fixed (2753 issues, behavior-preserving):
- UP006/UP035: ``List[X]`` → ``list[X]``, ``Dict[X]`` → ``dict[X]``,
  ``from typing import …`` redirected where superseded by builtins.
- UP045: ``Optional[X]`` → ``X | None``.
- UP010/UP009/UP015: dropped Python-2-era pragmas (``from __future__
  import absolute_import, division, print_function``,
  ``# -*- coding: utf-8 -*-``), redundant ``open(..., "r")`` mode.
- UP004: dropped implicit ``class X(object):``.
- UP022/UP008/UP032: stdlib idiom modernization (``capture_output``,
  super-call simplification, etc.).
- B905: ``zip(...)`` → ``zip(..., strict=False)`` (preserves prior
  behavior; switching to ``strict=True`` is a separate semantic
  choice not made here).
- I001: import-block ordering.

Hand-fixed (66 issues):
- B904 × 54: appended ``from <bound>`` (when the enclosing ``except``
  binds a name) or ``from None`` (when it doesn't) so chained
  exceptions stay distinguishable from errors-during-exception-
  handling. Applied via a small AST-aware script that walked back to
  the enclosing ``except`` clause and matched the binding.
- B017 × 4: narrowed broad ``assertRaises(Exception)`` to the actual
  ``AnsibleError`` / ``AnsibleFilterError`` raised by the code under
  test.
- B023 × 2: bound captured loop variables via default args
  (``def _record(name, *, _path_real=path_real, ...)``) so each
  closure gets its own snapshot.
- B007 × 2: unused loop control variables renamed to ``_`` /
  rewritten to ``.values()``.
- UP007 × 2: ``Union[X, Y]`` → ``X | Y`` (plus dropping the now-unused
  ``from typing import Union``).
- B018 × 1: Odoo addon manifests are bare dict expressions at module
  level by design — suppressed with an inline ``# noqa: B018`` and
  rationale comment.
- UP031 × 1: printf-style format → f-string.

The 65 ``# noqa: …`` markers introduced by the auto-fixer all carry
real ruff codes (``B018``, ``E402``, ``F401``, etc.), so
``test_noqa_only_ruff_codes`` stays green.

Verification
============
- ``ruff check .`` → All checks passed
- ``ruff format --check .`` → 894 files already formatted
- ``tests.lint.repository.{test_project_root_import,
  test_no_direct_yaml_calls, test_noqa_only_ruff_codes}`` and
  ``tests.unit.utils.annotations.test_suppress`` → 20 tests OK
- 1621 unit tests → all pass
- Integration suite: 44 failures (pre-existing baseline, none from
  this change), 1 skipped.

Going forward, the new rules block regressions on E (style), F
(pyflakes), I (import order), B (likely-bug patterns), and UP
(modernization to py311) for any new code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:57:20 +02:00

207 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
import subprocess
import sys
import textwrap
from pathlib import Path
from cli.core.colors import Fore, Style, color_text
from cli.core.discovery import discover_commands
def format_command_help(
name: str, description: str, indent: int = 2, col_width: int = 36, width: int = 80
) -> str:
prefix = " " * indent + f"{name:<{col_width - indent}}"
wrapper = textwrap.TextWrapper(
width=width, initial_indent=prefix, subsequent_indent=" " * col_width
)
return wrapper.fill(description)
def extract_description_via_help(module: str) -> str:
"""
Best-effort: run "python -m <module> --help" and extract the first paragraph after usage.
"""
try:
result = subprocess.run(
[sys.executable, "-m", module, "--help"],
capture_output=True,
text=True,
check=False,
)
out = (result.stdout or "").splitlines()
# heuristic:
# skip usage line(s) then return first non-empty line after the first blank line
seen_usage = False
for i, line in enumerate(out):
if line.strip().startswith("usage:"):
seen_usage = True
continue
if not seen_usage:
continue
if not line.strip():
for j in range(i + 1, len(out)):
desc = out[j].strip()
if desc:
return desc
break
return "-"
except Exception:
return "-"
def print_global_help(cli_dir: Path) -> None:
commands = discover_commands(cli_dir)
print(color_text("Infinito.Nexus CLI 🦫🌐🖥️", Fore.CYAN + Style.BRIGHT))
print()
print(color_text("Your Gateway to Automated IT Infrastructure Setup", Style.DIM))
print()
print(
color_text(
"Usage: infinito "
"[--log <LOG_DIR>] "
"[--git-clean] "
"[--infinite] "
"[--help-all] "
"[-h|--help] "
"<command> [options]",
Fore.GREEN,
)
)
print()
print(color_text("Options:", Style.BRIGHT))
print(
color_text(
" --log <LOG_DIR> Log all proxied command output to <LOG_DIR>/<timestamp>.log",
Fore.YELLOW,
)
)
print(
color_text(
" --git-clean Remove all Git-ignored files before running",
Fore.YELLOW,
)
)
print(
color_text(
" --infinite Run the proxied command in an infinite loop",
Fore.YELLOW,
)
)
print(
color_text(
" --help-all Show full --help for all CLI commands", Fore.YELLOW
)
)
print(
color_text(" -h, --help Show this help message and exit", Fore.YELLOW)
)
print()
print(color_text("Available commands:", Style.BRIGHT))
print()
current_folder: str | None = None
for cmd in commands:
if cmd.folder != current_folder:
if cmd.folder:
print(color_text(f"{cmd.folder}/", Fore.MAGENTA))
print()
current_folder = cmd.folder
desc = extract_description_via_help(cmd.module)
print(color_text(format_command_help(cmd.name, desc, indent=2), ""), "\n")
print()
print(
color_text(
"🔗 You can chain subcommands by specifying nested directories,", Fore.CYAN
)
)
print(color_text(" e.g. infinito build tree", Fore.CYAN))
print(color_text(" corresponds to cli/build/tree/__main__.py.", Fore.CYAN))
print()
print(
color_text(
"Infinito.Nexus is a product of Kevin Veen-Birkenbach, https://cybermaster.space .\n",
Style.DIM,
)
)
print(
color_text("Test and use productively on https://infinito.nexus .\n", Style.DIM)
)
print(
color_text(
"For commercial use, a license agreement with Kevin Veen-Birkenbach is required. \n",
Style.DIM,
)
)
print(color_text("License: https://s.infinito.nexus/license", Style.DIM))
print()
print(
color_text(
"🎉🌈 Happy IT Infrastructuring! 🚀🔧✨", Fore.MAGENTA + Style.BRIGHT
)
)
print()
def show_full_help_for_all(cli_dir: Path) -> None:
commands = discover_commands(cli_dir)
print(
color_text("Infinito.Nexus CLI – Full Help Overview", Fore.CYAN + Style.BRIGHT)
)
print()
for cmd in commands:
file_path = str(
cmd.main_path.relative_to(cli_dir.parent)
) # cli/<...>/__main__.py
print(color_text("=" * 80, Fore.BLUE + Style.BRIGHT))
print(color_text(f"Subcommand: {cmd.subcommand}", Fore.YELLOW + Style.BRIGHT))
print(color_text(f"File: {file_path}", Fore.CYAN))
print(color_text("-" * 80, Fore.BLUE))
try:
result = subprocess.run(
[sys.executable, "-m", cmd.module, "--help"],
capture_output=True,
text=True,
check=False,
)
if result.stdout:
print(result.stdout.rstrip())
if result.stderr:
print(color_text(result.stderr.rstrip(), Fore.RED))
except Exception as e:
print(color_text(f"Failed to get help for {file_path}: {e}", Fore.RED))
print()
def show_help_for_directory(cli_dir: Path, dir_parts: list[str]) -> bool:
"""
If cli/<dir_parts>/ is a directory, show commands directly below it.
"""
candidate_dir = cli_dir.joinpath(*dir_parts)
if not candidate_dir.is_dir():
return False
commands = discover_commands(cli_dir)
prefix = "/".join(dir_parts)
print(color_text(f"Overview of commands in: {prefix}", Fore.CYAN + Style.BRIGHT))
print()
shown = False
for cmd in commands:
if (cmd.folder or "") == prefix:
desc = extract_description_via_help(cmd.module)
print(color_text(format_command_help(cmd.name, desc, indent=2), ""))
shown = True
return shown