Skip to content

Commit 6aa061a

Browse files
committed
WS1
codetracer-python-recorder/codetracer_python_recorder/cli.py: codetracer-python-recorder/codetracer_python_recorder/session.py: codetracer-python-recorder/src/session.rs: codetracer-python-recorder/tests/python/unit/test_auto_start.py: codetracer-python-recorder/tests/python/unit/test_session_helpers.py: design-docs/toplevel-exit-and-trace-gating-implementation-plan.status.md: pytest.log: pytest_case.log: Signed-off-by: Tzanko Matev <[email protected]>
1 parent c2999af commit 6aa061a

File tree

6 files changed

+82
-17
lines changed

6 files changed

+82
-17
lines changed

codetracer-python-recorder/codetracer_python_recorder/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ def main(argv: Iterable[str] | None = None) -> int:
287287
try:
288288
flush()
289289
finally:
290-
stop()
290+
stop(exit_code=exit_code)
291291
sys.argv = old_argv
292292

293293
_serialise_metadata(trace_dir, script=script_path)

codetracer-python-recorder/codetracer_python_recorder/session.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,17 @@ def __init__(self, path: Path, format: str) -> None:
3838
self.path = path
3939
self.format = format
4040

41-
def stop(self) -> None:
42-
"""Stop this trace session."""
41+
def stop(self, *, exit_code: int | None = None) -> None:
42+
"""Stop this trace session.
43+
44+
Parameters
45+
----------
46+
exit_code:
47+
Optional process exit status to forward to the recorder backend.
48+
When ``None``, the session shutdown reason remains unspecified.
49+
"""
4350
if _active_session is self:
44-
stop()
51+
stop(exit_code=exit_code)
4552

4653
def flush(self) -> None:
4754
"""Flush buffered trace data for this session."""
@@ -51,6 +58,7 @@ def __enter__(self) -> "TraceSession":
5158
return self
5259

5360
def __exit__(self, exc_type, exc, tb) -> None: # pragma: no cover - thin wrapper
61+
# Exit codes are not tracked for context-managed sessions; report unknown.
5462
self.stop()
5563

5664

