diff --git a/.codespellrc b/.codespellrc index a39b898a278..2c08ba8272e 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] -skip = *.pdf,*.grb,*.bib,*.bst,./src/Utilities/Libraries/*,./utils/mf5to6/* +skip = *.pdf,*.grb,*.bib,*.bst,*.log,./src/Utilities/Libraries/*,./utils/mf5to6/* ignore-words = .codespell.ignore diff --git a/.github/common/check_spelling.py b/.github/common/check_spelling.py deleted file mode 100644 index 25a3e347482..00000000000 --- a/.github/common/check_spelling.py +++ /dev/null @@ -1,133 +0,0 @@ -import argparse -import os -import sys -import timeit -from itertools import repeat -from queue import Empty -from pathlib import Path -from subprocess import run -from multiprocessing import cpu_count, Pool, Manager - -PROJ_ROOT = Path(__file__).parents[2] - -# exclude these directories from checks -excludedirs = [ - PROJ_ROOT / ".pixi", - PROJ_ROOT / "autotest" / ".pytest_cache", - PROJ_ROOT / "src" / "Utilities" / "Libraries", - PROJ_ROOT / "srcbmi" / "latex", - PROJ_ROOT / "utils" / "mf5to6", -] - -# exclude these files from checks -excludefiles = [] - -# commands -codespell_cmds = ["codespell"] - - -def excluded(path) -> bool: - path = Path(path) - for f in excludefiles: - if os.path.exists(f) and os.path.samefile(path, f): - return True - for d in excludedirs: - if os.path.exists(d) and path.is_relative_to(d): - return True - return False - - -def check_spelling(path, lock, checks, failures, write_changes=False, verbose=False): - path = Path(path) - if verbose: - print(f"Checking spelling: {path}") - - cmds = codespell_cmds.copy() - if write_changes: - cmds.append("-w") - cmds.append(path) - result = run(cmds, capture_output=True) - if result.returncode != 0: - failures.put(path) - - with lock: - checks.value += 1 - - -def report(checks, failures, duration: float) -> bool: - def pop(q): - return q.get(block=False) - - n_failures = failures.qsize() - success = n_failures == 0 - print(f"Checked spelling for {checks.value} files in {duration:.4f}s") - - if n_failures > 0: - success = False - stats = f"failures: {n_failures} \\" - hr = "".join(repeat("_", len(stats) - 1)) - print(f"{hr}\n{stats}") - while True: - try: - print(f"{' '.join(codespell_cmds)} {pop(failures)}") - except Empty: - break - - print() - return success - - -if __name__ == "__main__": - start = timeit.default_timer() - parser = argparse.ArgumentParser("MODFLOW 6 spell check verification") - parser.add_argument( - "-p", - "--path", - help="path to file or directory", - default=PROJ_ROOT, - ) - parser.add_argument( - "-e", - "--extension", - help="file extensions to check", - action="append", - default=[".[fF]9[05]", ".dfn", ".tex", ".md", ".py"], - ) - parser.add_argument( - "-w", - "--write-changes", - help="write changes in place if possible", - action="store_true", - default=False, - ) - parser.add_argument( - "-v", "--verbose", action="store_true", help="verbose", default=False - ) - args = parser.parse_args() - path = Path(args.path).expanduser().absolute() - assert path.exists(), f"Path not found: {path}" - extensions = args.extension - write = args.write_changes - verbose = args.verbose - - # shared state - manager = Manager() - lock = manager.Lock() - checks = manager.Value("checks", 0) - failures = manager.Queue() - - if path.is_file(): - check_spelling(path, lock, checks, failures, write, verbose) - else: - with Pool(cpu_count()) as pool: - files = [] - for ext in extensions: - files.extend([str(p) for p in path.rglob(f"*{ext}") if not excluded(p)]) - if verbose: - msg = f"Checking {len(files)} files in directory: {path}" - print(msg) - print("".join(repeat("-", len(msg)))) - pool.starmap(check_spelling, [(f, lock, checks, failures, write, verbose) for f in files]) - - stop = timeit.default_timer() - sys.exit(0 if report(checks, failures, stop - start) else 1) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b6ce680cbbb..fbbc193226b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -566,7 +566,7 @@ { "label": "Check spelling", "type": "shell", - "command": "python .github/common/check_spelling.py", + "command": "codespell", "options": {"cwd": "${workspaceFolder}"}, "group": { "kind": "build", diff --git a/DEVELOPER.md b/DEVELOPER.md index 5bf301e8c56..d69faf65ae6 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -361,26 +361,19 @@ pixi run build builddir Fortran source files, python files, definition files, markdown, and LaTeX files can be checked with [codespell](https://github.com/codespell-project/codespell). codespell was designed primarily for checking misspelled words in source code, but it can be used with other text files as well. The `codespell` package is included in the Conda `environment.yml` and the Pixi `pixi.toml` files and can be run directly, via Pixi, or via [VSCode](.vscode/README.md) tasks. -For instance, to format a single file: - -```shell -python .github/common/check_spelling.py -p ./utils/zonebudget/src/zbud6.f90 --write-changes -``` -When run in this way, the tool will modify the file in place. If unresolvable errors are encountered, these are written to standard output and must be manually fixed before attempting to rerun the tool. - To check whether the repository's Fortran source files, python files, definition files, markdown, and LaTeX files have any spelling errors without making any changes: ```shell -python .github/common/check_spelling.py +pixi run check-spelling ``` -or using pixi: +Or, from an environment with `codespell` installed, simply ```shell -pixi run check-spelling +codespell ``` -To fix spelling errors in all files, add the `--write-changes` flag to the end of the python or pixi commands. +To fix spelling errors in all files, use `-w` (`--write-changes`). When run in this way, the tool will modify the file in place. If unresolvable errors are encountered, these are written to standard output and must be manually fixed before attempting to rerun the tool. **Note**: Spell checking by codespell may make unwanted changes (for example, a variable name in source code). As a result, you should check the `codespell` changes. codespell can be forced to leave a particular word unchanged by adding it to the `.codespell.ignore` file. diff --git a/pixi.toml b/pixi.toml index 5af1c4c3e51..6ee06b92fb7 100644 --- a/pixi.toml +++ b/pixi.toml @@ -76,7 +76,7 @@ install = { depends_on = [ # check format check-format = "python .github/common/check_format.py" check-vfproj = "python .github/common/check_vfproj.py" -check-spelling = "python .github/common/check_spelling.py" +check-spelling = "codespell" check-python-lint = { cmd = "ruff check ." } check-python-format = { cmd = "pixi run fix-python-format --check" }