Summary
tina4 test (the CLI _test command) runs pytest but discards its exit code, so the command
always exits 0 — even when tests fail. Any CI or pre-push gate that relies on tina4 test's exit
status (tina4 test || exit 1) silently passes on a red suite, letting broken code through to
production.
Affected code
tina4_python/cli/__init__.py::_test, on both branches:
v3 (default / release branch):
def _test(args):
"""Run the test suite."""
subprocess.run([sys.executable, "-m", "pytest", "tests/"] + args)
main:
def _test(args):
"""Run the test suite."""
import subprocess
cmd = [sys.executable, "-m", "pytest", "tests/"] + args
subprocess.run(cmd)
Neither inspects result.returncode nor calls sys.exit(...), so the function returns None and the
CLI exits 0 regardless of the pytest result. Contrast _build a few lines below, which does it right:
result = subprocess.run([docker, "build", ...])
if result.returncode != 0:
sys.exit(result.returncode)
Reproduction
tina4-python 3.13.75 (also reproduced by reading 3.13.78 / current v3 + main), Windows, Python 3.12.2, pytest 9.1.1:
- Add a failing test under
tests/: def test_x(): assert False
- Run
tina4 test — it prints 1 failed, N passed but the exit code is 0.
- Run
python -m pytest tests/ on the same tree — exit code is 1.
$ tina4 test -k some_failing_test ; echo "exit=$?"
...
====================== 1 failed, 336 deselected in 0.33s ======================
exit=0 # <-- should be non-zero
$ python -m pytest tests/ -k some_failing_test ; echo "exit=$?"
...
====================== 1 failed, 336 deselected in 0.33s ======================
exit=1 # correct
Fix (one line)
Propagate pytest's exit code:
def _test(args):
"""Run the test suite."""
result = subprocess.run([sys.executable, "-m", "pytest", "tests/"] + args)
sys.exit(result.returncode)
Happy to open a PR against v3 (and main) if that helps.
Impact
Real-world: a project's pre-push hook ran tina4 test || exit 1 as its backend gate and pushed a
red suite (1 failed, 334 passed) to production because tina4 test returned 0. Anyone gating
CI or a git hook on tina4 test's exit code is currently unprotected against failing backend tests.
Summary
tina4 test(the CLI_testcommand) runs pytest but discards its exit code, so the commandalways exits 0 — even when tests fail. Any CI or pre-push gate that relies on
tina4 test's exitstatus (
tina4 test || exit 1) silently passes on a red suite, letting broken code through toproduction.
Affected code
tina4_python/cli/__init__.py::_test, on both branches:v3(default / release branch):main:Neither inspects
result.returncodenor callssys.exit(...), so the function returnsNoneand theCLI exits
0regardless of the pytest result. Contrast_builda few lines below, which does it right:Reproduction
tina4-python
3.13.75(also reproduced by reading3.13.78/ currentv3+main), Windows, Python 3.12.2, pytest 9.1.1:tests/:def test_x(): assert Falsetina4 test— it prints1 failed, N passedbut the exit code is0.python -m pytest tests/on the same tree — exit code is1.Fix (one line)
Propagate pytest's exit code:
Happy to open a PR against
v3(andmain) if that helps.Impact
Real-world: a project's
pre-pushhook rantina4 test || exit 1as its backend gate and pushed ared suite (
1 failed, 334 passed) to production becausetina4 testreturned0. Anyone gatingCI or a git hook on
tina4 test's exit code is currently unprotected against failing backend tests.