Download src/tools/licence_headers.py from CIIL/Anuvani-Diarization: direct link, hf CLI and curl.
- Browser
- Download file 5.81 kB
-
https://huggingface.co/CIIL/Anuvani-Diarization/resolve/main/src/tools/licence_headers.py
- Command line
-
hf download hf://CIIL/Anuvani-Diarization/src/tools/licence_headers.py
-
curl -L -o licence_headers.py https://huggingface.co/CIIL/Anuvani-Diarization/resolve/main/src/tools/licence_headers.py
5.81 kB
| # Copyright (c) 2026 The Anuvani-Diarization authors | |
| # SPDX-License-Identifier: MIT OR Apache-2.0 | |
| """Add the copyright and SPDX licence lines to every source file of the release (idempotent). | |
| python3 tools/licence_headers.py [--check] | |
| Covers the git-tracked .py, .rs and .sh files, Dockerfiles, Makefiles and the `diar` command under | |
| release/anuvani_diar_rs, release/anuvani_diar_v1 and release/hub. Our files are MIT OR | |
| Apache-2.0. Files copied from other projects keep those projects' licences: verbatim copies are left as they are | |
| (their own headers say where they come from); copies with small changes get their upstream licence; files that | |
| port another project's code say so in a third line (THIRD_PARTY_NOTICES.md has the notices and the licence texts). | |
| A shebang or a coding line stays first. With --check, lists the files without a header and exits 1 if any. | |
| """ | |
| import re | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| RELEASE = Path(__file__).resolve().parents[2] | |
| TREES = ("anuvani_diar_rs", "anuvani_diar_v1", "hub") | |
| OURS = "Copyright (c) 2026 The Anuvani-Diarization authors" | |
| SPDX = "SPDX-License-Identifier: MIT OR Apache-2.0" | |
| VERBATIM = re.compile(r"(nn/seg|hf_port_poc/anuvani_diar_net)/(wav2vec2/.*|conformer\.py|wavlm_config\.py)$") | |
| # file suffix -> (copyright line, SPDX line) | |
| UPSTREAM = { | |
| "python/anuvani_diar/nn/kaldi.py": ("Copyright (c) 2017 Facebook Inc. (Soumith Chintala); copied from torchaudio 2.1.1", | |
| "SPDX-License-Identifier: BSD-2-Clause"), | |
| "python/anuvani_diar/nn/resample.py": ("Copyright (c) 2017 Facebook Inc. (Soumith Chintala); copied from torchaudio 2.1.1", | |
| "SPDX-License-Identifier: BSD-2-Clause"), | |
| "python/anuvani_diar/nn/voiceprint.py": ("Copyright (c) 2020 CNRS (pyannote.audio), (c) 2021 Shuai Wang (WeSpeaker); " | |
| "changes (c) 2026 The Anuvani-Diarization authors", | |
| "SPDX-License-Identifier: MIT AND Apache-2.0"), | |
| "nn/seg/segnet.py": ("Copyright (c) 2024 BUT Speech@FIT (DiariZen); changes (c) 2026 The Anuvani-Diarization authors", | |
| "SPDX-License-Identifier: MIT"), | |
| "hf_port_poc/anuvani_diar_net/segnet.py": ("Copyright (c) 2024 BUT Speech@FIT (DiariZen); changes (c) 2026 The " | |
| "Anuvani-Diarization authors", "SPDX-License-Identifier: MIT"), | |
| "crates/diar-core/src/vbx.rs": (OURS, "SPDX-License-Identifier: (MIT OR Apache-2.0) AND Apache-2.0"), | |
| } | |
| # file suffix -> the third line: what it ports | |
| PORTS = { | |
| "crates/diar-core/src/vbx.rs": "Ports DiariZen's VBx (diarizen/clustering/VBx.py, Apache-2.0, after BUT Speech@FIT's VBx).", | |
| "crates/diar-exact/src/hierarchy.rs": "Ports SciPy 1.15.3's hierarchical clustering (BSD-3-Clause).", | |
| "crates/diar-exact/src/assign.rs": "Ports SciPy 1.15.3's cdist cosine and linear_sum_assignment (BSD-3-Clause).", | |
| "crates/diar-exact/src/special.rs": "Ports SciPy 1.15.3's softmax and logsumexp (BSD-3-Clause).", | |
| "crates/diar-exact/src/sort.rs": "Ports NumPy 1.26.4's argsort (BSD-3-Clause).", | |
| "crates/diar-exact/src/unique.rs": "Ports NumPy 1.26.4's unique (BSD-3-Clause).", | |
| "crates/diar-exact/src/linalg.rs": "Ports NumPy 1.26.4's linalg.norm (BSD-3-Clause).", | |
| "crates/diar-exact/src/npblas.rs": "Ports NumPy 1.26.4's BLAS call sites (BSD-3-Clause).", | |
| "crates/diar-exact/src/pairwise.rs": "Ports NumPy 1.26.4's pairwise summation and reductions (BSD-3-Clause).", | |
| "crates/diar-core/src/recon.rs": "Ports pyannote.audio 3.1.1 and pyannote.core 5.0.0 (MIT, CNRS).", | |
| "crates/diar-core/src/front.rs": "Ports pyannote.audio 3.1.1's sliding-window inference and masks (MIT, CNRS).", | |
| "crates/diar-audio/src/sndfile.rs": "Reproduces python-soundfile 0.14.0's libsndfile calls (BSD-3-Clause).", | |
| } | |
| NOTE = "Notices and licence texts: THIRD_PARTY_NOTICES.md." | |
| def files(): | |
| out = [] | |
| for tree in TREES: | |
| root = RELEASE / tree | |
| listed = subprocess.run(["git", "ls-files", "-z", "."], cwd=root, capture_output=True, check=True).stdout | |
| for rel in listed.decode().split("\0"): | |
| p = root / rel | |
| if rel and p.is_file() and (p.suffix in (".py", ".rs", ".sh") or p.name in ("Dockerfile", "Makefile", "diar")): | |
| out.append(p) | |
| return sorted(out) | |
| def header_for(p): | |
| rel = str(p.relative_to(RELEASE)) | |
| if VERBATIM.search(rel): | |
| return None | |
| mark = "//" if p.suffix == ".rs" else "#" | |
| copyright_line, spdx = OURS, SPDX | |
| for suffix, (c, s) in UPSTREAM.items(): | |
| if rel.endswith(suffix): | |
| copyright_line, spdx = c, s | |
| lines = [f"{mark} {copyright_line}", f"{mark} {spdx}"] | |
| for suffix, port in PORTS.items(): | |
| if rel.endswith(suffix): | |
| lines.append(f"{mark} {port} {NOTE}") | |
| return lines | |
| def main(): | |
| check = "--check" in sys.argv | |
| missing, added = [], 0 | |
| for p in files(): | |
| lines = header_for(p) | |
| if lines is None: | |
| continue | |
| text = p.read_text() | |
| if "SPDX-License-Identifier:" in "\n".join(text.split("\n")[:6]): | |
| continue | |
| if check: | |
| missing.append(str(p.relative_to(RELEASE))) | |
| continue | |
| body = text.split("\n") | |
| keep = 0 | |
| while keep < len(body) and keep < 2 and (body[keep].startswith("#!") or re.match(r"#.*coding[:=]", body[keep])): | |
| keep += 1 | |
| p.write_text("\n".join(body[:keep] + lines + body[keep:])) | |
| added += 1 | |
| if check: | |
| print("\n".join(missing) or "every source file has a licence header") | |
| return 1 if missing else 0 | |
| print(f"headers added to {added} files") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |