diff --git a/codecarbon/emissions_tracker.py b/codecarbon/emissions_tracker.py index 96ed00c91..7915910d0 100644 --- a/codecarbon/emissions_tracker.py +++ b/codecarbon/emissions_tracker.py @@ -706,6 +706,16 @@ def start(self) -> None: ) return if self._start_time is not None: + if self._scheduler is None: + # stop() drops the schedulers, releases the lock and exits the + # output handlers, so a stopped tracker cannot be restarted. + # `start()` is wrapped in @suppress(Exception), so raising here + # would be swallowed: log instead of pretending it worked. + logger.error( + "This tracker was already stopped and cannot be restarted. " + "Create a new tracker instead." + ) + return logger.warning("Already started tracking") return diff --git a/tests/test_emissions_tracker.py b/tests/test_emissions_tracker.py index 8ab12e5d8..e2a330b4f 100644 --- a/tests/test_emissions_tracker.py +++ b/tests/test_emissions_tracker.py @@ -1108,3 +1108,20 @@ def test_cumulative_emissions_with_varying_intensity( # Verification: If it wasn't cumulative, it would be 3.0 kWh * 300 g/kWh = 0.9 kg self.assertLess(data3.emissions, 0.8) + + +class TestRestartAfterStop(unittest.TestCase): + def test_start_after_stop_is_refused(self): + tracker = OfflineEmissionsTracker( + country_iso_code="FRA", + save_to_file=False, + allow_multiple_runs=True, + measure_power_secs=10, + ) + tracker.start() + tracker.stop() + with self.assertLogs("codecarbon", level="ERROR") as logs: + tracker.start() + self.assertIn("cannot be restarted", "".join(logs.output)) + # Refused, not half-restarted: nothing was rebuilt. + self.assertIsNone(tracker._scheduler)