# Tools for A Feminist Audit of Pop Music. # Copyright 2026 imacat. All rights reserved. # Authors: # imacat@mail.imacat.idv.tw (imacat), 2026/7/31 # AI assistance: Claude Code (Anthropic) """The package-level command-line entry point. Dispatches ``python -m pop_fem_audit_tools `` or the console script ``pop-fem-audit-tools `` to the main function of the corresponding tool module. """ import os.path import sys from collections.abc import Callable from importlib.machinery import ModuleSpec from types import ModuleType from .commands import ( build_db_command, cluster_keywords_command, export_llm_input_command, fetch_artists_command, fetch_lyrics_command, run_llm_command, tally_codings_command, ) MODULE_PROG: str = "python -m pop_fem_audit_tools" """The program name when run with ``python -m``.""" SUBCOMMANDS: dict[str, Callable[[list[str] | None], int]] = { "build-db": build_db_command, "cluster-keywords": cluster_keywords_command, "export-llm-input": export_llm_input_command, "fetch-artists": fetch_artists_command, "fetch-lyrics": fetch_lyrics_command, "run-llm": run_llm_command, "tally-codings": tally_codings_command, } """The dispatch table from the subcommand name to the tool main.""" def prog() -> str: """Return the program name shown in the usage messages. :return: ``python -m pop_fem_audit_tools`` when run with ``python -m``, or the basename of ``sys.argv[0]`` when run as a console script. """ if sys.argv[0].endswith("__main__.py"): return MODULE_PROG return os.path.basename(sys.argv[0]) def usage() -> str: """Return the usage text listing the available subcommands. :return: The usage text. """ lines: list[str] = [ f"usage: {prog()} [...]", "", "subcommands:"] lines.extend(f" {x}" for x in SUBCOMMANDS) return "\n".join(lines) def main(argv: list[str] | None = None) -> int: """Dispatch a subcommand to its tool module. :param argv: The command-line arguments, or None for ``sys.argv``. :return: The exit status: the status of the subcommand, 0 for the usage help, or non-zero on a usage error. """ args: list[str] = sys.argv[1:] if argv is None else argv if len(args) == 0: print("error: missing subcommand", file=sys.stderr) print(usage(), file=sys.stderr) return 2 if args[0] in ("-h", "--help"): print(usage()) return 0 if args[0] not in SUBCOMMANDS: print(f"error: unknown subcommand \"{args[0]}\"", file=sys.stderr) print(usage(), file=sys.stderr) return 2 prog_backup: str = sys.argv[0] main_module: ModuleType = sys.modules["__main__"] spec_backup: ModuleSpec | None = main_module.__spec__ sys.argv[0] = f"{prog()} {args[0]}" main_module.__spec__ = None try: return SUBCOMMANDS[args[0]](args[1:]) finally: sys.argv[0] = prog_backup main_module.__spec__ = spec_backup if __name__ == "__main__": sys.exit(main())