codecarbon 3.0.7__tar.gz → 3.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {codecarbon-3.0.7 → codecarbon-3.0.8}/PKG-INFO +1 -1
  2. codecarbon-3.0.8/codecarbon/_version.py +1 -0
  3. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/units.py +16 -1
  4. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/emissions_tracker.py +19 -3
  5. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/external/task.py +1 -0
  6. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/emissions_data.py +4 -0
  7. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon.egg-info/PKG-INFO +1 -1
  8. {codecarbon-3.0.7 → codecarbon-3.0.8}/pyproject.toml +4 -1
  9. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_api_call.py +1 -0
  10. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_emissions_tracker.py +56 -27
  11. codecarbon-3.0.7/codecarbon/_version.py +0 -1
  12. {codecarbon-3.0.7 → codecarbon-3.0.8}/LICENSE +0 -0
  13. {codecarbon-3.0.7 → codecarbon-3.0.8}/README.md +0 -0
  14. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/__init__.py +0 -0
  15. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/cli/__init__.py +0 -0
  16. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/cli/cli_utils.py +0 -0
  17. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/cli/main.py +0 -0
  18. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/__init__.py +0 -0
  19. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/api_client.py +0 -0
  20. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/cloud.py +0 -0
  21. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/co2_signal.py +0 -0
  22. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/config.py +0 -0
  23. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/cpu.py +0 -0
  24. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/emissions.py +0 -0
  25. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/gpu.py +0 -0
  26. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/measure.py +0 -0
  27. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/powermetrics.py +0 -0
  28. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/rapl.py +0 -0
  29. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/resource_tracker.py +0 -0
  30. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/schemas.py +0 -0
  31. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/core/util.py +0 -0
  32. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/canada_provinces.geojson +0 -0
  33. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/cloud/impact.csv +0 -0
  34. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_scrapper.py +0 -0
  35. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/hardware/cpu_dataset_builder/intel_cpu_scrapper.py +0 -0
  36. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/hardware/cpu_dataset_builder/merge_scrapped_cpu_power.py +0 -0
  37. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/hardware/cpu_power.csv +0 -0
  38. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/private_infra/2016/usa_emissions.json +0 -0
  39. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/private_infra/2023/canada_energy_mix.json +0 -0
  40. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/private_infra/carbon_intensity_per_source.json +0 -0
  41. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/data/private_infra/global_energy_mix.json +0 -0
  42. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/external/__init__.py +0 -0
  43. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/external/geography.py +0 -0
  44. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/external/hardware.py +0 -0
  45. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/external/logger.py +0 -0
  46. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/external/ram.py +0 -0
  47. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/external/scheduler.py +0 -0
  48. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/input.py +0 -0
  49. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/lock.py +0 -0
  50. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output.py +0 -0
  51. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/__init__.py +0 -0
  52. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/base_output.py +0 -0
  53. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/file.py +0 -0
  54. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/http.py +0 -0
  55. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/logger.py +0 -0
  56. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/metrics/__init__.py +0 -0
  57. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/metrics/logfire.py +0 -0
  58. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/metrics/metric_docs.py +0 -0
  59. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/output_methods/metrics/prometheus.py +0 -0
  60. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/viz/__init__.py +0 -0
  61. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/viz/assets/__init__.py +0 -0
  62. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/viz/carbonboard.py +0 -0
  63. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/viz/carbonboard_on_api.py +0 -0
  64. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/viz/components.py +0 -0
  65. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/viz/data.py +0 -0
  66. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon/viz/units.py +0 -0
  67. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon.egg-info/SOURCES.txt +0 -0
  68. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon.egg-info/dependency_links.txt +0 -0
  69. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon.egg-info/entry_points.txt +0 -0
  70. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon.egg-info/requires.txt +0 -0
  71. {codecarbon-3.0.7 → codecarbon-3.0.8}/codecarbon.egg-info/top_level.txt +0 -0
  72. {codecarbon-3.0.7 → codecarbon-3.0.8}/setup.cfg +0 -0
  73. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_cli.py +0 -0
  74. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_cloud.py +0 -0
  75. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_co2_signal.py +0 -0
  76. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_config.py +0 -0
  77. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_core_util.py +0 -0
  78. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_cpu.py +0 -0
  79. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_cpu_load.py +0 -0
  80. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_custom_handler.py +0 -0
  81. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_emissions.py +0 -0
  82. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_emissions_tracker_constant.py +0 -0
  83. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_emissions_tracker_flush.py +0 -0
  84. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_energy.py +0 -0
  85. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_geography.py +0 -0
  86. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_gpu.py +0 -0
  87. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_lock.py +0 -0
  88. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_logging_output.py +0 -0
  89. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_offline_emissions_tracker.py +0 -0
  90. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_package_integrity.py +0 -0
  91. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_powermetrics.py +0 -0
  92. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_ram.py +0 -0
  93. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_tracking_inference.py +0 -0
  94. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_unsupported_gpu.py +0 -0
  95. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_viz_data.py +0 -0
  96. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/test_viz_units.py +0 -0
  97. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/testdata.py +0 -0
  98. {codecarbon-3.0.7 → codecarbon-3.0.8}/tests/testutils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codecarbon
