fix: end listings quietly when the reader leaves

This commit is contained in:
Abdessamad Derraz committed 2026-10-17 20:50:22 +02:00
1 parent 6c0bcb64f1
commit 55631a2fbc
40 files changed
+155 -38

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ param(
$ErrorActionPreference = "Stop"
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
$defaultInstallSha256 = "d336ca66e88def775842bca2ed4fae67dabf1d3effcb18e84d057da78470459c"
$defaultInstallSha256 = "61ffed8fddf816c02c1b45268dfd9bfdff9daeb1da2adedf2e13d14472f8654d"
$maximumInstallerBytes = 2MB
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
$temporary = $null
+8 -1
View File
@@ -3210,4 +3210,11 @@ def _install(args: argparse.Namespace, real_stdout) -> None:
if __name__ == "__main__":
main()
# A reader that stops early (`install.py --list | head`) ends the run
# quietly instead of on a BrokenPipeError traceback.
try:
main()
sys.stdout.flush()
except BrokenPipeError:
os.dup2(os.open(os.devnull, os.O_WRONLY), sys.stdout.fileno())
sys.exit(141)
+1 -1
View File
@@ -18,7 +18,7 @@ esac
TEMP_INSTALLER=""
TEMP_DIRECTORY=""
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
DEFAULT_INSTALL_SHA256="d336ca66e88def775842bca2ed4fae67dabf1d3effcb18e84d057da78470459c"
DEFAULT_INSTALL_SHA256="61ffed8fddf816c02c1b45268dfd9bfdff9daeb1da2adedf2e13d14472f8654d"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+3 -1
View File
@@ -463,4 +463,6 @@ def main():
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -218,4 +218,6 @@ def pending(report: dict) -> list[dict]:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -1204,4 +1204,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -380,4 +380,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+17
View File
@@ -2378,3 +2378,20 @@ from dumpcatalog import ( # noqa: E402,F401
annotate_provenance,
write_provenance_snapshot,
)
def run_cli(main) -> None:
"""Run a command-line entry point to its exit status.
A reader that stops early (`verify.py --all | head`) closed the pipe
and the next write died on a BrokenPipeError traceback. Output nobody
reads any more ends the run quietly, with the status a shell gives a
writer whose reader left.
"""
try:
code = main()
sys.stdout.flush()
except BrokenPipeError:
os.dup2(os.open(os.devnull, os.O_WRONLY), sys.stdout.fileno())
sys.exit(141)
sys.exit(code)
+3 -1
View File
@@ -776,4 +776,6 @@ def main():
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -318,4 +318,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -222,4 +222,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -383,4 +383,6 @@ To check files already in place, use: python install.py --check
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -519,4 +519,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -107,4 +107,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -99,4 +99,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -4363,4 +4363,6 @@ from packresolve import ( # noqa: E402,F401
)
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -768,4 +768,6 @@ def main():
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -4028,4 +4028,6 @@ from siterender import ( # noqa: E402,F401
)
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -153,4 +153,6 @@ def main(argv: list[str] | None = None) -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -155,4 +155,6 @@ def main() -> int:
if __name__ == "__main__":
raise SystemExit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -49,4 +49,6 @@ def main():
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -141,4 +141,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -564,4 +564,6 @@ def main():
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -688,4 +688,6 @@ def main():
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -3660,4 +3660,6 @@ def _print_elided(
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -202,4 +202,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -559,4 +559,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -470,4 +470,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -210,4 +210,6 @@ def main() -> int:
if __name__ == "__main__":
raise SystemExit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -156,4 +156,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -103,4 +103,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -471,4 +471,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -900,4 +900,6 @@ def main() -> int:
if __name__ == "__main__":
raise SystemExit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -243,4 +243,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -143,4 +143,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -408,4 +408,6 @@ def main():
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -391,4 +391,6 @@ def main() -> int:
if __name__ == "__main__":
sys.exit(main())
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -292,4 +292,6 @@ def main() -> None:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+3 -1
View File
@@ -2309,4 +2309,6 @@ def _overall_summary(group_results: list[tuple[dict, list[str]]]) -> str:
if __name__ == "__main__":
main()
from common import run_cli
run_cli(main)
+23
View File
@@ -3442,5 +3442,28 @@ class MessagesSeparateWithAColon(unittest.TestCase):
self.assertEqual(found, [])
class AReaderThatLeavesEarlyIsNoCrash(unittest.TestCase):
"""`verify.py --list-emulators | head -1` ended on a BrokenPipeError
traceback; every listing and report did."""
def test_a_closed_pipe_ends_quietly(self):
proc = subprocess.Popen(
[sys.executable, "scripts/verify.py", "--list-emulators"], cwd=ROOT,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
)
proc.stdout.readline()
proc.stdout.close()
_, err = proc.communicate(timeout=120)
self.assertNotIn(b"Traceback", err)
self.assertEqual(proc.returncode, 141)
def test_every_entry_point_goes_through_run_cli(self):
plain = re.compile(r'if __name__ == "__main__":\n (main\(\)|sys\.exit\(main\(\)\))')
found = [p.name for p in sorted((ROOT / "scripts").glob("*.py"))
if plain.search(p.read_text())]
self.assertEqual(found, [])
if __name__ == "__main__":
unittest.main()