mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 03:38:23 +00:00
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>
207 lines
6.1 KiB
Python
207 lines
6.1 KiB
Python
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
|