3
- Version: 3.0.7
3
+ Version: 3.0.8
4
4
  Author: Mila, DataForGood, BCG GAMMA, Comet.ml, Haverford College
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://codecarbon.io/
@@ -0,0 +1 @@
1
+ __version__ = "3.0.8"
@@ -90,7 +90,6 @@ class Energy:
90
90
  return Energy(self.kWh + other.kWh)
91
91
 
92
92
  def __mul__(self, factor: float) -> "Energy":
93
- assert isinstance(factor, float)
94
93
  assert isinstance(self.kWh, float)
95
94
  result = Energy(self.kWh * factor)
96
95
  return result
@@ -162,3 +161,19 @@ class Power:
162
161
 
163
162
  def __floordiv__(self, divisor: float) -> "Power":
164
163
  return Power(self.kW // divisor)
164
+
165
+
166
+ @dataclass
167
+ class Water:
168
+ """
169
+ Measured in litres
170
+ """
171
+
172
+ litres: float
173
+
174
+ @classmethod
175
+ def from_litres(cls, litres: float) -> "Water":
176
+ return cls(litres=litres)
177
+
178
+ def __add__(self, other: "Water") -> "Water":
179
+ return Water(self.litres + other.litres)
@@ -17,7 +17,7 @@ from codecarbon._version import __version__
17
17
  from codecarbon.core.config import get_hierarchical_config
18
18
  from codecarbon.core.emissions import Emissions
19
19
  from codecarbon.core.resource_tracker import ResourceTracker
20
- from codecarbon.core.units import Energy, Power, Time
20
+ from codecarbon.core.units import Energy, Power, Time, Water
21
21
  from codecarbon.core.util import count_cpus, count_physical_cpus, suppress
22
22
  from codecarbon.external.geography import CloudMetadata, GeoMetadata
23
23
  from codecarbon.external.hardware import CPU, GPU, AppleSiliconChip
@@ -179,6 +179,7 @@ class BaseEmissionsTracker(ABC):
179
179
  force_cpu_power: Optional[int] = _sentinel,
180
180
  force_ram_power: Optional[int] = _sentinel,
181
181
  pue: Optional[int] = _sentinel,
182
+ wue: Optional[bool] = _sentinel,
182
183
  force_mode_cpu_load: Optional[bool] = _sentinel,
183
184
  allow_multiple_runs: Optional[bool] = _sentinel,
184
185
  ):
@@ -238,6 +239,7 @@ class BaseEmissionsTracker(ABC):
238
239
  :param pue: PUE (Power Usage Effectiveness) of the datacenter.
239
240
  :param force_mode_cpu_load: Force the addition of a CPU in MODE_CPU_LOAD
240
241
  :param allow_multiple_runs: Allow multiple instances of codecarbon running in parallel. Defaults to False.
