Repository: numpy/numpy
File: tools/ci/check_c_api_usage.py (Python)

Code before:
                if not code.strip():
                    continue

                # Find all suspicious calls in non-comment code
                for m in FUNC_RX.finditer(code):
                    func = m.group(0)
                    hits.append((func, lineno, str(path), raw.rstrip("\n")))
    except FileNotFoundError:
        # File may have disappeared; ignore gracefully
        pass
    return hits


def main(argv: list[str] | None = None) -> int:
    ap = argparse.ArgumentParser(description="Borrow-ref C API linter (Python).")
    ap.add_argument(
        "--root",
        default="numpy",
        type=str,
        help="Root directory to scan (default: numpy)"
        )
    ap.add_argument(
        "--ext",
        action="append",
        default=None,
        help="File extension(s) to include (repeatable). Defaults to .c,.h,.c.src,.cpp",
    )
    ap.add_argument(
        "--exclude",
        action="append",
        default=None,
        help="Directory name(s) to exclude (repeatable). Default: pythoncapi-compat",
    )
    args = ap.parse_args(argv)

    root = Path(args.root)
    if not root.exists():
        print(f"error: root '{root}' does not exist", file=sys.stderr)
        return 2

    exts = set(args.ext) if args.ext else set(DEFAULT_EXTS)
    excludes = set(args.exclude) if args.exclude else set(DEFAULT_EXCLUDES)

    files = list(iter_source_files(root, exts, excludes))
    print(f"Scanning {len(files)} C/C++ source files...")

    # Output file (mirrors your shell behavior)
    tmpdir = Path(".tmp")
    tmpdir.mkdir(exist_ok=True)
    fd, outpath = tempfile.mkstemp(
        prefix="c_api_usage_report.",

Review comment (suggestion):
I wonder if it would make sense to just substitute the variable in directly here to avoid hardcoding the defaults in two separate locations, i.e.,

```diff
--- a/tools/ci/check_c_api_usage.py
+++ b/tools/ci/check_c_api_usage.py
@@ -148,7 +148,7 @@ def main(argv: list[str] | None = None) -> int:
         "--ext",
         action="append",
         default=None,
-        help="File extension(s) to include (repeatable). Defaults to .c,.h,.c.src,.cpp",
+        help=f"File extension(s) to include (repeatable). Defaults to {DEFAULT_EXTS}",
```

Code after:
        "PyDict_GetItemWithError",
        "PyDict_GetItemString",
        "PyDict_SetDefault",
        "PyDict_Next",
        "PyWeakref_GetObject",
        "PyWeakref_GET_OBJECT",
        "PyList_GET_ITEM",
        "_PyDict_GetItemStringWithError",
        "PySequence_Fast"
    )
    func_rx = build_func_rx(suspicious_funcs)
    noqa_markers = (
        "noqa: borrowed-ref OK",
        "noqa: borrowed-ref - manual fix needed"
        )
    default_exts = {".c", ".h", ".c.src", ".cpp"}
    default_excludes = {"pythoncapi-compat"}

    ap = argparse.ArgumentParser(description="Borrow-ref C API linter (Python).")
    ap.add_argument(
        "--quiet",
        action="store_true",
        help="Suppress normal output; exit status alone indicates result (useful\
              for CI).",
    )
    ap.add_argument(
        "-j", "--jobs",
        type=int,
        default=0,
        help="Number of worker threads (0=auto, 1=sequential).",
    )
    ap.add_argument(
        "--root",
        default="numpy",
        type=str,
        help="Root directory to scan (default: numpy)"
        )
    ap.add_argument(
        "--ext",
        action="append",
        default=None,
        help=f"File extension(s) to include (repeatable). Defaults to {default_exts}",
    )
    ap.add_argument(
        "--exclude",
        action="append",
        default=None,
        help=f"Directory name(s) to exclude (repeatable). Default: {default_excludes}",
    )
    args = ap.parse_args(argv)