Skip to content

Commit cce942a

Browse files
committed
ready for release 2.4.2
1 parent 6cef69b commit cce942a

3 files changed

Lines changed: 85 additions & 13 deletions

File tree

carbontracker/tracker.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def _fetch_carbon_intensity(self):
6262

6363
def predict_carbon_intensity(self, pred_time_dur) -> float:
6464
new_fetch = self.carbon_intensity_service.fetch_carbon_intensity(time_duration=pred_time_dur)
65-
65+
6666

6767
weighted_intensities = [
6868
fetch.carbon_intensity for fetch in self.carbon_intensities_fetches
@@ -256,8 +256,7 @@ class CarbonTracker:
256256
257257
Args:
258258
epochs (int): Total epochs of your training loop.
259-
api_keys (dict, optional): Dictionary of Carbon Intensity API keys following the {name:key} format. Can also be set using `CarbonTracker.set_api_keys`
260-
259+
api_keys (dict, optional): Dictionary of Carbon Intensity API keys following the {name:key} format.
261260
Example: `{ \\"electricitymaps\\": \\"abcdefg\\" }`
262261
epochs_before_pred (int, optional): Epochs to monitor before outputting predicted consumption. Set to -1 for all epochs. Set to 0 for no prediction.
263262
monitor_epochs (int, optional): Total number of epochs to monitor. Outputs actual consumption when reached. Set to -1 for all epochs. Cannot be less than `epochs_before_pred` or equal to 0.
@@ -461,6 +460,10 @@ def stop(self):
461460
self._output_actual()
462461
self._delete()
463462

463+
def set_api_keys(self, api_keys):
464+
self.api_keys = api_keys
465+
self._get_fetcher()
466+
464467
def _handle_error(self, error):
465468
err_str = traceback.format_exc()
466469
if self.ignore_errors:
@@ -508,7 +511,7 @@ def _output_actual(self):
508511
)
509512
else:
510513
self._output_energy(
511-
f"Actual consumption for {self.epoch_counter+1} epoch(s):",
514+
f"Actual consumption for {self.epoch_counter} epoch(s):",
512515
time,
513516
energy,
514517
_co2eq,
@@ -639,7 +642,6 @@ def _get_fetcher(self) -> Optional[IntensityFetcher]:
639642
except Exception:
640643
provider_name = provider_id
641644

642-
# Try to initialize the provider
643645
try:
644646
initialized_provider = constructor(logger=self.logger, api_key=api_key)
645647
self.logger.err_info(f"Using intensity provider: {provider_name} ('{provider_id}').")
@@ -653,7 +655,7 @@ def _get_fetcher(self) -> Optional[IntensityFetcher]:
653655
msg = f"No matching provider for API keys: {', '.join(unknown_keys)}."
654656
if available_display:
655657
msg += f" Supported providers: {available_display}."
656-
self.logger.err_warn(msg)
658+
self.logger.err_critical(msg)
659+
sys.exit(70)
657660

658661
return None
659-

tests/test_loggerutil.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def test_output(self, mock_info):
162162

163163
logger.output(test_message)
164164

165-
mock_info.assert_called_once_with(f"CarbonTracker: {test_message}")
165+
mock_info.assert_called_once_with(f"CarbonTracker: {test_message}", extra={'verbose_level':0})
166166

167167
def test_multiple_loggers(self):
168168
logger1 = loggerutil.Logger(logger_id="1")

tests/test_tracker.py

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ def test_output_actual_zero_epochs(self):
618618
"\tEnergy:\t60.000000 kWh\n"
619619
"\tCO2eq:\t150.000000 g"
620620
"\n\tThis is equivalent to:\n"
621-
"\t1.395349 km travelled by car"
621+
"\t1.404494 km travelled by car"
622622
)
623623

624624
self.mock_logger.output.assert_called_once_with(
@@ -648,7 +648,7 @@ def test_output_actual_nonzero_epochs(self):
648648
"\tEnergy:\t60.000000 kWh\n"
649649
"\tCO2eq:\t150.000000 g"
650650
"\n\tThis is equivalent to:\n"
651-
"\t1.395349 km travelled by car"
651+
"\t1.404494 km travelled by car"
652652
)
653653

654654
self.mock_logger.output.assert_called_once_with(
@@ -681,7 +681,7 @@ def test_output_pred(self):
681681
"\tEnergy:\t100.000000 kWh\n"
682682
"\tCO2eq:\t150.000000 g"
683683
"\n\tThis is equivalent to:\n"
684-
"\t1.395349 km travelled by car"
684+
"\t1.404494 km travelled by car"
685685
)
686686

