fix: propagate exit code (#108)

* fix(pytest): propagate exit code

* feat: derive exit code for unittest
This commit is contained in:
Salomon Popp
2026-08-18 16:39:57 +03:00
committed by Itai Bohadana
parent 7d7cacb91a
commit b720009f3e
6 changed files with 21 additions and 20 deletions
+6 -6
View File
@@ -50,20 +50,18 @@ parser.add_argument(
parser.add_argument("args", nargs="*")
def main(argv: List[str]):
def main(argv: List[str]) -> int:
if "--pytest-collect" in argv:
argv.remove("--pytest-collect")
from .pytest_ import collect
collect(argv)
return
return collect(argv)
if "--pytest-extract-test-name-template" in argv:
argv.remove("--pytest-extract-test-name-template")
from .pytest_ import extract_test_name_template
extract_test_name_template(argv)
return
return extract_test_name_template(argv)
args = parser.parse_args(argv)
adapter = get_adapter(TestRunner(args.runner), args.emit_parameterized_ids)
@@ -74,7 +72,9 @@ def main(argv: List[str]):
stream_file.write(json.dumps({"id": pos_id, "result": result}) + "\n")
stream_file.flush()
results = adapter.run(args.args, stream)
results, exit_code = adapter.run(args.args, stream)
with open(args.results_file, "w") as results_file:
json.dump(results, results_file)
return exit_code
+2 -2
View File
@@ -1,6 +1,6 @@
import abc
from enum import Enum
from typing import TYPE_CHECKING, Callable, Dict, List, Optional
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple
class NeotestResultStatus(str, Enum):
@@ -43,6 +43,6 @@ class NeotestAdapter(abc.ABC):
}
@abc.abstractmethod
def run(self, args: List[str], stream: Callable):
def run(self, args: List[str], stream: Callable) -> Tuple[Dict, int]:
del args, stream
raise NotImplementedError
+4 -3
View File
@@ -55,7 +55,7 @@ class DjangoNeotestAdapter(CaseUtilsMixin, NeotestAdapter):
relative_dotted = relative_stem.replace(os.sep, ".")
return [*args, ".".join([relative_dotted, *child_ids])]
def run(self, args: List[str], _) -> Dict:
def run(self, args: List[str], _) -> Tuple[Dict, int]:
errs: Dict[str, Tuple[Exception, Any, TracebackType]] = {}
results = {}
@@ -146,5 +146,6 @@ class DjangoNeotestAdapter(CaseUtilsMixin, NeotestAdapter):
runner = DjangoUnittestRunner(
**vars(parser.parse_args(argv[1:-1])) # parse plugin config args
)
runner.run_tests(test_labels=[argv[-1]]) # pass test label
return results
failures = runner.run_tests(test_labels=[argv[-1]]) # pass test label
exit_code = 0 if failures == 0 else 1
return results, exit_code
+4 -4
View File
@@ -4,7 +4,7 @@ from typing import Callable, Dict, List, Optional, Union
from . import params_getter
from io import StringIO
from pathlib import Path
from typing import Callable, Dict, Generator, List, Optional, Union
from typing import Callable, Dict, Generator, List, Optional, Tuple, Union
import pytest
from _pytest._code.code import ExceptionRepr
@@ -24,18 +24,18 @@ class PytestNeotestAdapter(NeotestAdapter):
self,
args: List[str],
stream: Callable[[str, NeotestResult], None],
) -> Dict[str, NeotestResult]:
) -> Tuple[Dict[str, NeotestResult], int]:
result_collector = NeotestResultCollector(
self, stream=stream, emit_parameterized_ids=self.emit_parameterized_ids
)
pytest.main(
exit_code = pytest.main(
args=args,
plugins=[
result_collector,
NeotestDebugpyPlugin(),
],
)
return result_collector.results
return result_collector.results, int(exit_code)
class NeotestResultCollector:
+4 -4
View File
@@ -45,7 +45,7 @@ class UnittestNeotestAdapter(NeotestAdapter):
return [*args, ".".join([relative_dotted, *child_ids])]
# TODO: Stream results
def run(self, args: List[str], _) -> Dict:
def run(self, args: List[str], _) -> Tuple[Dict, int]:
results = {}
errs: Dict[str, Tuple[Exception, Any, TracebackType]] = {}
@@ -96,11 +96,11 @@ class UnittestNeotestAdapter(NeotestAdapter):
# Prepend an executable name which is just used in output
argv = ["neotest-python"] + self.convert_args(args[-1], args[:-1])
unittest.main(
program = unittest.main(
module=None,
argv=argv,
testRunner=NeotestUnittestRunner(resultclass=NeotestTextTestResult),
exit=False,
)
return results
exit_code = 0 if program.result.wasSuccessful() else 1
return results, exit_code