diff --git a/codecarbon/emissions_tracker.py b/codecarbon/emissions_tracker.py index 96ed00c91..4eb146a46 100644 --- a/codecarbon/emissions_tracker.py +++ b/codecarbon/emissions_tracker.py @@ -1309,7 +1309,6 @@ class OfflineEmissionsTracker(BaseEmissionsTracker): _country_iso_code = None _country_name, _region, country_2letter_iso_code = None, None, None - @suppress(Exception) def __init__( self, *args, diff --git a/docs/reference/api.md b/docs/reference/api.md index 15117b123..f8561acb3 100644 --- a/docs/reference/api.md +++ b/docs/reference/api.md @@ -8,6 +8,13 @@ Parameters can be set via `EmissionsTracker()`, `OfflineEmissionsTracker()`, the PUE is a multiplication factor provided by the user. Old datacenters have PUE up to 2.2, new greener ones as low as 1.1. +!!! warning "Constructor errors (changed in v3.4.0)" + `OfflineEmissionsTracker(...)` used to swallow every exception raised while + building the tracker, returning a half-initialised object that silently + recorded nothing. It now propagates those errors, like `EmissionsTracker` + always did — for example an `output_dir` that does not exist raises instead of + logging. Code that relied on the constructor never raising needs a `try`/`except`. + !!! note "GPU selection" If you use `CUDA_VISIBLE_DEVICES` or `ROCR_VISIBLE_DEVICES` to set GPUs, CodeCarbon will automatically populate `gpu_ids`. Manual `gpu_ids` overrides this. diff --git a/tests/test_offline_emissions_tracker.py b/tests/test_offline_emissions_tracker.py index 36447409d..c13c1c61d 100644 --- a/tests/test_offline_emissions_tracker.py +++ b/tests/test_offline_emissions_tracker.py @@ -6,7 +6,7 @@ import pandas as pd -from codecarbon.emissions_tracker import OfflineEmissionsTracker +from codecarbon.emissions_tracker import EmissionsTracker, OfflineEmissionsTracker from tests.testutils import get_custom_mock_open, get_test_data_source @@ -68,6 +68,24 @@ def test_offline_tracker_task(self): self.assertGreater(task_emission_data.emissions, 0.0) self.assertEqual(task_emission_data.country_name, None) + def test_offline_tracker_raises_on_invalid_output_dir(self): + # Configuration errors must not be swallowed by the constructor, + # otherwise the user gets a half-built tracker that silently does + # nothing. Same semantics as the online EmissionsTracker. + with self.assertRaises(OSError): + OfflineEmissionsTracker( + country_iso_code="FRA", + output_dir=str(self.temp_path / "does_not_exist"), + ) + with self.assertRaises(OSError): + EmissionsTracker(output_dir=str(self.temp_path / "does_not_exist")) + + def test_offline_tracker_raises_on_invalid_region(self): + # A second, offline-specific constructor path: the region check runs + # before `super().__init__`, so it also has to reach the caller. + with self.assertRaises(AssertionError): + OfflineEmissionsTracker(country_iso_code="FRA", region=123) + def test_resolve_offline_country_name_logs_on_invalid_iso(self): tracker = OfflineEmissionsTracker( country_iso_code="INVALID",