Skip to content

Commit 8968bd1

Browse files
Fix AttributeError in Emissions class and add comprehensive parametrized tests
- Fixed bug where codecarbon_offline attribute was not set when codecarbon_config is None - Added self.codecarbon_offline = False for default configuration - Created comprehensive test suite with pytest parametrization - Tests cover all offline parameters, online mode, and attribute existence - Reduced code duplication by using @pytest.mark.parametrize - All 15 test cases pass (12 run, 3 skipped when codecarbon not installed) Fixes issues in: - examples/tutorials/tutorial_3_benchmarking_multiple_pipelines.py - examples/advanced_examples/plot_filterbank_csp_vs_csp.py - examples/advanced_examples/plot_hinss2021_classification.py - examples/advanced_examples/plot_use_an_X_y_dataset.py - examples/advanced_examples/plot_statistical_analysis.py
1 parent 547ad22 commit 8968bd1

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

moabb/evaluations/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ def __init__(self, codecarbon_config=None):
478478
if codecarbon_config is None:
479479
# Default CodeCarbon configurations
480480
self.codecarbon_config = dict(save_to_file=False, log_level="error")
481+
self.codecarbon_offline = False
481482
else:
482483
# Offline mode parameters are a superset of online mode parameters
483484
# Hardcode check avoids object reflection for security and compatibility

moabb/tests/test_emissions.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""Tests for the Emissions class in evaluations/utils.py."""
2+
from unittest.mock import MagicMock, patch
3+
4+
import pytest
5+
6+
from moabb.evaluations.utils import Emissions
7+
8+
try:
9+
from codecarbon import EmissionsTracker, OfflineEmissionsTracker
10+
CODECARBON_AVAILABLE = True
11+
except ImportError:
12+
CODECARBON_AVAILABLE = False
13+
14+
15+
def test_default_config():
16+
"""Test Emissions initialization with default config (None)."""
17+
emissions = Emissions()
18+
19+
# Check default configuration is set
20+
assert emissions.codecarbon_config == dict(save_to_file=False, log_level="error")
21+
# Check codecarbon_offline is set to False for default config
22+
assert emissions.codecarbon_offline is False
23+
24+
25+
def test_custom_config_online_mode():
26+
"""Test Emissions initialization with custom config (online mode)."""
27+
custom_config = {
28+
"save_to_file": True,
29+
"log_level": "info",
30+
"project_name": "test_project"
31+
}
32+
emissions = Emissions(codecarbon_config=custom_config)
33+
34+
# Check custom configuration is set
35+
assert emissions.codecarbon_config == custom_config
36+
# Check codecarbon_offline is False when no offline params are present
37+
assert emissions.codecarbon_offline is False
38+
39+
40+
@pytest.mark.parametrize("offline_param,param_value", [
41+
("country_iso_code", "USA"),
42+
("region", "us-west-1"),
43+
("cloud_provider", "aws"),
44+
("cloud_region", "us-west-1"),
45+
("country_2letter_iso_code", "US"),
46+
])
47+
def test_custom_config_offline_mode(offline_param, param_value):
48+
"""Test Emissions initialization with various offline parameters."""
49+
custom_config = {
50+
"save_to_file": False,
51+
"log_level": "error",
52+
offline_param: param_value
53+
}
54+
emissions = Emissions(codecarbon_config=custom_config)
55+
56+
# Check custom configuration is set
57+
assert emissions.codecarbon_config == custom_config
58+
# Check codecarbon_offline is True when offline param is present
59+
assert emissions.codecarbon_offline is True
60+
61+
62+
def test_custom_config_offline_mode_multiple_params():
63+
"""Test Emissions initialization with multiple offline parameters."""
64+
custom_config = {
65+
"save_to_file": True,
66+
"log_level": "info",
67+
"country_iso_code": "USA",
68+
"region": "california",
69+
"cloud_provider": "aws"
70+
}
71+
emissions = Emissions(codecarbon_config=custom_config)
72+
73+
assert emissions.codecarbon_config == custom_config
74+
assert emissions.codecarbon_offline is True
75+
76+
77+
@pytest.mark.skipif(not CODECARBON_AVAILABLE, reason="codecarbon not installed")
78+
@patch('moabb.evaluations.utils.EmissionsTracker')
79+
def test_create_tracker_default_config(mock_emissions_tracker):
80+
"""Test create_tracker with default config uses EmissionsTracker."""
81+
mock_tracker = MagicMock()
82+
mock_emissions_tracker.return_value = mock_tracker
83+
84+
emissions = Emissions()
85+
tracker = emissions.create_tracker()
86+
87+
# Verify EmissionsTracker was called with correct config
88+
mock_emissions_tracker.assert_called_once_with(
89+
save_to_file=False,
90+
log_level="error"
91+
)
92+
assert tracker == mock_tracker
93+
94+
95+
@pytest.mark.skipif(not CODECARBON_AVAILABLE, reason="codecarbon not installed")
96+
@patch('moabb.evaluations.utils.EmissionsTracker')
97+
def test_create_tracker_online_mode(mock_emissions_tracker):
98+
"""Test create_tracker with online config uses EmissionsTracker."""
99+
mock_tracker = MagicMock()
100+
mock_emissions_tracker.return_value = mock_tracker
101+
102+
custom_config = {
103+
"save_to_file": True,
104+
"log_level": "info"
105+
}
106+
emissions = Emissions(codecarbon_config=custom_config)
107+
tracker = emissions.create_tracker()
108+
109+
# Verify EmissionsTracker was called with custom config
110+
mock_emissions_tracker.assert_called_once_with(
111+
save_to_file=True,
112+
log_level="info"
113+
)
114+
assert tracker == mock_tracker
115+
116+
117+
@pytest.mark.skipif(not CODECARBON_AVAILABLE, reason="codecarbon not installed")
118+
@patch('moabb.evaluations.utils.OfflineEmissionsTracker')
119+
def test_create_tracker_offline_mode(mock_offline_emissions_tracker):
120+
"""Test create_tracker with offline config uses OfflineEmissionsTracker."""
121+
mock_tracker = MagicMock()
122+
mock_offline_emissions_tracker.return_value = mock_tracker
123+
124+
custom_config = {
125+
"save_to_file": False,
126+
"log_level": "error",
127+
"country_iso_code": "USA"
128+
}
129+
emissions = Emissions(codecarbon_config=custom_config)
130+
tracker = emissions.create_tracker()
131+
132+
# Verify OfflineEmissionsTracker was called with custom config
133+
mock_offline_emissions_tracker.assert_called_once_with(
134+
save_to_file=False,
135+
log_level="error",
136+
country_iso_code="USA"
137+
)
138+
assert tracker == mock_tracker
139+
140+
141+
@pytest.mark.parametrize("config,expected_offline", [
142+
(None, False),
143+
({}, False),
144+
({"save_to_file": False}, False),
145+
({"country_iso_code": "USA"}, True),
146+
])
147+
def test_codecarbon_offline_attribute_always_exists(config, expected_offline):
148+
"""Test that codecarbon_offline attribute always exists regardless of config."""
149+
emissions = Emissions(codecarbon_config=config)
150+
assert hasattr(emissions, 'codecarbon_offline')
151+
assert emissions.codecarbon_offline == expected_offline

0 commit comments

Comments
 (0)