687687
self.mock_logger.output.assert_called_once_with(
@@ -692,7 +692,7 @@ def test_co2eq_with_pred_time_dur(self):
692692
assert self.tracker is not None
693693
intensity_updater = MagicMock()
694694
intensity_updater.predict_carbon_intensity = MagicMock(
695-
return_value=MagicMock(carbon_intensity=0.5)
695+
return_value=0.5
696696
)
697697

698698
energy_usage = 100
@@ -709,7 +709,7 @@ def test_co2eq_without_pred_time_dur(self):
709709
assert self.tracker is not None
710710
intensity_updater = MagicMock()
711711
intensity_updater.average_carbon_intensity = MagicMock(
712-
return_value=MagicMock(carbon_intensity=0.5)
712+
return_value=0.5
713713
)
714714

715715
energy_usage = 100
@@ -928,5 +928,75 @@ def test_all_sim_parameters_ok(self):
928928
self.assertEqual(tracker.sim_gpu_util, 0.8)
929929

930930

931+
class TestCarbonTrackerFetcherInitialization(unittest.TestCase):
932+
def setUp(self):
933+
self.mock_logger = MagicMock()
934+
self.mock_tracker_thread_instance = MagicMock()
935+
self.mock_intensity_thread_instance = MagicMock()
936+
self.patcher_logger = patch(
937+
"carbontracker.tracker.loggerutil.Logger", return_value=self.mock_logger
938+
)
939+
self.patcher_tracker_thread = patch(
940+
"carbontracker.tracker.CarbonTrackerThread",
941+
return_value=self.mock_tracker_thread_instance,
942+
)
943+
self.patcher_intensity_thread = patch("carbontracker.tracker.CarbonIntensityThread")
944+
self.patcher_get_pids = patch(
945+
"carbontracker.tracker.CarbonTracker._get_pids", return_value=[]
946+
)
947+
self.patcher_components = patch(
948+
"carbontracker.tracker.component.create_components", return_value=[]
949+
)
950+
951+
self.patcher_logger.start()
952+
self.patcher_tracker_thread.start()
953+
self.mock_intensity_thread_class = self.patcher_intensity_thread.start()
954+
self.mock_intensity_thread_class.return_value = self.mock_intensity_thread_instance
955+
self.patcher_get_pids.start()
956+
self.patcher_components.start()
957+
958+
def tearDown(self):
959+
self.patcher_components.stop()
960+
self.patcher_get_pids.stop()
961+
self.patcher_intensity_thread.stop()
962+
self.patcher_tracker_thread.stop()
963+
self.patcher_logger.stop()
964+
965+
def _build_tracker(self, api_keys):
966+
return CarbonTracker(epochs=1, api_keys=api_keys)
967+
968+
def _assert_intensity_fetcher_used(self, provider_key, patch_target, api_key):
969+
expected_fetcher = MagicMock(name=f"{provider_key}_fetcher")
970+
with patch(patch_target, return_value=expected_fetcher) as mock_constructor:
971+
self._build_tracker({provider_key: api_key})
972+
973+
mock_constructor.assert_called_once_with(logger=self.mock_logger, api_key=api_key)
974+
self.mock_intensity_thread_class.assert_called_once()
975+
intensity_fetcher = self.mock_intensity_thread_class.call_args.kwargs[
976+
"intensity_fetcher"
977+
]
978+
self.assertIs(intensity_fetcher, expected_fetcher)
979+
980+
def test_electricitymaps_api_key_attaches_fetcher(self):
981+
self._assert_intensity_fetcher_used(
982+
"electricitymaps",
983+
"carbontracker.tracker.electricitymaps.ElectricityMap",
984+
"electric_key",
985+
)
986+
987+
def test_carbonintensitygb_api_key_attaches_fetcher(self):
988+
self._assert_intensity_fetcher_used(
989+
"carbonintensityGB",
990+
"carbontracker.tracker.carbonintensitygb.CarbonIntensityGB",
991+
"gb_key",
992+
)
993+
994+
def test_energidataservice_api_key_attaches_fetcher(self):
995+
self._assert_intensity_fetcher_used(
996+
"energidataservice",
997+
"carbontracker.tracker.energidataservice.EnergiDataService",
998+
"dk_key",
999+
)
1000+
9311001
if __name__ == "__main__":
9321002
unittest.main()

0 commit comments

Comments
 (0)