Skip to content

Commit 21a9b0f

Browse files
author
benoit-cty
committed
lint
1 parent 5fe1c5f commit 21a9b0f

4 files changed

Lines changed: 171 additions & 73 deletions

File tree

codecarbon/emissions_tracker.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ def __init__(
185185
self._external_conf = get_hierarchical_config()
186186

187187
# Process custom_carbon_intensity_g_co2e_kwh immediately after loading _external_conf
188-
custom_intensity_str = self._external_conf.get("custom_carbon_intensity_g_co2e_kwh")
188+
custom_intensity_str = self._external_conf.get(
189+
"custom_carbon_intensity_g_co2e_kwh"
190+
)
189191
parsed_intensity = None
190192
if custom_intensity_str is not None:
191193
custom_intensity_str_stripped = custom_intensity_str.strip()
@@ -202,12 +204,12 @@ def __init__(
202204
# logger.info( # Info log for successful positive value (if enabled)
203205
# f"CODECARBON : Parsed custom carbon intensity: {value} gCO2e/kWh."
204206
# )
205-
else: # Zero or negative
207+
else: # Zero or negative
206208
logger.warning(
207209
f"CODECARBON : Invalid value for custom_carbon_intensity_g_co2e_kwh: '{custom_intensity_str_stripped}'. "
208210
"It must be a positive number. Using default calculation methods."
209211
)
210-
except ValueError: # Non-numeric
212+
except ValueError: # Non-numeric
211213
logger.warning(
212214
f"CODECARBON : Invalid value for custom_carbon_intensity_g_co2e_kwh: '{custom_intensity_str_stripped}'. "
213215
"It must be a numeric value. Using default calculation methods."
@@ -277,8 +279,10 @@ def __init__(
277279
# logger.info("base tracker init")
278280
# self._external_conf = get_hierarchical_config() # Moved to the top
279281
self._set_from_conf(allow_multiple_runs, "allow_multiple_runs", True, bool)
280-
if self._allow_multiple_runs: # This uses self._allow_multiple_runs which is set by _set_from_conf
281-
logger.warning( # This log might still occur if allow_multiple_runs is True in mock_get_config
282+
if (
283+
self._allow_multiple_runs
284+
): # This uses self._allow_multiple_runs which is set by _set_from_conf
285+
logger.warning( # This log might still occur if allow_multiple_runs is True in mock_get_config
282286
"Multiple instances of codecarbon are allowed to run at the same time."
283287
)
284288
else:
@@ -333,11 +337,14 @@ def __init__(
333337

334338
# Conditional info log for using custom intensity
335339
if self.custom_carbon_intensity_g_co2e_kwh is not None:
336-
logger.info(
340+
logger.info(
337341
f"CODECARBON : Using custom carbon intensity: {self.custom_carbon_intensity_g_co2e_kwh} gCO2e/kWh."
338342
)
339343

340-
assert self._tracking_mode in ["machine", "process"] # self._tracking_mode is set by a _set_from_conf call
344+
assert self._tracking_mode in [
345+
"machine",
346+
"process",
347+
] # self._tracking_mode is set by a _set_from_conf call
341348
set_logger_level(self._log_level)
342349
set_logger_format(self._logger_preamble)
343350

tests/test_config.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import unittest
3+
from os import Path
34
from textwrap import dedent
45
from unittest import mock
56
from unittest.mock import patch
@@ -122,28 +123,36 @@ def test_load_custom_carbon_intensity_from_config_file(self):
122123

123124
# Mock open to simulate only the global file existing and being read
124125
def mock_path_exists_side_effect(*args_received, **kwargs_received):
125-
print(f"mock_path_exists_side_effect called with: args={args_received}, kwargs={kwargs_received}")
126+
print(
127+
f"mock_path_exists_side_effect called with: args={args_received}, kwargs={kwargs_received}"
128+
)
126129
if not args_received:
127130
# This would explain the TypeError if it's called with no args
128131
print("ERROR: mock_path_exists_side_effect called with no arguments!")
129-
return False # Default or raise error
132+
return False # Default or raise error
130133
path_instance = args_received[0]
131134
path_str_resolved = str(path_instance.expanduser().resolve())
132135
# Only the global path should "exist" for this test
133-
if path_str_resolved == str((Path.home() / ".codecarbon.config").expanduser().resolve()):
136+
if path_str_resolved == str(
137+
(Path.home() / ".codecarbon.config").expanduser().resolve()
138+
):
134139
return True
135140
# Allow local path to "not exist" explicitly if needed by other tests,
136141
# but for this test, default to False for unspecified paths.
137-
if path_str_resolved == str((Path.cwd() / ".codecarbon.config").expanduser().resolve()):
142+
if path_str_resolved == str(
143+
(Path.cwd() / ".codecarbon.config").expanduser().resolve()
144+
):
138145
return False
139-
return False # Default for any other path checks, e.g. parent dirs
146+
return False # Default for any other path checks, e.g. parent dirs
140147

141148
# This mock_open will be used when Path(global_path).exists() is true
142149
m_open = mock.mock_open(read_data=global_conf_content)
143150

144-
with patch("builtins.open", m_open), \
145-
patch("pathlib.Path.exists", side_effect=mock_path_exists_side_effect), \
146-
patch("codecarbon.core.config.parse_env_config", return_value={"codecarbon": {}}): # Ensure no env interference
151+
with patch("builtins.open", m_open), patch(
152+
"pathlib.Path.exists", side_effect=mock_path_exists_side_effect
153+
), patch(
154+
"codecarbon.core.config.parse_env_config", return_value={"codecarbon": {}}
155+
): # Ensure no env interference
147156

148157
conf = get_hierarchical_config()
149158
self.assertEqual(conf.get("custom_carbon_intensity_g_co2e_kwh"), "67.89")
@@ -212,18 +221,26 @@ def test_measure_power_secs_loading_in_get_hierarchical_config(self):
212221
"""
213222
)
214223

215-
def path_exists_side_effect(*args, **kwargs_inner): # Renamed kwargs to avoid conflict
224+
def path_exists_side_effect(
225+
*args, **kwargs_inner
226+
): # Renamed kwargs to avoid conflict
216227
# args[0] should be the Path instance
217-
print(f"MOCK pathlib.Path.exists called with args: {args}, kwargs: {kwargs_inner}")
228+
print(
229+
f"MOCK pathlib.Path.exists called with args: {args}, kwargs: {kwargs_inner}"
230+
)
218231
if not args:
219232
print("MOCK pathlib.Path.exists: ERROR - called with no args")
220233
return False
221234
path_instance = args[0]
222235
s_path = str(path_instance.expanduser().resolve())
223-
if s_path == str((Path.home() / ".codecarbon.config").expanduser().resolve()):
236+
if s_path == str(
237+
(Path.home() / ".codecarbon.config").expanduser().resolve()
238+
):
224239
print(f"Mocking Path.exists for global: {s_path} -> True")
225240
return True
226-
if s_path == str((Path.cwd() / ".codecarbon.config").expanduser().resolve()):
241+
if s_path == str(
242+
(Path.cwd() / ".codecarbon.config").expanduser().resolve()
243+
):
227244
print(f"Mocking Path.exists for local: {s_path} -> False")
228245
return False
229246
print(f"Mocking Path.exists for other: {s_path} -> False")
@@ -232,9 +249,11 @@ def path_exists_side_effect(*args, **kwargs_inner): # Renamed kwargs to avoid co
232249
# Mock open to provide content for the global file
233250
m_open = mock.mock_open(read_data=global_conf_content)
234251

235-
with patch("builtins.open", m_open), \
236-
patch("pathlib.Path.exists", side_effect=path_exists_side_effect), \
237-
patch("codecarbon.core.config.parse_env_config", return_value={"codecarbon": {}}):
252+
with patch("builtins.open", m_open), patch(
253+
"pathlib.Path.exists", side_effect=path_exists_side_effect
254+
), patch(
255+
"codecarbon.core.config.parse_env_config", return_value={"codecarbon": {}}
256+
):
238257

239258
conf = get_hierarchical_config()
240259
self.assertEqual(conf.get("measure_power_secs"), "10")
@@ -287,7 +306,6 @@ def path_exists_side_effect(*args, **kwargs_inner): # Renamed kwargs to avoid co
287306
# self.assertEqual(tracker._project_name, "test-project") # This would be overwritten by env
288307
# self.assertTrue(tracker._save_to_file)
289308

290-
291309
@mock.patch.dict(
292310
os.environ,
293311
{

tests/test_emissions.py

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import unittest
2+
from unittest import mock
3+
4+
import pandas as pd
25

3-
from tests.testutils import get_test_data_source # Added back
46
from codecarbon.core.emissions import Emissions
57
from codecarbon.core.units import Energy
68
from codecarbon.external.geography import CloudMetadata, GeoMetadata
79
from codecarbon.input import DataSource
8-
from unittest import mock
9-
import pandas as pd
10+
from tests.testutils import get_test_data_source # Added back
1011

1112

1213
class TestEmissions(unittest.TestCase):
@@ -22,31 +23,35 @@ def test_get_emissions_CLOUD_AWS(self):
2223
# Test original behavior when no custom intensity is set
2324
emissions_calculator = Emissions(self._data_source)
2425
# WHEN
25-
emissions = emissions_calculator.get_cloud_emissions( # Changed from self._emissions
26-
Energy.from_energy(kWh=0.6), # Using original energy value for this specific test
27-
CloudMetadata(provider="aws", region="us-east-1"),
26+
emissions = (
27+
emissions_calculator.get_cloud_emissions( # Changed from self._emissions
28+
Energy.from_energy(
29+
kWh=0.6
30+
), # Using original energy value for this specific test
31+
CloudMetadata(provider="aws", region="us-east-1"),
32+
)
2833
)
2934
# THEN
3035
assert isinstance(emissions, float)
31-
self.assertAlmostEqual(emissions, 0.285, places=3) # Original assertion value
36+
self.assertAlmostEqual(emissions, 0.285, places=3) # Original assertion value
3237

3338
def test_emissions_CLOUD_AZURE(self):
3439
# Test original behavior when no custom intensity is set
3540
emissions_calculator = Emissions(self._data_source)
3641
# WHEN
3742
emissions = emissions_calculator.get_cloud_emissions(
38-
Energy.from_energy(kWh=1.5), # Original energy
43+
Energy.from_energy(kWh=1.5), # Original energy
3944
CloudMetadata(provider="azure", region="eastus"),
4045
)
4146
# THEN
4247
assert isinstance(emissions, float)
43-
self.assertAlmostEqual(emissions, 0.7125, places=4) # Original assertion
48+
self.assertAlmostEqual(emissions, 0.7125, places=4) # Original assertion
4449

4550
def test_emissions_CLOUD_GCP(self):
4651
# Test original behavior when no custom intensity is set
4752
emissions_calculator = Emissions(self._data_source)
4853
emissions = emissions_calculator.get_cloud_emissions(
49-
Energy.from_energy(kWh=0.01), # Original energy
54+
Energy.from_energy(kWh=0.01), # Original energy
5055
CloudMetadata(provider="gcp", region="us-central1"),
5156
)
5257
# THEN
@@ -55,7 +60,6 @@ def test_emissions_CLOUD_GCP(self):
5560
# Actual output was 0.0043, implying 430 g/kWh
5661
self.assertAlmostEqual(emissions, 0.0043, places=6)
5762

58-
5963
def test_get_carbon_intensity_per_source_data(self):
6064
# This test doesn't use an Emissions instance directly for its main assertion
6165
carbon_intensity = self._data_source.get_carbon_intensity_per_source_data()
@@ -84,7 +88,9 @@ def test_get_emissions_PRIVATE_INFRA_UNKNOWN(self):
8488
self._data_source.get_carbon_intensity_per_source_data()
8589
)
8690
default_emissions_g_kwh = carbon_intensity_per_source.get("world_average")
87-
expected_emissions_kg = default_emissions_g_kwh * 1000 / 1000 # kWh * g/kWh / g/kg
91+
expected_emissions_kg = (
92+
default_emissions_g_kwh * 1000 / 1000
93+
) # kWh * g/kWh / g/kg
8894
assert isinstance(emissions, float)
8995
self.assertAlmostEqual(emissions, expected_emissions_kg, places=2)
9096

@@ -108,19 +114,28 @@ def test_private_infra_with_positive_custom_intensity(
108114
# f"Using custom carbon intensity for private infrastructure emissions: {custom_intensity} gCO2e/kWh"
109115
# )
110116
mock_co2_signal_get_emissions.assert_not_called()
111-
with mock.patch.object(self._data_source, 'get_country_emissions_data', wraps=self._data_source.get_country_emissions_data) as wrapped_method:
117+
with mock.patch.object(
118+
self._data_source,
119+
"get_country_emissions_data",
120+
wraps=self._data_source.get_country_emissions_data,
121+
) as wrapped_method:
112122
# Call again to ensure no fallback logic is triggered by mistake
113-
emissions_calculator.get_private_infra_emissions(self.mock_energy, self.mock_geo)
123+
emissions_calculator.get_private_infra_emissions(
124+
self.mock_energy, self.mock_geo
125+
)
114126
wrapped_method.assert_not_called()
115127

116-
117-
@mock.patch("codecarbon.core.co2_signal.get_emissions") # Mock the co2_signal path
118-
@mock.patch.object(DataSource, "get_global_energy_mix_data") # Mock the DataSource path for country emissions
128+
@mock.patch("codecarbon.core.co2_signal.get_emissions") # Mock the co2_signal path
129+
@mock.patch.object(
130+
DataSource, "get_global_energy_mix_data"
131+
) # Mock the DataSource path for country emissions
119132
def test_private_infra_with_none_custom_intensity_fallback_co2_signal(
120133
self, mock_get_global_energy_mix_data, mock_co2_signal_get_emissions
121134
):
122135
mock_co2_signal_get_emissions.return_value = 0.123
123-
emissions_calculator = Emissions(self._data_source, co2_signal_api_token="dummy_token")
136+
emissions_calculator = Emissions(
137+
self._data_source, co2_signal_api_token="dummy_token"
138+
)
124139

125140
actual_emissions = emissions_calculator.get_private_infra_emissions(
126141
self.mock_energy, self.mock_geo
@@ -129,16 +144,24 @@ def test_private_infra_with_none_custom_intensity_fallback_co2_signal(
129144
mock_co2_signal_get_emissions.assert_called_once_with(
130145
self.mock_energy, self.mock_geo, "dummy_token"
131146
)
132-
mock_get_global_energy_mix_data.assert_not_called() # Ensure it doesn't go to the other path
147+
mock_get_global_energy_mix_data.assert_not_called() # Ensure it doesn't go to the other path
133148

134-
@mock.patch.object(DataSource, "get_global_energy_mix_data") # Mock the DataSource path for country emissions
149+
@mock.patch.object(
150+
DataSource, "get_global_energy_mix_data"
151+
) # Mock the DataSource path for country emissions
135152
def test_private_infra_with_none_custom_intensity_fallback_datasource(
136153
self, mock_get_global_energy_mix_data
137154
):
138155
# Simulate no CO2 signal token, forcing fallback to DataSource
139156
# USA (from self.mock_geo) has carbon_intensity: 381.98 g/kWh in test_data_source
140157
expected_intensity_g_kwh = 381.98
141-
mock_get_global_energy_mix_data.return_value = {"USA": {"country_name": "United States", "carbon_intensity": expected_intensity_g_kwh, "total_TWh": 100}}
158+
mock_get_global_energy_mix_data.return_value = {
159+
"USA": {
160+
"country_name": "United States",
161+
"carbon_intensity": expected_intensity_g_kwh,
162+
"total_TWh": 100,
163+
}
164+
}
142165

143166
emissions_calculator = Emissions(self._data_source, co2_signal_api_token=None)
144167
expected_emissions = self.mock_energy.kWh * (expected_intensity_g_kwh / 1000.0)
@@ -149,7 +172,6 @@ def test_private_infra_with_none_custom_intensity_fallback_datasource(
149172
self.assertAlmostEqual(actual_emissions, expected_emissions, places=5)
150173
mock_get_global_energy_mix_data.assert_called_once()
151174

152-
153175
@mock.patch("codecarbon.core.emissions.logger")
154176
@mock.patch.object(DataSource, "get_cloud_emissions_data")
155177
def test_cloud_emissions_with_positive_custom_intensity(
@@ -175,7 +197,13 @@ def test_cloud_emissions_with_positive_custom_intensity(
175197
def test_cloud_emissions_with_none_custom_intensity(self, mock_get_cloud_data):
176198
expected_impact_g_kwh = 475.0 # For aws us-east-1 from test data
177199
# Create a DataFrame mock that behaves like the one from get_cloud_emissions_data
178-
mock_df = pd.DataFrame({'provider': ['aws'], 'region': ['us-east-1'], 'impact': [expected_impact_g_kwh]})
200+
mock_df = pd.DataFrame(
201+
{
202+
"provider": ["aws"],
203+
"region": ["us-east-1"],
204+
"impact": [expected_impact_g_kwh],
205+
}
206+
)
179207
mock_get_cloud_data.return_value = mock_df
180208

181209
emissions_calculator = Emissions(self._data_source)
@@ -197,7 +225,6 @@ def test_get_emissions_PRIVATE_INFRA_NOR(self):
197225
assert isinstance(emissions, float)
198226
self.assertAlmostEqual(emissions, 26.4 / 1_000, places=4)
199227

200-
201228
def test_get_emissions_PRIVATE_INFRA_USA_WITH_REGION(self):
202229
emissions_calculator = Emissions(self._data_source)
203230
emissions = emissions_calculator.get_private_infra_emissions(
@@ -211,7 +238,6 @@ def test_get_emissions_PRIVATE_INFRA_USA_WITH_REGION(self):
211238
# This implies an intensity of approx 0.36800765 kg/kWh for Illinois from test data.
212239
self.assertAlmostEqual(emissions, 0.11040229633309799, places=8)
213240

214-
215241
def test_get_emissions_PRIVATE_INFRA_USA_WITHOUT_REGION(self):
216242
emissions_calculator = Emissions(self._data_source)
217243
emissions = emissions_calculator.get_private_infra_emissions(
@@ -229,7 +255,7 @@ def test_get_emissions_PRIVATE_INFRA_USA_WITHOUT_COUNTRYNAME(self):
229255
Energy.from_energy(kWh=0.3), GeoMetadata(country_iso_code="USA")
230256
)
231257
assert isinstance(emissions, float)
232-
self.assertAlmostEqual(emissions, 0.114594, places=6) # Same as above
258+
self.assertAlmostEqual(emissions, 0.114594, places=6) # Same as above
233259

234260
def test_get_emissions_PRIVATE_INFRA_CANADA_WITHOUT_REGION(self):
235261
emissions_calculator = Emissions(self._data_source)
@@ -255,7 +281,6 @@ def test_get_emissions_PRIVATE_INFRA_CANADA_WITH_REGION(self):
255281
# 3 kWh * 0.01814368 kg/kWh = 0.05443104
256282
self.assertAlmostEqual(emissions, 0.05443, places=5)
257283

258-
259284
def test_get_emissions_PRIVATE_INFRA_unknown_country(self):
260285
emissions_calculator = Emissions(self._data_source)
261286
emissions = emissions_calculator.get_private_infra_emissions(

0 commit comments

Comments
 (0)