242
+ :param wue: WUE (Water Usage Effectiveness) of the datacenter, L/kWh.
241
243
  """
242
244
 
243
245
  # logger.info("base tracker init")
@@ -287,6 +289,7 @@ class BaseEmissionsTracker(ABC):
287
289
  self._set_from_conf(force_cpu_power, "force_cpu_power", None, float)
288
290
  self._set_from_conf(force_ram_power, "force_ram_power", None, float)
289
291
  self._set_from_conf(pue, "pue", 1.0, float)
292
+ self._set_from_conf(wue, "wue", 0, float)
290
293
  self._set_from_conf(force_mode_cpu_load, "force_mode_cpu_load", False, bool)
291
294
  self._set_from_conf(
292
295
  experiment_id, "experiment_id", "5b0fa12a-3dd7-45bb-9766-cc326314d9f1"
@@ -299,6 +302,7 @@ class BaseEmissionsTracker(ABC):
299
302
  self._start_time: Optional[float] = None
300
303
  self._last_measured_time: float = time.perf_counter()
301
304
  self._total_energy: Energy = Energy.from_energy(kWh=0)
305
+ self._total_water: Water = Water.from_litres(litres=0)
302
306
  self._total_cpu_energy: Energy = Energy.from_energy(kWh=0)
303
307
  self._total_gpu_energy: Energy = Energy.from_energy(kWh=0)
304
308
  self._total_ram_energy: Energy = Energy.from_energy(kWh=0)
@@ -703,6 +707,7 @@ class BaseEmissionsTracker(ABC):
703
707
  gpu_energy=self._total_gpu_energy.kWh,
704
708
  ram_energy=self._total_ram_energy.kWh,
705
709
  energy_consumed=self._total_energy.kWh,
710
+ water_consumed=self._total_water.litres,
706
711
  country_name=country_name,
707
712
  country_iso_code=country_iso_code,
708
713
  region=region,
@@ -721,6 +726,7 @@ class BaseEmissionsTracker(ABC):
721
726
  ram_total_size=self._conf.get("ram_total_size"),
722
727
  tracking_mode=self._conf.get("tracking_mode"),
723
728
  pue=self._pue,
729
+ wue=self._wue,
724
730
  )
725
731
  logger.debug(total_emissions)
726
732
  return total_emissions
@@ -778,7 +784,9 @@ class BaseEmissionsTracker(ABC):
778
784
  ) = hardware.measure_power_and_energy(last_duration=last_duration)
779
785
  # Apply the PUE of the datacenter to the consumed energy
780
786
  energy *= self._pue
787
+ water = Water.from_litres(litres=self._wue * energy.kWh)
781
788
  self._total_energy += energy
789
+ self._total_water += water
782
790
  if isinstance(hardware, CPU):
783
791
  self._total_cpu_energy += energy
784
792
  self._cpu_power = power
@@ -825,7 +833,7 @@ class BaseEmissionsTracker(ABC):
825
833
  f"Done measure for {hardware.__class__.__name__} - measurement time: {h_time:,.4f} s - last call {last_duration:,.2f} s"
826
834
  )
827
835
  logger.info(
828
- f"{self._total_energy.kWh:.6f} kWh of electricity used since the beginning."
836
+ f"{self._total_energy.kWh:.6f} kWh of electricity and {self._total_water.litres:.6f} L of water were used since the beginning."
829
837
  )
830
838
 
831
839
  def _measure_power_and_energy(self) -> None:
@@ -843,7 +851,11 @@ class BaseEmissionsTracker(ABC):
843
851
  raise e
844
852
 
845
853
  warning_duration = self._measure_power_secs * 3
846
- if last_duration > warning_duration and not self._scheduler._stopped:
854
+ if (
855
+ last_duration > warning_duration
856
+ and self._scheduler
857
+ and not self._scheduler._stopped
858
+ ):
847
859
  warn_msg = (
848
860
  "Background scheduler didn't run for a long period"
849
861
  + " (%ds), results might be inaccurate"
@@ -1066,6 +1078,7 @@ def track_emissions(
1066
1078
  force_cpu_power: Optional[int] = _sentinel,
1067
1079
  force_ram_power: Optional[int] = _sentinel,
1068
1080
  pue: Optional[int] = _sentinel,
1081
+ wue: Optional[float] = _sentinel,
1069
1082
  allow_multiple_runs: Optional[bool] = _sentinel,
1070
1083
  ):
1071
1084
  """
