cli: add __main__ guard so python -m cmos.cli actually runs

Without `if __name__ == "__main__": sys.exit(main())` at the bottom
of cli.py, `python -m cmos.cli format <path>` imports the module
but never invokes main(), so the process silently exits 0 with
empty stdout — indistinguishable from a successful run that
produced no output. Discovered during real-draft testing on
2026-04-11.

Adds a regression test that subprocesses the CLI with --help and
asserts on stdout content. argparse --help exits 0 in both broken
and fixed states; stdout content is the only discriminator.

Both invocation paths now work:
- uv run cmos format <path>                (pyproject script entry)
- uv run python -m cmos.cli format <path>  (module invocation)
This commit is contained in:
Mark Eaton
2026-04-11 17:45:18 -04:00
parent 1d970e84f9
commit 22404fbd6b
2 changed files with 37 additions and 0 deletions
+33
View File
@@ -5,6 +5,8 @@ formatter so no API calls happen; the goal is to pin the glue logic, not the
LLM behavior.
"""
import subprocess
import sys
from pathlib import Path
import pytest
@@ -68,6 +70,37 @@ def test_reformat_draft_bibliography_heading_preserved():
assert "## Bibliography" in output
def test_python_dash_m_invocation_actually_runs_main():
"""Regression test: `python -m cmos.cli` must actually invoke main().
Without an `if __name__ == "__main__"` guard at the bottom of cli.py,
`python -m cmos.cli` imports the module body but never calls main(),
so the process silently exits 0 with empty stdout. That looks
indistinguishable from a successful run that produced no output —
the worst kind of bug, since callers assume the pipeline ran. This
test forces the guard to exist by invoking the CLI as a subprocess
with --help and asserting argparse actually fired.
"""
result = subprocess.run(
[sys.executable, "-m", "cmos.cli", "--help"],
capture_output=True,
text=True,
timeout=10,
)
# argparse --help exits 0 whether or not main() ran, so the
# discriminator is the stdout content. Without main(), stdout is empty.
assert result.returncode == 0, (
f"expected exit 0, got {result.returncode}; stderr={result.stderr!r}"
)
assert result.stdout, (
"stdout was empty — `python -m cmos.cli` likely silently exited "
"without invoking main(). Check that cli.py has an "
'`if __name__ == "__main__": sys.exit(main())` guard at the bottom.'
)
assert "format" in result.stdout
assert "usage" in result.stdout.lower()
def test_reformat_draft_preserves_order_under_concurrency():
# With concurrent execution the formatter is called on all entries in
# parallel; the CLI must reassemble them in input order regardless of