File: generate_cli_reference.py

package info (click to toggle)
huggingface-hub 1.2.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,424 kB
  • sloc: python: 45,857; sh: 434; makefile: 33
file content (123 lines) | stat: -rw-r--r-- 4,389 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import argparse
import html
import io
import tempfile
from contextlib import redirect_stdout
from difflib import unified_diff
from pathlib import Path

from typer.cli import app as typer_main


PACKAGE_REFERENCE_PATH = Path(__file__).parents[1] / "docs" / "source" / "en" / "package_reference" / "cli.md"

WARNING_HEADER = """<!--
# WARNING
# This entire file has been generated by Typer based on the `hf` CLI implementation.
# To re-generate the code, run `make style` or `python ./utils/generate_cli_reference.py --update`.
# WARNING
-->"""


def print_colored_diff(expected: str, current: str) -> None:
    """Print a colored line-by-line diff between expected and current content.

    Auto-generated code by Cursor.
    """
    expected_lines = expected.splitlines(keepends=True)
    current_lines = current.splitlines(keepends=True)

    diff = unified_diff(
        current_lines, expected_lines, fromfile="Current content", tofile="Expected content", lineterm=""
    )

    for line in diff:
        line = line.rstrip("\n")
        if line.startswith("+++"):
            print(f"\033[92m{line}\033[0m")  # Green for additions
        elif line.startswith("---"):
            print(f"\033[91m{line}\033[0m")  # Red for deletions
        elif line.startswith("@@"):
            print(f"\033[96m{line}\033[0m")  # Cyan for context
        elif line.startswith("+"):
            print(f"\033[92m{line}\033[0m")  # Green for additions
        elif line.startswith("-"):
            print(f"\033[91m{line}\033[0m")  # Red for deletions
        else:
            print(line)  # Default color for context


def generate_cli_reference() -> str:
    with tempfile.TemporaryDirectory() as tmpdir:
        tmp_file = Path(tmpdir) / "cli.md"
        try:
            with redirect_stdout(io.StringIO()):  # catch and ignore typer.echo output
                typer_main(
                    [
                        "src/huggingface_hub/cli/hf.py",
                        "utils",
                        "docs",
                        "--name",
                        "hf",
                        "--output",
                        str(tmp_file),
                    ]
                )
        except SystemExit as e:
            # Typer (Click) calls sys.exit() internally, so we catch it
            if e.code not in (0, None):
                raise  # re-raise if it was an error exit

        content = tmp_file.read_text()
        # Decode HTML entities that Typer generates
        content = html.unescape(content)
        return f"{WARNING_HEADER}\n\n{content}"


def check_and_update_cli_reference(update: bool, verbose: bool = False) -> None:
    new_content = generate_cli_reference()
    if PACKAGE_REFERENCE_PATH.exists():
        existing_content = PACKAGE_REFERENCE_PATH.read_text()
        if existing_content == new_content:
            print("āœ… All good! (CLI reference)")
            return
    elif not update:
        print(
            f"āŒ `{PACKAGE_REFERENCE_PATH}` does not exist yet.\n"
            "   Please run `make style` or `python utils/generate_cli_reference.py --update` to generate it."
        )
        exit(1)

    if update:
        PACKAGE_REFERENCE_PATH.write_text(new_content)
        print(
            f"āœ… CLI reference has been updated in `{PACKAGE_REFERENCE_PATH}`.\n   Please make sure the changes are accurate and commit them."
        )
    else:
        print(
            f"āŒ Expected content mismatch in `{PACKAGE_REFERENCE_PATH}`.\n"
            "   It is most likely that you've modified the CLI implementation and did not re-generate the docs.\n"
            "   Please run `make style` or `python utils/generate_cli_reference.py --update`."
        )

        if verbose:
            print("\nšŸ“‹ Diff between current and expected content:")
            print_colored_diff(new_content, existing_content)

        exit(1)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--update",
        action="store_true",
        help=(f"Whether to re-generate `{PACKAGE_REFERENCE_PATH}` if a change is detected."),
    )
    parser.add_argument(
        "--verbose",
        action="store_true",
        help="Show detailed diff when content mismatch is detected.",
    )
    args = parser.parse_args()
    check_and_update_cli_reference(update=args.update, verbose=args.verbose)