@@ -1141,6 +1154,7 @@ def track_emissions(
1141
1154
  :param force_cpu_power: cpu power to be used instead of automatic detection.
1142
1155
  :param force_ram_power: ram power to be used instead of automatic detection.
1143
1156
  :param pue: PUE (Power Usage Effectiveness) of the datacenter.
1157
+ :param wue: WUE (Water Usage Effectiveness) of the datacenter, L/kWh.
1144
1158
  :param allow_multiple_runs: Prevent multiple instances of codecarbon running. Defaults to False.
1145
1159
 
1146
1160
  :return: The decorated function
@@ -1181,6 +1195,7 @@ def track_emissions(
1181
1195
  force_cpu_power=force_cpu_power,
1182
1196
  force_ram_power=force_ram_power,
1183
1197
  pue=pue,
1198
+ wue=wue,
1184
1199
  allow_multiple_runs=allow_multiple_runs,
1185
1200
  )
1186
1201
  else:
@@ -1212,6 +1227,7 @@ def track_emissions(
1212
1227
  force_cpu_power=force_cpu_power,
1213
1228
  force_ram_power=force_ram_power,
1214
1229
  pue=pue,
1230
+ wue=wue,
1215
1231
  allow_multiple_runs=allow_multiple_runs,
1216
1232
  )
1217
1233
  tracker.start()
@@ -34,6 +34,7 @@ class Task:
34
34
  gpu_energy=self.emissions_data.gpu_energy,
35
35
  ram_energy=self.emissions_data.ram_energy,
36
36
  energy_consumed=self.emissions_data.energy_consumed,
37
+ water_consumed=self.emissions_data.water_consumed,
37
38
  country_name=self.emissions_data.country_name,
38
39
  country_iso_code=self.emissions_data.country_iso_code,
39
40
  region=self.emissions_data.region,
@@ -23,6 +23,7 @@ class EmissionsData:
23
23
  gpu_energy: float
24
24
  ram_energy: float
25
25
  energy_consumed: float
26
+ water_consumed: float
26
27
  country_name: str
27
28
  country_iso_code: str
28
29
  region: str
@@ -41,6 +42,7 @@ class EmissionsData:
41
42
  tracking_mode: str
42
43
  on_cloud: str = "N"
43
44
  pue: float = 1
45
+ wue: float = 0
44
46
 
45
47
  @property
46
48
  def values(self) -> OrderedDict:
@@ -55,6 +57,7 @@ class EmissionsData:
55
57
  self.gpu_energy -= previous_emission.gpu_energy
56
58
  self.ram_energy -= previous_emission.ram_energy
57
59
  self.energy_consumed -= previous_emission.energy_consumed
60
+ self.water_consumed -= previous_emission.water_consumed
58
61
  if delta_duration > 0:
59
62
  # emissions_rate in g/s : delta_emissions in kg.CO2 / delta_duration in s
60
63
  self.emissions_rate = delta_emissions / delta_duration
@@ -81,6 +84,7 @@ class TaskEmissionsData:
81
84
  gpu_energy: float
82
85
  ram_energy: float
83
86
  energy_consumed: float
87
+ water_consumed: float
84
88
  country_name: str
85
89
  country_iso_code: str
86
90
  region: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codecarbon
3
- Version: 3.0.7
3
+ Version: 3.0.8
4
4
  Author: Mila, DataForGood, BCG GAMMA, Comet.ml, Haverford College
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://codecarbon.io/
@@ -162,7 +162,7 @@ docs = "cd docs/edit && make docs"
162
162
  carbonboard = "python codecarbon/viz/carbonboard.py"
163
163
 
164
164
  [tool.bumpver]
165
- current_version = "3.0.7"
165
+ current_version = "3.0.8"
166
166
  version_pattern = "MAJOR.MINOR.PATCH[_TAGNUM]"
167
167
 
168
168
  [tool.bumpver.file_patterns]
@@ -172,3 +172,6 @@ version_pattern = "MAJOR.MINOR.PATCH[_TAGNUM]"
172
172
  "docs/edit/conf.py" = [
173
173
  '^release = "{version}"$',
174
174
  ]
175
+
176
+ [tool.pytest.ini_options]
177
+ pythonpath = "."
@@ -86,6 +86,7 @@ class TestApi(unittest.TestCase):
86
86
  gpu_power=0,
87
87
  ram_power=0.15,
88
88
  energy_consumed=3.0,
89
+ water_consumed=0.0,
89
90
  country_name="Groland",
90
91
  country_iso_code="GRD",
91
92
  region="EU",
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import shutil
3
+ import sys
3
4
  import tempfile
4
5
  import time
5
6
  import unittest
@@ -37,6 +38,16 @@ def heavy_computation(run_time_secs: float = 3):
37
38
  empty_conf = "[codecarbon]"
38
39
 
39
40
 
41
+ if sys.platform == "darwin":
42
+ mock_platform_cli_setup = mock.patch(
43
+ "codecarbon.core.powermetrics.ApplePowermetrics._setup_cli"
44
+ )
45
+ else:
46
+ mock_platform_cli_setup = mock.patch(
47
+ "codecarbon.core.cpu.IntelPowerGadget._setup_cli"
48
+ )
49
+
50
+
40
51
  @mock.patch("codecarbon.core.gpu.pynvml", fake_pynvml)
41
52
  @mock.patch("codecarbon.core.gpu.is_gpu_details_available", return_value=True)
42
53
  @mock.patch(
@@ -48,7 +59,7 @@ empty_conf = "[codecarbon]"
48
59
  return_value=CloudMetadata(provider=None, region=None),
49
60
  )
50
61
  @mock.patch("codecarbon.core.cpu.IntelPowerGadget._log_values")
51
- @mock.patch("codecarbon.core.cpu.IntelPowerGadget._setup_cli")
62
+ @mock_platform_cli_setup
52
63
  class TestCarbonTracker(unittest.TestCase):
53
64
  def setUp(self) -> None:
54
65
  fake_pynvml.DETAILS = TWO_GPU_DETAILS_RESPONSE_HANDLES
@@ -73,7 +84,7 @@ class TestCarbonTracker(unittest.TestCase):
73
84
  @responses.activate
74
85
  def test_carbon_tracker_TWO_GPU_PRIVATE_INFRA_CANADA(
75
86
  self,
76
- mock_setup_intel_cli,
87
+ mock_cli_setup,
77
88
  mock_log_values,
78
89
  mocked_get_gpu_details,
79
90
  mocked_env_cloud_details,
@@ -89,7 +100,7 @@ class TestCarbonTracker(unittest.TestCase):
89
100
  tracker = EmissionsTracker(measure_power_secs=1, save_to_file=False)
90
101
  # WHEN
91
102
  tracker.start()
92
- heavy_computation()
103
+ heavy_computation(run_time_secs=5)
93
104
  emissions = tracker.stop()
94
105
 
95
106
  # THEN
@@ -108,7 +119,7 @@ class TestCarbonTracker(unittest.TestCase):
108
119
  def test_carbon_tracker_timeout(
109
120
  self,
110
121
  mocked_requests_get,
111
- mock_setup_intel_cli,
122
+ mock_cli_setup,
112
123
  mock_log_values,
113
124
  mocked_get_gpu_details,
114
125
  mocked_env_cloud_details,
@@ -135,7 +146,7 @@ class TestCarbonTracker(unittest.TestCase):
135
146
 
136
147
  def test_graceful_start_failure(
137
148
  self,
138
- mock_setup_intel_cli,
149
+ mock_cli_setup,
139
150
  mock_log_values,
140
151
  mocked_get_gpu_details,
141
152
  mocked_env_cloud_details,
@@ -153,7 +164,7 @@ class TestCarbonTracker(unittest.TestCase):
153
164
 
154
165
  def test_graceful_stop_failure(
155
166
  self,
156
- mock_setup_intel_cli,
167
+ mock_cli_setup,
157
168
  mock_log_values,
158
169
  mocked_get_gpu_details,
159
170
  mocked_env_cloud_details,
@@ -172,7 +183,7 @@ class TestCarbonTracker(unittest.TestCase):
172
183
  @responses.activate
173
184
  def test_decorator_ONLINE_NO_ARGS(
174
185
  self,
175
- mock_setup_intel_cli,
186
+ mock_cli_setup,
176
187
  mock_log_values,
177
188
  mocked_get_gpu_details,
178
189
  mocked_env_cloud_details,
@@ -199,7 +210,7 @@ class TestCarbonTracker(unittest.TestCase):
199
210
  @responses.activate
200
211
  def test_decorator_ONLINE_WITH_ARGS(
201
212
  self,
202
- mock_setup_intel_cli,
213
+ mock_cli_setup,
203
214
  mock_log_values,
204
215
  mocked_get_gpu_details,
205
216
  mocked_env_cloud_details,
@@ -225,7 +236,7 @@ class TestCarbonTracker(unittest.TestCase):
225
236
 
226
237
  def test_decorator_OFFLINE_NO_COUNTRY(
227
238
  self,
228
- mock_setup_intel_cli,
239
+ mock_cli_setup,
229
240
  mock_log_values,
230
241
  mocked_get_gpu_details,
231
242
  mocked_env_cloud_details,
@@ -241,7 +252,7 @@ class TestCarbonTracker(unittest.TestCase):
241
252
 
242
253
  def test_decorator_OFFLINE_WITH_LOC_ARGS(
243
254
  self,
244
- mock_setup_intel_cli,
255
+ mock_cli_setup,
245
256
  mock_log_values,
246
257
  mocked_get_gpu_details,
247
258
  mocked_env_cloud_details,
@@ -264,7 +275,7 @@ class TestCarbonTracker(unittest.TestCase):
264
275
 
265
276
  def test_decorator_OFFLINE_WITH_CLOUD_ARGS(
266
277
  self,
267
- mock_setup_intel_cli,
278
+ mock_cli_setup,
268
279
  mock_log_values,
269
280
  mocked_get_gpu_details,
270
281
  mocked_env_cloud_details,
@@ -287,7 +298,7 @@ class TestCarbonTracker(unittest.TestCase):
287
298
 
288
299
  def test_offline_tracker_country_name(
289
300
  self,
290
- mock_setup_intel_cli,
301
+ mock_cli_setup,
291
302
  mock_log_values,
292
303
  mocked_get_gpu_details,
293
304
  mocked_env_cloud_details,
@@ -309,7 +320,7 @@ class TestCarbonTracker(unittest.TestCase):
309
320
 
310
321
  def test_offline_tracker_invalid_headers(
311
322
  self,
312
- mock_setup_intel_cli,
323
+ mock_cli_setup,
313
324
  mock_log_values,
314
325
  mocked_get_gpu_details,
315
326
  mocked_env_cloud_details,
@@ -341,7 +352,7 @@ class TestCarbonTracker(unittest.TestCase):
341
352
 
342
353
  def test_offline_tracker_valid_headers(
343
354
  self,
344
- mock_setup_intel_cli,
355
+ mock_cli_setup,
345
356
  mock_log_values,
346
357
  mocked_get_gpu_details,
347
358
  mocked_env_cloud_details,
@@ -378,7 +389,7 @@ class TestCarbonTracker(unittest.TestCase):
378
389
  @responses.activate
379
390
  def test_carbon_tracker_online_context_manager_TWO_GPU_PRIVATE_INFRA_CANADA(
380
391
  self,
381
- mock_setup_intel_cli,
392
+ mock_cli_setup,
382
393
  mock_log_values,
383
394
  mocked_get_gpu_details,
384
395
  mocked_env_cloud_details,
@@ -394,7 +405,7 @@ class TestCarbonTracker(unittest.TestCase):
394
405
 
395
406
  # WHEN
396
407
  with EmissionsTracker(measure_power_secs=1, save_to_file=False) as tracker:
397
- heavy_computation()
408
+ heavy_computation(run_time_secs=5)
398
409
 
399
410
  # THEN
400
411
  self.assertGreaterEqual(
@@ -408,17 +419,18 @@ class TestCarbonTracker(unittest.TestCase):
408
419
  self.assertIsInstance(tracker.final_emissions, float)
409
420
  self.assertAlmostEqual(tracker.final_emissions, 6.262572537957655e-05, places=2)
410
421
 
422
+ @mock.patch("codecarbon.external.ram.RAM.measure_power_and_energy")
423
+ @mock.patch("codecarbon.external.hardware.CPU.measure_power_and_energy")
411
424
  @mock.patch(
412
- "codecarbon.external.ram.RAM.measure_power_and_energy"
413
- ) # Corrected path for RAM
414
- @mock.patch(
415
- "codecarbon.external.hardware.CPU.measure_power_and_energy"
416
- ) # Path for CPU is likely correct
425
+ "codecarbon.external.hardware.AppleSiliconChip.measure_power_and_energy",
426
+ autospec=True,
427
+ )
417
428
  def test_task_energy_with_live_update_interference(
418
429
  self,
430
+ mock_apple_silicon_measure,
419
431
  mock_cpu_measure, # Method decorator (innermost)
420
432
  mock_ram_measure, # Method decorator (outermost)
421
- mock_setup_intel_cli, # Class decorator (innermost)
433
+ mock_cli_setup, # Class decorator (innermost)
422
434
  mock_log_values, # Class decorator
423
435
  mocked_env_cloud_details, # Class decorator
424
436
  mocked_get_gpu_details, # Class decorator
@@ -428,6 +440,19 @@ class TestCarbonTracker(unittest.TestCase):
428
440
  # Configure mocks to return specific, non-zero energy values
429
441
  cpu_energy_val_task = 0.0001
430
442
  ram_energy_val_task = 0.00005
443
+
444
+ # On a Mac, AppleSiliconChip.measure_power_and_energy is called for both CPUs and GPU
445
+ # so we need to check which it is before returning a value.
446
+ # We chose to return 0 for a GPU to be consistent when testing on Intel.
447
+ def apple_silicon_side_effect(hardware, *args, **kwargs):
448
+ if hardware.chip_part == "CPU":
449
+ return (
450
+ Power.from_watts(10),
451
+ Energy.from_energy(kWh=cpu_energy_val_task),
452
+ )
453
+ return (Power.from_watts(0), Energy.from_energy(kWh=0))
454
+
455
+ mock_apple_silicon_measure.side_effect = apple_silicon_side_effect
431
456
  mock_cpu_measure.return_value = (
432
457
  Power.from_watts(10),
433
458
  Energy.from_energy(kWh=cpu_energy_val_task),
@@ -497,14 +522,18 @@ class TestCarbonTracker(unittest.TestCase):
497
522
  )
498
523
 
499
524
  # Verify mocks were called as expected
500
- # They are called once in _measure_power_and_energy inside stop_task
501
- mock_cpu_measure.assert_called_once()
525
+ # They are called from within _measure_power_and_energy inside stop_task.
526
+ # As noted above, mock_apple_silicon_measure is called twice on a Mac, once for CPU and once for GPU.
527
+ assert (
528
+ mock_cpu_measure.call_count == 1
529
+ or mock_apple_silicon_measure.call_count == 2
530
+ )
502
531
  mock_ram_measure.assert_called_once()
503
532
 
504
533
  @responses.activate
505
534
  def test_carbon_tracker_offline_context_manager(
506
535
  self,
507
- mock_setup_intel_cli,
536
+ mock_cli_setup,
508
537
  mock_log_values,
509
538
  mocked_get_gpu_details,
510
539
  mocked_env_cloud_details,
@@ -525,7 +554,7 @@ class TestCarbonTracker(unittest.TestCase):
525
554
  def test_scheduler_warning_suppressed_when_stopped(
526
555
  self,
527
556
  mock_logger,
528
- mock_setup_intel_cli,
557
+ mock_cli_setup,
529
558
  mock_log_values,
530
559
  mocked_get_gpu_details,
531
560
  mocked_env_cloud_details,
@@ -567,7 +596,7 @@ class TestCarbonTracker(unittest.TestCase):
567
596
  def test_scheduler_warning_shown_when_running(
568
597
  self,
569
598
  mock_logger,
570
- mock_setup_intel_cli,
599
+ mock_cli_setup,
571
600
  mock_log_values,
572
601
  mocked_get_gpu_details,
573
602
  mocked_env_cloud_details,
@@ -1 +0,0 @@
1
- __version__ = "3.0.7"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes