Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions codecarbon/cli/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,12 @@ def run_and_monitor(
else:
print(" Emissions: N/A")

# Show where the data was saved
if hasattr(tracker, "_conf") and "output_file" in tracker._conf:
output_path = tracker._conf["output_file"]
# Make it absolute if it's relative
if not os.path.isabs(output_path):
output_path = os.path.abspath(output_path)
print(f" Saved to: {output_path}")
# Show where the data was saved, asking the output handlers themselves
# so the path stays right whatever `output_dir` / `output_file` are.
for handler in getattr(tracker, "_output_handlers", []):
save_file_path = getattr(handler, "save_file_path", None)
if save_file_path:
print(f" Saved to: {os.path.abspath(save_file_path)}")

print(" ⚠️ Note: Tracked the command process and its children")
print("=" * 60)
Expand Down
3 changes: 3 additions & 0 deletions codecarbon/output_methods/boamps/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ def __init__(
self._quality = quality
self._infra_overrides = infra_overrides
self._environment_overrides = environment_overrides
# Path of the last report written, None until out() succeeds.
self.save_file_path: Optional[str] = None

@classmethod
def from_file(cls, context_file_path: str, output_dir: str = ".") -> "BoAmpsOutput":
Expand Down Expand Up @@ -182,6 +184,7 @@ def out(self, total: EmissionsData, delta: EmissionsData):
file_path = os.path.join(self._output_dir, file_name)
with open(file_path, "w") as f:
json.dump(report_dict, f, indent=2)
self.save_file_path = file_path
logger.info(f"BoAmps report saved to {os.path.abspath(file_path)}")
except Exception as e:
logger.error(f"Failed to write BoAmps report: {e}", exc_info=True)
Expand Down
49 changes: 49 additions & 0 deletions tests/cli/test_monitor.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from types import SimpleNamespace

import pytest
Expand All @@ -11,6 +12,7 @@ def __init__(self, *args, **kwargs):
self.kwargs = kwargs
self.stopped = 0
self._conf = {"output_file": "emissions.csv"}
self._output_handlers = [SimpleNamespace(save_file_path="emissions.csv")]

def start(self):
return None
Expand Down Expand Up @@ -226,3 +228,50 @@ def kill(self):
assert exc_info.value.exit_code == 130
assert process_info["terminated"] == 1
assert process_info["killed"] == 1


def _run_and_capture(monkeypatch, capsys, handlers):
class FakePopen:
def __init__(self, command, text=True):
pass

def wait(self):
return 0

class FakeTrackerWithHandlers(FakeTracker):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._output_handlers = handlers

_patch_trackers(monkeypatch, online_cls=FakeTrackerWithHandlers)
monkeypatch.setattr(monitor_module.subprocess, "Popen", FakePopen)

with pytest.raises(typer.Exit):
monitor_module.run_and_monitor(SimpleNamespace(args=["echo", "hi"]))

# rich wraps long lines to the terminal width, so strip all whitespace
return "".join(capsys.readouterr().out.split())


def test_run_and_monitor_reports_output_dir(monkeypatch, capsys, tmp_path):
save_file_path = os.path.join(str(tmp_path), "emissions.csv")
out = _run_and_capture(
monkeypatch, capsys, [SimpleNamespace(save_file_path=save_file_path)]
)

assert f"Savedto:{save_file_path}" in out


def test_run_and_monitor_reports_relative_path_from_cwd(monkeypatch, capsys, tmp_path):
monkeypatch.chdir(tmp_path)
out = _run_and_capture(
monkeypatch, capsys, [SimpleNamespace(save_file_path="emissions.csv")]
)

assert f"Savedto:{os.path.join(os.getcwd(), 'emissions.csv')}" in out


def test_run_and_monitor_reports_no_path_without_file_output(monkeypatch, capsys):
out = _run_and_capture(monkeypatch, capsys, [SimpleNamespace()])

assert "Savedto:" not in out
1 change: 1 addition & 0 deletions tests/test_boamps_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ def test_out_writes_json_file(self):
self.tmpdir, f"boamps_report_{self.emissions.run_id}.json"
)
self.assertTrue(os.path.isfile(expected_file))
self.assertEqual(handler.save_file_path, expected_file)

with open(expected_file) as f:
report = json.load(f)
Expand Down
Loading