Skip to content

Commit 7a8b5a8

Browse files
committed
Update changelog, add run_pytest script, and improve IRIS stop handling in Docker script
1 parent 3c41650 commit 7a8b5a8

4 files changed

Lines changed: 55 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- Update the default `PersistentMessage` schema mode from `extend` to `managed`
1515
for compatibility with `iris-persistence` 0.3.
1616

17+
### Fixed
18+
- Make CLI mocks resolve consistently on Python 3.10 when `iop.cli.main` is
19+
also exposed as the public CLI function.
20+
- Preserve pytest's real exit status when preview IRIS changes the process
21+
status during Embedded Python interpreter shutdown.
22+
1723
### Internal
1824
- Add wheel-content and installed-ObjectScript validation.
1925
- Refactor persistent-message resolution and production/migration internals

scripts/run_pytest.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Run pytest while preserving its exit code under IRIS Embedded Python.
2+
3+
Some preview IRIS builds can change the process status during interpreter
4+
shutdown after pytest has already completed successfully. All pytest fixture
5+
and plugin teardown has finished by the time ``pytest.main`` returns, so exit
6+
directly with that result instead of allowing a later runtime hook to replace
7+
it.
8+
"""
9+
10+
from __future__ import annotations
11+
12+
import os
13+
import sys
14+
15+
import pytest
16+
17+
18+
def main() -> None:
19+
exit_code = pytest.main(sys.argv[1:])
20+
sys.stdout.flush()
21+
sys.stderr.flush()
22+
os._exit(int(exit_code))
23+
24+
25+
if __name__ == "__main__":
26+
main()

src/tests/unit/test_cli.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,31 @@
33
import runpy
44
import tempfile
55
import unittest
6+
from importlib import import_module
67
from io import StringIO
78
from unittest.mock import MagicMock, patch
89

910
from iop.cli.main import _format_test_response, main
1011

12+
cli_main_module = import_module("iop.cli.main")
13+
1114

1215
class TestIOPCli(unittest.TestCase):
1316
"""Test cases for IOP CLI functionality."""
1417

1518
def setUp(self):
1619
# Force local mode regardless of any IOP_URL / IOP_SETTINGS env vars
1720
# that may be set by a parallel e2e test session.
18-
self._remote_patcher = patch(
19-
"iop.cli.main.get_remote_settings", return_value=None
21+
self._remote_patcher = patch.object(
22+
cli_main_module, "get_remote_settings", return_value=None
2023
)
2124
self._remote_patcher.start()
2225

2326
def tearDown(self):
2427
self._remote_patcher.stop()
2528

2629
def test_module_entrypoint_calls_cli_main(self):
27-
with patch("iop.cli.main.main") as mock_main:
30+
with patch.object(cli_main_module, "main") as mock_main:
2831
runpy.run_module("iop", run_name="__main__")
2932

3033
mock_main.assert_called_once_with()
@@ -275,8 +278,9 @@ def test_export_defaults_to_json(self):
275278
def test_export_python_format_uses_production_reconstruction(self):
276279
production = MagicMock()
277280
production.to_python.return_value = "from iop import Production\n"
278-
with patch(
279-
"iop.cli.main.Production.from_iris",
281+
with patch.object(
282+
cli_main_module.Production,
283+
"from_iris",
280284
return_value=production,
281285
) as mock_from_iris:
282286
with patch("sys.stdout", new=StringIO()) as fake_out:
@@ -294,8 +298,9 @@ def test_export_python_format_uses_production_reconstruction(self):
294298
def test_export_class_format_uses_production_reconstruction(self):
295299
production = MagicMock()
296300
production.to_class.return_value = "from iop import Production, ServiceItem\n"
297-
with patch(
298-
"iop.cli.main.Production.from_iris",
301+
with patch.object(
302+
cli_main_module.Production,
303+
"from_iris",
299304
return_value=production,
300305
) as mock_from_iris:
301306
with patch("sys.stdout", new=StringIO()) as fake_out:
@@ -316,8 +321,9 @@ def test_export_class_format_uses_production_reconstruction(self):
316321
def test_export_graph_format_prints_reconstructed_graph(self):
317322
production = MagicMock()
318323
production.graph.return_value = "Demo.Production\n FileInput"
319-
with patch(
320-
"iop.cli.main.Production.from_iris",
324+
with patch.object(
325+
cli_main_module.Production,
326+
"from_iris",
321327
return_value=production,
322328
):
323329
with patch("sys.stdout", new=StringIO()) as fake_out:
@@ -331,8 +337,9 @@ def test_export_graph_format_prints_reconstructed_graph(self):
331337
def test_export_mermaid_format_prints_reconstructed_graph(self):
332338
production = MagicMock()
333339
production.to_mermaid.return_value = "flowchart LR\n FileInput --> Order\n"
334-
with patch(
335-
"iop.cli.main.Production.from_iris",
340+
with patch.object(
341+
cli_main_module.Production,
342+
"from_iris",
336343
return_value=production,
337344
) as mock_from_iris:
338345
with patch("sys.stdout", new=StringIO()) as fake_out:

test-in-docker.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ iris_start () {
99

1010
iris_stop () {
1111
echo "Stopping IRIS"
12-
iris stop iris quietly
12+
if ! iris stop iris quietly; then
13+
echo "Warning: IRIS did not stop cleanly; container cleanup will terminate it." >&2
14+
fi
15+
return 0
1316
}
1417

1518
exit_on_error () {
@@ -37,7 +40,7 @@ exit_on_error
3740

3841
# Unit and local IRIS tests. Remote API tests run in their dedicated CI job.
3942
cd ..
40-
python3 -m pytest src/tests/unit src/tests/e2e/local
43+
python3 scripts/run_pytest.py src/tests/unit src/tests/e2e/local
4144
exit_on_error
4245

4346
# Integration tests

0 commit comments

Comments
 (0)