FreeCAD / tools /lint /codespell.py
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
#!/usr/bin/env python3
import argparse
import sys
import os
import urllib.request
import logging
from utils import (
run_command,
init_environment,
write_file,
append_file,
emit_problem_matchers,
)
def download_dictionary(url, dest):
logging.info(f"Downloading dictionary from {url} to {dest}")
try:
urllib.request.urlretrieve(url, dest)
except Exception as e:
logging.error(f"Error downloading dictionary: {e}", file=sys.stderr)
sys.exit(1)
def generate_markdown_report(misspellings: int, log_file: str) -> str:
"""
Generate a Markdown report section based on the codespell results and log file.
"""
report_lines = []
if misspellings > 0:
report_lines.append(
f"<details><summary>:pencil2: Codespell found {misspellings} misspellings</summary>"
)
else:
report_lines.append(
"<details><summary>:heavy_check_mark: Codespell found no misspellings</summary>"
)
report_lines.append("")
report_lines.append(
"To ignore false positives, append the word to the [.github/codespellignore]"
"(https://github.com/FreeCAD/FreeCAD/blob/master/.github/codespellignore) file (lowercase)"
)
report_lines.append("````")
with open(log_file, "r", encoding="utf-8") as lf:
report_lines.append(lf.read())
report_lines.append("````")
report_lines.append("</details>")
report_lines.append("")
return "\n".join(report_lines)
def main():
parser = argparse.ArgumentParser(
description="Run codespell on files and append a Markdown report."
)
parser.add_argument(
"--files",
action="extend",
nargs="+",
required=True,
help="List of files to spell check."
)
parser.add_argument(
"--ignore-words",
required=True,
help="Comma-separated list of words to ignore (from codespellignore).",
)
parser.add_argument(
"--log-dir",
required=True,
help="Directory to store the log file."
)
parser.add_argument(
"--report-file",
required=True,
help="Name of the report file."
)
parser.add_argument(
"--skip", required=True, help="Comma-separated list of file patterns to skip."
)
parser.add_argument(
"--verbose",
action='store_true',
help="Use verbose output."
)
args = parser.parse_args()
init_environment(args)
dictionary_file = "dictionary.txt"
if not os.path.exists(dictionary_file):
dictionary_url = "https://raw.githubusercontent.com/codespell-project/codespell/master/codespell_lib/data/dictionary.txt"
logging.info("Dictionary not found; downloading...")
download_dictionary(dictionary_url, dictionary_file)
run_command(["pip", "install", "-q", "codespell"], check=True)
cmd = [
"codespell",
"--quiet-level",
"3",
"--summary",
"--count",
"--ignore-words",
args.ignore_words,
"--skip",
args.skip,
"-D",
dictionary_file,
] + args.files
stdout, stderr, _ = run_command(cmd)
output = stdout + "\n" + stderr + "\n"
log_file = os.path.join(args.log_dir, "codespell.log")
write_file(log_file, output)
emit_problem_matchers(log_file, "codespell.json", "codespell")
try:
misspellings = int(stdout.strip())
except ValueError:
logging.info(f"Could not parse misspellings count from output:\n{stdout}")
misspellings = 0
logging.info(f"Found {misspellings} misspellings")
report = generate_markdown_report(misspellings, log_file)
append_file(args.report_file, report + "\n")
sys.exit(0 if misspellings == 0 else 1)
if __name__ == "__main__":
main()