diff --git a/CHANGELOG.md b/CHANGELOG.md index 128712e2..50556996 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ All notable changes to this project are documented in this file. long form was dead on arrival: the app-level `--version` flag shadowed it, so `build-fullmap --version ` printed the app version and exited 0 without ever running the command. The short form `-v` still works, `tablassert --version` is unchanged, and the stale - "two different `--version`s" docs warning is replaced by the rename explanation. ([#TBD](https://github.com/SkyeAv/Tablassert/pull)) + "two different `--version`s" docs warning is replaced by the rename explanation. ([#201](https://github.com/SkyeAv/Tablassert/pull/201)) ## 19.3.0 - 2026-09-29 diff --git a/src/tablassert/cli.py b/src/tablassert/cli.py index 4fe66165..edd8e54a 100644 --- a/src/tablassert/cli.py +++ b/src/tablassert/cli.py @@ -1002,14 +1002,16 @@ def validate_kgx_command( @APP.command(name="quick-map") def quick_map_command( - terms: Annotated[list[str], cyclopts.Parameter(allow_leading_hyphen=False)], + # negative="" suppresses cyclopts' auto-generated --empty-terms help row: the reset + # negation is unused noise that rendered as a phantom flag on the help page. + terms: Annotated[list[str], cyclopts.Parameter(allow_leading_hyphen=False, negative="")], *, fullmap: Annotated[Path, cyclopts.Parameter(name=["--fullmap", "-f"])], taxon: Annotated[int | None, cyclopts.Parameter(name=["--taxon", "-t"])] = 9606, - prioritize: Annotated[list[str] | None, cyclopts.Parameter(name=["--prioritize", "-p"])] = None, - avoid: Annotated[list[str] | None, cyclopts.Parameter(name=["--avoid", "-a"])] = None, - exclude_prefixes: Annotated[list[str] | None, cyclopts.Parameter(name=["--exclude-prefixes", "-ep"])] = None, - exclude_regex: Annotated[list[str] | None, cyclopts.Parameter(name=["--exclude-regex", "-er"])] = None, + prioritize: Annotated[list[str] | None, cyclopts.Parameter(name=["--prioritize", "-p"], negative="")] = None, + avoid: Annotated[list[str] | None, cyclopts.Parameter(name=["--avoid", "-a"], negative="")] = None, + exclude_prefixes: Annotated[list[str] | None, cyclopts.Parameter(name=["--exclude-prefixes", "-ep"], negative="")] = None, + exclude_regex: Annotated[list[str] | None, cyclopts.Parameter(name=["--exclude-regex", "-er"], negative="")] = None, ) -> None: """Show what fullmap entity resolution does with one or more terms, as a build would see it. @@ -1123,7 +1125,9 @@ def fail(message: str) -> NoReturn: @APP.command(name="agent") def agent( - pmc_ids: Annotated[list[str], cyclopts.Parameter(allow_leading_hyphen=False)], + # negative="" suppresses cyclopts' auto-generated --empty-pmc-ids help row, which + # rendered as a phantom REQUIRED flag on the help page. + pmc_ids: Annotated[list[str], cyclopts.Parameter(allow_leading_hyphen=False, negative="")], *, graph_configuration_file: Annotated[Path, cyclopts.Parameter(name=["--configuration-file", "-f"])], model_id: Annotated[str | None, cyclopts.Parameter(name=["--model-id", "-m"])] = None, @@ -1139,7 +1143,7 @@ def agent( judge_model: Annotated[str | None, cyclopts.Parameter(name=["--judge-model"])] = None, judge_threshold: Annotated[float | None, cyclopts.Parameter(name=["--judge-threshold"])] = None, biolink_threshold: Annotated[float, cyclopts.Parameter(name=["--biolink-threshold"])] = 0.0, - local: Annotated[list[str] | None, cyclopts.Parameter(name=["--local", "-l"])] = None, + local: Annotated[list[str] | None, cyclopts.Parameter(name=["--local", "-l"], negative="")] = None, optimize: Annotated[bool, cyclopts.Parameter(name=["--optimize", "-o"], negative="")] = False, distill: Annotated[bool, cyclopts.Parameter(name=["--distill", "-d", "-dt"], negative="")] = False, instructions_file: Annotated[Path | None, cyclopts.Parameter(name=["--instructions-file"])] = None, diff --git a/tests/test_cli_help_friendly.py b/tests/test_cli_help_friendly.py index f8669bd2..7b3dc812 100644 --- a/tests/test_cli_help_friendly.py +++ b/tests/test_cli_help_friendly.py @@ -129,6 +129,23 @@ def test_validate_kgx_help_documents_the_failure_example_cap() -> None: assert ".edges.ndjson" in text +ALL_COMMANDS = ["agent", "build-fullmap", "build-kg", "distill-export", "distill-weigh", "quick-map", "validate", "validate-kgx"] + + +def test_no_help_page_renders_a_phantom_empty_flag() -> None: + """No rendered help contains cyclopts' auto --empty-* list-negation rows. + + Why: cyclopts auto-generates an ``--empty-`` reset flag for every list + parameter and renders it as its own help row; on ``agent`` the row even carried + ``[required]``, reading as a real flag an agent must pass. List params now opt out + via ``Parameter(negative="")``, and this sweeps every command so a newly added list + parameter cannot reintroduce the noise. + """ + for command in ALL_COMMANDS: + text = render_help([command]) + assert "--empty-" not in text, f"{command} --help renders a phantom --empty-* row" + + def test_build_fullmap_babel_version_flag_binds_and_the_old_shadow_is_documented() -> None: """--babel-version selects the snapshot; the stale --version form stays app-owned.