@@ -121,12 +129,18 @@ def start(
121129
return session
122130

123131

124-
def stop() -> None:
125-
"""Stop the active trace session if one is running."""
132+
def stop(*, exit_code: int | None = None) -> None:
133+
"""Stop the active trace session if one is running.
134+
135+
Parameters
136+
----------
137+
exit_code:
138+
Optional process exit status to forward to the backend.
139+
"""
126140
global _active_session
127141
if not _is_tracing_backend():
128142
return
129-
_stop_backend()
143+
_stop_backend(exit_code)
130144
_active_session = None
131145

132146

codetracer-python-recorder/src/session.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@ pub fn start_tracing(
7373
}
7474

7575
/// Stop tracing by resetting the global flag.
76-
#[pyfunction]
77-
pub fn stop_tracing() -> PyResult<()> {
76+
#[pyfunction(signature = (exit_code=None))]
77+
pub fn stop_tracing(exit_code: Option<i32>) -> PyResult<()> {
7878
ffi::wrap_pyfunction("stop_tracing", || {
79+
let _ = exit_code;
7980
Python::with_gil(|py| {
8081
// Uninstall triggers finish() on tracer implementation.
8182
uninstall_tracer(py)?;

codetracer-python-recorder/tests/python/unit/test_auto_start.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def fake_start_backend(
3838
state["active"] = True
3939
captured_filters.append(filters)
4040

41-
def fake_stop_backend() -> None:
41+
def fake_stop_backend(exit_code: int | None = None) -> None:
4242
state["active"] = False
4343

4444
monkeypatch.setenv(auto_start.ENV_TRACE_PATH, str(trace_dir))

codetracer-python-recorder/tests/python/unit/test_session_helpers.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ def clear_active_session() -> None:
6363

6464

6565
def test_trace_session_stop_clears_global(monkeypatch: pytest.MonkeyPatch) -> None:
66-
called = {"stop": False, "start": False}
66+
called = {"stop_exit_codes": [], "start": False}
6767

6868
def fake_start(*args, **kwargs) -> None:
6969
called["start"] = True
7070

71-
def fake_stop() -> None:
72-
called["stop"] = True
71+
def fake_stop(exit_code: int | None = None) -> None:
72+
called["stop_exit_codes"].append(exit_code)
7373

7474
monkeypatch.setattr(session, "_start_backend", fake_start)
7575
monkeypatch.setattr(session, "_stop_backend", fake_stop)
@@ -78,7 +78,7 @@ def fake_stop() -> None:
7878
session._active_session = session.TraceSession(path=Path("/tmp"), format="json")
7979
session.stop()
8080
assert session._active_session is None
81-
assert called["stop"] is True
81+
assert called["stop_exit_codes"] == [None]
8282

8383

8484
def test_trace_session_flush_noop_when_inactive(monkeypatch: pytest.MonkeyPatch) -> None:
@@ -107,9 +107,9 @@ def fake_start(
107107
trace_state["active"] = True
108108
calls["start"].append((Path(path), fmt, activation, filters))
109109

110-
def fake_stop() -> None:
110+
def fake_stop(exit_code: int | None = None) -> None:
111111
trace_state["active"] = False
112-
calls["stop"].append(True)
112+
calls["stop"].append(exit_code)
113113

114114
monkeypatch.setattr(session, "_start_backend", fake_start)
115115
monkeypatch.setattr(session, "_stop_backend", fake_stop)
@@ -124,7 +124,19 @@ def fake_stop() -> None:
124124
assert handle.format == "binary"
125125

126126
assert calls["start"] == [(target, "binary", None, None)]
127-
assert calls["stop"] == [True]
127+
assert calls["stop"] == [None]
128+
129+
130+
def test_stop_forwards_exit_code(monkeypatch: pytest.MonkeyPatch) -> None:
131+
captured: list[int | None] = []
132+
133+
monkeypatch.setattr(session, "_is_tracing_backend", lambda: True)
134+
monkeypatch.setattr(session, "_stop_backend", lambda code=None: captured.append(code))
135+
136+
session._active_session = session.TraceSession(path=Path("/tmp"), format="json")
137+
session.stop(exit_code=123)
138+
assert captured == [123]
139+
assert session._active_session is None
128140

129141

130142
def test_normalize_trace_filter_handles_none() -> None:
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Toplevel Exit & Trace Gating – Status
2+
3+
## Relevant Design Docs
4+
- `design-docs/adr/0015-balanced-toplevel-lifecycle-and-trace-gating.md`
5+
- `design-docs/toplevel-exit-and-trace-gating-implementation-plan.md`
6+
7+
## Key Source Files
8+
- `codetracer-python-recorder/src/session.rs`
9+
- `codetracer_python_recorder/session.py`
10+
- `codetracer_python_recorder/cli.py`
11+
- `codetracer-python-recorder/src/monitoring/install.rs`
12+
- `codetracer-python-recorder/src/monitoring/mod.rs`
13+
- `codetracer-python-recorder/tests/python` (planned additions)
14+
15+
## Workstream Progress
16+
17+
### WS1 – Public API & Session Plumbing
18+
- **Scope recap:** Teach `stop_tracing` to accept an optional exit code and propagate it through the Python helpers and CLI while keeping backwards compatibility.
19+
- **Status:** _Completed_
20+
- `stop_tracing` now accepts an optional `exit_code` argument, and the Python session helpers/CLI forward the value.
21+
- Added unit coverage ensuring `stop(exit_code=...)` forwards the value downstream while `stop()` remains valid.
22+
- Verification: `just dev` (editable build with `integration-test` feature) and `just py-test` (Python suites across both recorders) pass.
23+
24+
### WS2 – Runtime Exit State & `<toplevel>` Return Emission
25+
- **Status:** _Not Started_ (blocked on WS1 API plumbing).
26+
27+
### WS3 – Unified Trace Gate Abstraction
28+
- **Status:** _Not Started_.
29+
30+
### WS4 – Lifecycle & Metadata Updates
31+
- **Status:** _Not Started_.
32+
33+
### WS5 – Validation & Parity Follow-Up
34+
- **Status:** _Not Started_.
35+
36+
## Notes
37+
- API changes will require a minor version bump once runtime support lands; capture release planning tasks after WS2.
38+
- Remember to bootstrap the dev build (`just dev`) before Python suites so integration-test hooks stay enabled.

0 commit comments

Comments
 (0)