From 60fae3ded30a6ac8fb75caa2b246f076608cd18a Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 20:57:58 +0530 Subject: [PATCH 01/15] test: Add PVLive tests with proper request mocking --- .gitignore | 2 +- tests/data/test_pvlive_data.py | 73 +++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 800a94b..2b68b1b 100644 --- a/.gitignore +++ b/.gitignore @@ -93,4 +93,4 @@ node_modules/ .pypirc # Data -data/ +/data/ diff --git a/tests/data/test_pvlive_data.py b/tests/data/test_pvlive_data.py index 7a2265e..fb03cf7 100644 --- a/tests/data/test_pvlive_data.py +++ b/tests/data/test_pvlive_data.py @@ -1,64 +1,99 @@ import pytest -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch from datetime import datetime import pytz +import requests +from pvlive_api.pvlive import PVLiveException from open_data_pvnet.scripts.fetch_pvlive_data import PVLiveData +class MockResponse: + def __init__(self, json_data, status_code=200): + self.json_data = json_data + self.status_code = status_code + self.text = "" + + def json(self): + return self.json_data + + def raise_for_status(self): + if self.status_code != 200: + raise requests.exceptions.HTTPError() + + +@pytest.fixture(autouse=True) +def mock_requests(): + """ + Mock requests.get to prevent actual API calls. + """ + with patch('requests.get') as mock_get: + # Mock the GSP list response + mock_get.return_value = MockResponse({ + "data": [ + {"gsp_id": 0, "gsp_name": "National"}, + {"gsp_id": 1, "gsp_name": "Region 1"} + ] + }) + yield mock_get + + @pytest.fixture -def pvlive_mock(): +def pvlive_data(): """ Fixture to create a PVLiveData instance with mocked PVLive methods. """ - pvlive = PVLiveData() - pvlive.pvl.latest = MagicMock() - pvlive.pvl.between = MagicMock() - pvlive.pvl.at_time = MagicMock() - return pvlive + with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: + mock_fetch.return_value = {"data": [{"gsp_id": 0, "gsp_name": "National"}]} + instance = PVLiveData() + # Mock the methods after initialization + instance.pvl.latest = MagicMock() + instance.pvl.between = MagicMock() + instance.pvl.at_time = MagicMock() + return instance -def test_get_latest_data(pvlive_mock): +def test_get_latest_data(pvlive_data): """ Test the get_latest_data method. """ mock_data = {"column1": [1, 2], "column2": [3, 4]} - pvlive_mock.pvl.latest.return_value = mock_data + pvlive_data.pvl.latest.return_value = mock_data - result = pvlive_mock.get_latest_data(period=30) - pvlive_mock.pvl.latest.assert_called_once_with( + result = pvlive_data.get_latest_data(period=30) + pvlive_data.pvl.latest.assert_called_once_with( entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True ) assert result == mock_data -def test_get_data_between(pvlive_mock): +def test_get_data_between(pvlive_data): """ Test the get_data_between method. """ mock_data = {"column1": [5, 6], "column2": [7, 8]} - pvlive_mock.pvl.between.return_value = mock_data + pvlive_data.pvl.between.return_value = mock_data start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) - result = pvlive_mock.get_data_between(start, end) - pvlive_mock.pvl.between.assert_called_once_with( + result = pvlive_data.get_data_between(start, end) + pvlive_data.pvl.between.assert_called_once_with( start=start, end=end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=True ) assert result == mock_data -def test_get_data_at_time(pvlive_mock): +def test_get_data_at_time(pvlive_data): """ Test the get_data_at_time method. """ mock_data = {"column1": [9, 10], "column2": [11, 12]} - pvlive_mock.pvl.at_time.return_value = mock_data + pvlive_data.pvl.at_time.return_value = mock_data dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - result = pvlive_mock.get_data_at_time(dt) - pvlive_mock.pvl.at_time.assert_called_once_with( + result = pvlive_data.get_data_at_time(dt) + pvlive_data.pvl.at_time.assert_called_once_with( dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True ) assert result == mock_data From 6292c513ff96f621be7c984c84407fa4876365c0 Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 21:12:37 +0530 Subject: [PATCH 02/15] test: Fix PVLive tests with proper mocking and realistic test data --- tests/data/test_pvlive_data.py | 89 ++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/tests/data/test_pvlive_data.py b/tests/data/test_pvlive_data.py index fb03cf7..2be8f9a 100644 --- a/tests/data/test_pvlive_data.py +++ b/tests/data/test_pvlive_data.py @@ -3,6 +3,7 @@ from datetime import datetime import pytz import requests +import pandas as pd from pvlive_api.pvlive import PVLiveException from open_data_pvnet.scripts.fetch_pvlive_data import PVLiveData @@ -21,79 +22,95 @@ def raise_for_status(self): raise requests.exceptions.HTTPError() -@pytest.fixture(autouse=True) -def mock_requests(): - """ - Mock requests.get to prevent actual API calls. - """ - with patch('requests.get') as mock_get: - # Mock the GSP list response - mock_get.return_value = MockResponse({ - "data": [ - {"gsp_id": 0, "gsp_name": "National"}, - {"gsp_id": 1, "gsp_name": "Region 1"} - ] +@pytest.fixture +def mock_pvlive(): + """Mock the PVLive class""" + with patch('pvlive_api.pvlive.PVLive', autospec=True) as mock_pvlive_class: + # Create a mock instance + mock_instance = mock_pvlive_class.return_value + + # Create a mock DataFrame for gsp_list + mock_gsp_df = pd.DataFrame({ + 'gsp_id': [0, 1], + 'gsp_name': ['National', 'Region 1'] }) - yield mock_get + mock_instance.gsp_list = mock_gsp_df + + # Mock the API methods + mock_instance.latest = MagicMock() + mock_instance.between = MagicMock() + mock_instance.at_time = MagicMock() + + # Mock _get_gsp_list to return the mock DataFrame + mock_instance._get_gsp_list = MagicMock(return_value=mock_gsp_df) + + yield mock_instance @pytest.fixture -def pvlive_data(): +def pvlive_data(mock_pvlive): """ - Fixture to create a PVLiveData instance with mocked PVLive methods. + Fixture to create a PVLiveData instance with mocked PVLive. """ - with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: - mock_fetch.return_value = {"data": [{"gsp_id": 0, "gsp_name": "National"}]} + with patch('open_data_pvnet.scripts.fetch_pvlive_data.PVLive', return_value=mock_pvlive): instance = PVLiveData() - # Mock the methods after initialization - instance.pvl.latest = MagicMock() - instance.pvl.between = MagicMock() - instance.pvl.at_time = MagicMock() return instance -def test_get_latest_data(pvlive_data): +def test_get_latest_data(pvlive_data, mock_pvlive): """ Test the get_latest_data method. """ - mock_data = {"column1": [1, 2], "column2": [3, 4]} - pvlive_data.pvl.latest.return_value = mock_data + mock_data = pd.DataFrame({ + 'datetime_gmt': [datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc)], + 'generation_mw': [100.0] + }) + mock_pvlive.latest.return_value = mock_data result = pvlive_data.get_latest_data(period=30) - pvlive_data.pvl.latest.assert_called_once_with( + mock_pvlive.latest.assert_called_once_with( entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True ) - assert result == mock_data + assert result.equals(mock_data) -def test_get_data_between(pvlive_data): +def test_get_data_between(pvlive_data, mock_pvlive): """ Test the get_data_between method. """ - mock_data = {"column1": [5, 6], "column2": [7, 8]} - pvlive_data.pvl.between.return_value = mock_data + mock_data = pd.DataFrame({ + 'datetime_gmt': [ + datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc), + datetime(2021, 1, 1, 12, 30, tzinfo=pytz.utc) + ], + 'generation_mw': [100.0, 150.0] + }) + mock_pvlive.between.return_value = mock_data start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) result = pvlive_data.get_data_between(start, end) - pvlive_data.pvl.between.assert_called_once_with( + mock_pvlive.between.assert_called_once_with( start=start, end=end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=True ) - assert result == mock_data + assert result.equals(mock_data) -def test_get_data_at_time(pvlive_data): +def test_get_data_at_time(pvlive_data, mock_pvlive): """ Test the get_data_at_time method. """ - mock_data = {"column1": [9, 10], "column2": [11, 12]} - pvlive_data.pvl.at_time.return_value = mock_data + mock_data = pd.DataFrame({ + 'datetime_gmt': [datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc)], + 'generation_mw': [100.0] + }) + mock_pvlive.at_time.return_value = mock_data dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) result = pvlive_data.get_data_at_time(dt) - pvlive_data.pvl.at_time.assert_called_once_with( + mock_pvlive.at_time.assert_called_once_with( dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True ) - assert result == mock_data + assert result.equals(mock_data) From 7d2b5ff750fc2940f9f6ab08ec61b74a9992d61c Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 21:20:15 +0530 Subject: [PATCH 03/15] test: Add error handling tests for PVLive data methods --- tests/data/test_pvlive_data.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/data/test_pvlive_data.py b/tests/data/test_pvlive_data.py index 2be8f9a..ef75373 100644 --- a/tests/data/test_pvlive_data.py +++ b/tests/data/test_pvlive_data.py @@ -74,6 +74,15 @@ def test_get_latest_data(pvlive_data, mock_pvlive): assert result.equals(mock_data) +def test_get_latest_data_error(pvlive_data, mock_pvlive): + """ + Test error handling in get_latest_data method. + """ + mock_pvlive.latest.side_effect = Exception("API Error") + result = pvlive_data.get_latest_data(period=30) + assert result is None + + def test_get_data_between(pvlive_data, mock_pvlive): """ Test the get_data_between method. @@ -97,6 +106,17 @@ def test_get_data_between(pvlive_data, mock_pvlive): assert result.equals(mock_data) +def test_get_data_between_error(pvlive_data, mock_pvlive): + """ + Test error handling in get_data_between method. + """ + start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) + end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) + mock_pvlive.between.side_effect = Exception("API Error") + result = pvlive_data.get_data_between(start, end) + assert result is None + + def test_get_data_at_time(pvlive_data, mock_pvlive): """ Test the get_data_at_time method. @@ -114,3 +134,13 @@ def test_get_data_at_time(pvlive_data, mock_pvlive): dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True ) assert result.equals(mock_data) + + +def test_get_data_at_time_error(pvlive_data, mock_pvlive): + """ + Test error handling in get_data_at_time method. + """ + dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) + mock_pvlive.at_time.side_effect = Exception("API Error") + result = pvlive_data.get_data_at_time(dt) + assert result is None From 1a4e8e49e677c1500d1202c228197162c9793dce Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 21:47:41 +0530 Subject: [PATCH 04/15] Move and improve PVLive tests --- tests/data/test_pvlive_data.py | 146 --------------------------------- tests/test_pvlive.py | 124 ++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 146 deletions(-) delete mode 100644 tests/data/test_pvlive_data.py create mode 100644 tests/test_pvlive.py diff --git a/tests/data/test_pvlive_data.py b/tests/data/test_pvlive_data.py deleted file mode 100644 index ef75373..0000000 --- a/tests/data/test_pvlive_data.py +++ /dev/null @@ -1,146 +0,0 @@ -import pytest -from unittest.mock import MagicMock, patch -from datetime import datetime -import pytz -import requests -import pandas as pd -from pvlive_api.pvlive import PVLiveException -from open_data_pvnet.scripts.fetch_pvlive_data import PVLiveData - - -class MockResponse: - def __init__(self, json_data, status_code=200): - self.json_data = json_data - self.status_code = status_code - self.text = "" - - def json(self): - return self.json_data - - def raise_for_status(self): - if self.status_code != 200: - raise requests.exceptions.HTTPError() - - -@pytest.fixture -def mock_pvlive(): - """Mock the PVLive class""" - with patch('pvlive_api.pvlive.PVLive', autospec=True) as mock_pvlive_class: - # Create a mock instance - mock_instance = mock_pvlive_class.return_value - - # Create a mock DataFrame for gsp_list - mock_gsp_df = pd.DataFrame({ - 'gsp_id': [0, 1], - 'gsp_name': ['National', 'Region 1'] - }) - mock_instance.gsp_list = mock_gsp_df - - # Mock the API methods - mock_instance.latest = MagicMock() - mock_instance.between = MagicMock() - mock_instance.at_time = MagicMock() - - # Mock _get_gsp_list to return the mock DataFrame - mock_instance._get_gsp_list = MagicMock(return_value=mock_gsp_df) - - yield mock_instance - - -@pytest.fixture -def pvlive_data(mock_pvlive): - """ - Fixture to create a PVLiveData instance with mocked PVLive. - """ - with patch('open_data_pvnet.scripts.fetch_pvlive_data.PVLive', return_value=mock_pvlive): - instance = PVLiveData() - return instance - - -def test_get_latest_data(pvlive_data, mock_pvlive): - """ - Test the get_latest_data method. - """ - mock_data = pd.DataFrame({ - 'datetime_gmt': [datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc)], - 'generation_mw': [100.0] - }) - mock_pvlive.latest.return_value = mock_data - - result = pvlive_data.get_latest_data(period=30) - mock_pvlive.latest.assert_called_once_with( - entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True - ) - assert result.equals(mock_data) - - -def test_get_latest_data_error(pvlive_data, mock_pvlive): - """ - Test error handling in get_latest_data method. - """ - mock_pvlive.latest.side_effect = Exception("API Error") - result = pvlive_data.get_latest_data(period=30) - assert result is None - - -def test_get_data_between(pvlive_data, mock_pvlive): - """ - Test the get_data_between method. - """ - mock_data = pd.DataFrame({ - 'datetime_gmt': [ - datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc), - datetime(2021, 1, 1, 12, 30, tzinfo=pytz.utc) - ], - 'generation_mw': [100.0, 150.0] - }) - mock_pvlive.between.return_value = mock_data - - start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) - - result = pvlive_data.get_data_between(start, end) - mock_pvlive.between.assert_called_once_with( - start=start, end=end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=True - ) - assert result.equals(mock_data) - - -def test_get_data_between_error(pvlive_data, mock_pvlive): - """ - Test error handling in get_data_between method. - """ - start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) - mock_pvlive.between.side_effect = Exception("API Error") - result = pvlive_data.get_data_between(start, end) - assert result is None - - -def test_get_data_at_time(pvlive_data, mock_pvlive): - """ - Test the get_data_at_time method. - """ - mock_data = pd.DataFrame({ - 'datetime_gmt': [datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc)], - 'generation_mw': [100.0] - }) - mock_pvlive.at_time.return_value = mock_data - - dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - - result = pvlive_data.get_data_at_time(dt) - mock_pvlive.at_time.assert_called_once_with( - dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True - ) - assert result.equals(mock_data) - - -def test_get_data_at_time_error(pvlive_data, mock_pvlive): - """ - Test error handling in get_data_at_time method. - """ - dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - mock_pvlive.at_time.side_effect = Exception("API Error") - result = pvlive_data.get_data_at_time(dt) - assert result is None diff --git a/tests/test_pvlive.py b/tests/test_pvlive.py new file mode 100644 index 0000000..bc46b16 --- /dev/null +++ b/tests/test_pvlive.py @@ -0,0 +1,124 @@ +import pytest +from unittest.mock import MagicMock, patch +from datetime import datetime +import pytz +import requests +import pandas as pd +import json +from pvlive_api.pvlive import PVLiveException +from open_data_pvnet.scripts.fetch_pvlive_data import PVLiveData + + +class MockResponse: + def __init__(self, json_data, status_code=200): + self.json_data = json_data + self.status_code = status_code + self.text = json.dumps(json_data) + + def json(self): + return self.json_data + + def raise_for_status(self): + if self.status_code != 200: + raise requests.exceptions.HTTPError() + + +@pytest.fixture(autouse=True) +def mock_requests(): + """ + Mock requests.get to prevent actual API calls. + """ + with patch('requests.get') as mock_get: + # Mock the GSP list response with pes_id + mock_get.return_value = MockResponse({ + "data": [ + {"gsp_id": 0, "gsp_name": "National", "pes_id": 0}, + {"gsp_id": 1, "gsp_name": "Region 1", "pes_id": 1} + ], + "meta": ["gsp_id", "gsp_name", "pes_id"] + }) + yield mock_get + + +@pytest.fixture +def pvlive_data(): + """ + Fixture to create a PVLiveData instance with mocked PVLive methods. + """ + with patch('pvlive_api.PVLive') as mock_pvlive_class: + instance = PVLiveData() + return instance + + +def test_get_latest_data(pvlive_data): + """ + Test the get_latest_data method. + """ + mock_data = pd.DataFrame({"column1": [1, 2], "column2": [3, 4]}) + with patch.object(pvlive_data.pvl, 'latest', return_value=mock_data) as mock_latest: + result = pvlive_data.get_latest_data(period=30) + mock_latest.assert_called_once_with( + entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True + ) + assert result.equals(mock_data) + + +def test_get_latest_data_error(pvlive_data): + """ + Test error handling in get_latest_data method. + """ + with patch.object(pvlive_data.pvl, 'latest', side_effect=Exception("API Error")): + result = pvlive_data.get_latest_data(period=30) + assert result is None + + +def test_get_data_between(pvlive_data): + """ + Test the get_data_between method. + """ + mock_data = pd.DataFrame({"column1": [5, 6], "column2": [7, 8]}) + start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) + end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) + + with patch.object(pvlive_data.pvl, 'between', return_value=mock_data) as mock_between: + result = pvlive_data.get_data_between(start, end) + mock_between.assert_called_once_with( + start=start, end=end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=True + ) + assert result.equals(mock_data) + + +def test_get_data_between_error(pvlive_data): + """ + Test error handling in get_data_between method. + """ + start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) + end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) + with patch.object(pvlive_data.pvl, 'between', side_effect=Exception("API Error")): + result = pvlive_data.get_data_between(start, end) + assert result is None + + +def test_get_data_at_time(pvlive_data): + """ + Test the get_data_at_time method. + """ + mock_data = pd.DataFrame({"column1": [9, 10], "column2": [11, 12]}) + dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) + + with patch.object(pvlive_data.pvl, 'at_time', return_value=mock_data) as mock_at_time: + result = pvlive_data.get_data_at_time(dt) + mock_at_time.assert_called_once_with( + dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True + ) + assert result.equals(mock_data) + + +def test_get_data_at_time_error(pvlive_data): + """ + Test error handling in get_data_at_time method. + """ + dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) + with patch.object(pvlive_data.pvl, 'at_time', side_effect=Exception("API Error")): + result = pvlive_data.get_data_at_time(dt) + assert result is None \ No newline at end of file From 6fcb7e0cba07bc8878bf6a5e36ae2a0c89e1bbfe Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 21:57:58 +0530 Subject: [PATCH 05/15] Add conftest.py to ignore tests in data directory --- tests/conftest.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..866d1dc --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,7 @@ +import pytest +import os + +def pytest_ignore_collect(path, config): + """Ignore test files in the data directory.""" + if str(path).startswith(os.path.join('tests', 'data')): + return True \ No newline at end of file From 55aa01251008a1d6567f6257dcac2713e8df03d8 Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:03:16 +0530 Subject: [PATCH 06/15] Add session-wide mock for PVLive API to prevent real API calls --- tests/conftest.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 866d1dc..78bc551 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,21 @@ import pytest import os +import pandas as pd +from unittest.mock import patch, MagicMock def pytest_ignore_collect(path, config): """Ignore test files in the data directory.""" if str(path).startswith(os.path.join('tests', 'data')): - return True \ No newline at end of file + return True + +@pytest.fixture(scope="session", autouse=True) +def mock_pvlive(): + """Mock PVLive API at the session level to prevent any real API calls.""" + mock_data = pd.DataFrame({"column1": [1, 2], "column2": [3, 4]}) + mock_pvlive = MagicMock() + mock_pvlive.latest.return_value = mock_data + mock_pvlive.between.return_value = mock_data + mock_pvlive.at_time.return_value = mock_data + + with patch('pvlive_api.PVLive', return_value=mock_pvlive): + yield mock_pvlive \ No newline at end of file From ef50afb933904cd393dd21c8ab9f99567d5ae6bf Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:10:43 +0530 Subject: [PATCH 07/15] Improve PVLive mock to handle initialization and all API methods --- tests/conftest.py | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 78bc551..9368d99 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,8 @@ import os import pandas as pd from unittest.mock import patch, MagicMock +from datetime import datetime +import pytz def pytest_ignore_collect(path, config): """Ignore test files in the data directory.""" @@ -11,11 +13,41 @@ def pytest_ignore_collect(path, config): @pytest.fixture(scope="session", autouse=True) def mock_pvlive(): """Mock PVLive API at the session level to prevent any real API calls.""" - mock_data = pd.DataFrame({"column1": [1, 2], "column2": [3, 4]}) - mock_pvlive = MagicMock() - mock_pvlive.latest.return_value = mock_data - mock_pvlive.between.return_value = mock_data - mock_pvlive.at_time.return_value = mock_data + mock_data = pd.DataFrame({ + "generation_mw": [100, 200], + "datetime_gmt": [ + datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC), + datetime(2021, 1, 1, 12, 30, tzinfo=pytz.UTC) + ] + }) - with patch('pvlive_api.PVLive', return_value=mock_pvlive): - yield mock_pvlive \ No newline at end of file + # Create a mock class instead of instance to handle initialization + class MockPVLive: + def __init__(self, retries=3, proxies=None, timeout=10, ssl_verify=True): + self.retries = retries + self.proxies = proxies + self.timeout = timeout + self.ssl_verify = ssl_verify + self.gsp_list = [ + {"gsp_id": 0, "gsp_name": "National", "pes_id": 0}, + {"gsp_id": 1, "gsp_name": "Region 1", "pes_id": 1} + ] + + def _get_gsp_list(self): + return self.gsp_list + + def _fetch_url(self, *args, **kwargs): + return {"data": self.gsp_list, "meta": ["gsp_id", "gsp_name", "pes_id"]} + + def latest(self, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=False): + return mock_data if dataframe else mock_data.to_dict("records") + + def between(self, start, end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=False): + return mock_data if dataframe else mock_data.to_dict("records") + + def at_time(self, dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=False): + return mock_data if dataframe else mock_data.to_dict("records") + + with patch('pvlive_api.PVLive', MockPVLive), \ + patch('pvlive_api.pvlive.PVLive', MockPVLive): # Also patch the module-level import + yield MockPVLive() \ No newline at end of file From 9630e75f4b5df43e79a98593da5cc9a95cb58945 Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:20:00 +0530 Subject: [PATCH 08/15] Update PVLive mocking strategy to match working test approach --- tests/conftest.py | 89 ++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9368d99..985b673 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,50 +4,67 @@ from unittest.mock import patch, MagicMock from datetime import datetime import pytz +import requests +from pvlive_api.pvlive import PVLiveException + + +class MockResponse: + def __init__(self, json_data, status_code=200): + self.json_data = json_data + self.status_code = status_code + self.text = "" + + def json(self): + return self.json_data + + def raise_for_status(self): + if self.status_code != 200: + raise requests.exceptions.HTTPError() + + +@pytest.fixture(scope="session", autouse=True) +def mock_requests(): + """Mock requests.get to prevent actual API calls.""" + with patch('requests.get') as mock_get: + mock_get.return_value = MockResponse({ + "data": [ + {"gsp_id": 0, "gsp_name": "National"}, + {"gsp_id": 1, "gsp_name": "Region 1"} + ] + }) + yield mock_get -def pytest_ignore_collect(path, config): - """Ignore test files in the data directory.""" - if str(path).startswith(os.path.join('tests', 'data')): - return True @pytest.fixture(scope="session", autouse=True) def mock_pvlive(): - """Mock PVLive API at the session level to prevent any real API calls.""" - mock_data = pd.DataFrame({ + """Mock PVLive API methods to prevent actual API calls.""" + mock_data = { "generation_mw": [100, 200], "datetime_gmt": [ datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC), datetime(2021, 1, 1, 12, 30, tzinfo=pytz.UTC) ] - }) - - # Create a mock class instead of instance to handle initialization - class MockPVLive: - def __init__(self, retries=3, proxies=None, timeout=10, ssl_verify=True): - self.retries = retries - self.proxies = proxies - self.timeout = timeout - self.ssl_verify = ssl_verify - self.gsp_list = [ - {"gsp_id": 0, "gsp_name": "National", "pes_id": 0}, - {"gsp_id": 1, "gsp_name": "Region 1", "pes_id": 1} - ] - - def _get_gsp_list(self): - return self.gsp_list - - def _fetch_url(self, *args, **kwargs): - return {"data": self.gsp_list, "meta": ["gsp_id", "gsp_name", "pes_id"]} - - def latest(self, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=False): - return mock_data if dataframe else mock_data.to_dict("records") + } + + with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: + mock_fetch.return_value = { + "data": [{"gsp_id": 0, "gsp_name": "National"}], + "meta": ["gsp_id", "gsp_name"] + } + + # Mock the main PVLive methods + with patch('pvlive_api.pvlive.PVLive.latest') as mock_latest, \ + patch('pvlive_api.pvlive.PVLive.between') as mock_between, \ + patch('pvlive_api.pvlive.PVLive.at_time') as mock_at_time: - def between(self, start, end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=False): - return mock_data if dataframe else mock_data.to_dict("records") + mock_latest.return_value = mock_data + mock_between.return_value = mock_data + mock_at_time.return_value = mock_data - def at_time(self, dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=False): - return mock_data if dataframe else mock_data.to_dict("records") - - with patch('pvlive_api.PVLive', MockPVLive), \ - patch('pvlive_api.pvlive.PVLive', MockPVLive): # Also patch the module-level import - yield MockPVLive() \ No newline at end of file + yield + + +def pytest_ignore_collect(path, config): + """Ignore test files in the data directory.""" + if str(path).startswith(os.path.join('tests', 'data')): + return True \ No newline at end of file From 5b51f9a1c60114217a6c402f174e95ac6da800c6 Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:24:00 +0530 Subject: [PATCH 09/15] Add pes_id and other required columns to mock data --- tests/conftest.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 985b673..999f73b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -28,8 +28,8 @@ def mock_requests(): with patch('requests.get') as mock_get: mock_get.return_value = MockResponse({ "data": [ - {"gsp_id": 0, "gsp_name": "National"}, - {"gsp_id": 1, "gsp_name": "Region 1"} + {"gsp_id": 0, "gsp_name": "National", "pes_id": 0}, + {"gsp_id": 1, "gsp_name": "Region 1", "pes_id": 1} ] }) yield mock_get @@ -38,18 +38,22 @@ def mock_requests(): @pytest.fixture(scope="session", autouse=True) def mock_pvlive(): """Mock PVLive API methods to prevent actual API calls.""" - mock_data = { + # Create mock data as a DataFrame with all required columns + mock_data = pd.DataFrame({ "generation_mw": [100, 200], "datetime_gmt": [ datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC), datetime(2021, 1, 1, 12, 30, tzinfo=pytz.UTC) - ] - } + ], + "pes_id": [0, 0], # Added pes_id column + "gsp_id": [0, 0], # Added gsp_id column + "gsp_name": ["National", "National"] # Added gsp_name column + }) with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: mock_fetch.return_value = { - "data": [{"gsp_id": 0, "gsp_name": "National"}], - "meta": ["gsp_id", "gsp_name"] + "data": [{"gsp_id": 0, "gsp_name": "National", "pes_id": 0}], + "meta": ["gsp_id", "gsp_name", "pes_id"] } # Mock the main PVLive methods From e9d3cec9a82b87cc43f90591920265325a6d9444 Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:29:11 +0530 Subject: [PATCH 10/15] Mock PVLive class and methods to prevent real API calls --- tests/conftest.py | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 999f73b..fe5447f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -37,35 +37,33 @@ def mock_requests(): @pytest.fixture(scope="session", autouse=True) def mock_pvlive(): - """Mock PVLive API methods to prevent actual API calls.""" - # Create mock data as a DataFrame with all required columns + """Mock PVLive class and its methods to prevent actual API calls.""" mock_data = pd.DataFrame({ "generation_mw": [100, 200], "datetime_gmt": [ datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC), datetime(2021, 1, 1, 12, 30, tzinfo=pytz.UTC) ], - "pes_id": [0, 0], # Added pes_id column - "gsp_id": [0, 0], # Added gsp_id column - "gsp_name": ["National", "National"] # Added gsp_name column + "pes_id": [0, 0], + "gsp_id": [0, 0], + "gsp_name": ["National", "National"] }) - with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: - mock_fetch.return_value = { - "data": [{"gsp_id": 0, "gsp_name": "National", "pes_id": 0}], - "meta": ["gsp_id", "gsp_name", "pes_id"] - } - - # Mock the main PVLive methods - with patch('pvlive_api.pvlive.PVLive.latest') as mock_latest, \ - patch('pvlive_api.pvlive.PVLive.between') as mock_between, \ - patch('pvlive_api.pvlive.PVLive.at_time') as mock_at_time: - - mock_latest.return_value = mock_data - mock_between.return_value = mock_data - mock_at_time.return_value = mock_data - - yield + class MockPVLive: + def __init__(self, *args, **kwargs): + pass + + def latest(self, *args, **kwargs): + return mock_data + + def between(self, *args, **kwargs): + return mock_data + + def at_time(self, *args, **kwargs): + return mock_data + + with patch('pvlive_api.pvlive.PVLive', MockPVLive): + yield MockPVLive() def pytest_ignore_collect(path, config): From b17bdfbcd54b06105df5a64ba002b16c5ee8bf4d Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:38:28 +0530 Subject: [PATCH 11/15] Update PVLive tests to match working implementation --- tests/conftest.py | 72 ------------------------------------ tests/test_pvlive.py | 88 ++++++++++++++++++++++++-------------------- 2 files changed, 49 insertions(+), 111 deletions(-) delete mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index fe5447f..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,72 +0,0 @@ -import pytest -import os -import pandas as pd -from unittest.mock import patch, MagicMock -from datetime import datetime -import pytz -import requests -from pvlive_api.pvlive import PVLiveException - - -class MockResponse: - def __init__(self, json_data, status_code=200): - self.json_data = json_data - self.status_code = status_code - self.text = "" - - def json(self): - return self.json_data - - def raise_for_status(self): - if self.status_code != 200: - raise requests.exceptions.HTTPError() - - -@pytest.fixture(scope="session", autouse=True) -def mock_requests(): - """Mock requests.get to prevent actual API calls.""" - with patch('requests.get') as mock_get: - mock_get.return_value = MockResponse({ - "data": [ - {"gsp_id": 0, "gsp_name": "National", "pes_id": 0}, - {"gsp_id": 1, "gsp_name": "Region 1", "pes_id": 1} - ] - }) - yield mock_get - - -@pytest.fixture(scope="session", autouse=True) -def mock_pvlive(): - """Mock PVLive class and its methods to prevent actual API calls.""" - mock_data = pd.DataFrame({ - "generation_mw": [100, 200], - "datetime_gmt": [ - datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC), - datetime(2021, 1, 1, 12, 30, tzinfo=pytz.UTC) - ], - "pes_id": [0, 0], - "gsp_id": [0, 0], - "gsp_name": ["National", "National"] - }) - - class MockPVLive: - def __init__(self, *args, **kwargs): - pass - - def latest(self, *args, **kwargs): - return mock_data - - def between(self, *args, **kwargs): - return mock_data - - def at_time(self, *args, **kwargs): - return mock_data - - with patch('pvlive_api.pvlive.PVLive', MockPVLive): - yield MockPVLive() - - -def pytest_ignore_collect(path, config): - """Ignore test files in the data directory.""" - if str(path).startswith(os.path.join('tests', 'data')): - return True \ No newline at end of file diff --git a/tests/test_pvlive.py b/tests/test_pvlive.py index bc46b16..50b323b 100644 --- a/tests/test_pvlive.py +++ b/tests/test_pvlive.py @@ -3,8 +3,6 @@ from datetime import datetime import pytz import requests -import pandas as pd -import json from pvlive_api.pvlive import PVLiveException from open_data_pvnet.scripts.fetch_pvlive_data import PVLiveData @@ -13,7 +11,7 @@ class MockResponse: def __init__(self, json_data, status_code=200): self.json_data = json_data self.status_code = status_code - self.text = json.dumps(json_data) + self.text = "" def json(self): return self.json_data @@ -29,13 +27,12 @@ def mock_requests(): Mock requests.get to prevent actual API calls. """ with patch('requests.get') as mock_get: - # Mock the GSP list response with pes_id + # Mock the GSP list response mock_get.return_value = MockResponse({ "data": [ - {"gsp_id": 0, "gsp_name": "National", "pes_id": 0}, - {"gsp_id": 1, "gsp_name": "Region 1", "pes_id": 1} - ], - "meta": ["gsp_id", "gsp_name", "pes_id"] + {"gsp_id": 0, "gsp_name": "National"}, + {"gsp_id": 1, "gsp_name": "Region 1"} + ] }) yield mock_get @@ -45,8 +42,13 @@ def pvlive_data(): """ Fixture to create a PVLiveData instance with mocked PVLive methods. """ - with patch('pvlive_api.PVLive') as mock_pvlive_class: + with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: + mock_fetch.return_value = {"data": [{"gsp_id": 0, "gsp_name": "National"}]} instance = PVLiveData() + # Mock the methods after initialization + instance.pvl.latest = MagicMock() + instance.pvl.between = MagicMock() + instance.pvl.at_time = MagicMock() return instance @@ -54,71 +56,79 @@ def test_get_latest_data(pvlive_data): """ Test the get_latest_data method. """ - mock_data = pd.DataFrame({"column1": [1, 2], "column2": [3, 4]}) - with patch.object(pvlive_data.pvl, 'latest', return_value=mock_data) as mock_latest: - result = pvlive_data.get_latest_data(period=30) - mock_latest.assert_called_once_with( - entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True - ) - assert result.equals(mock_data) + mock_data = {"column1": [1, 2], "column2": [3, 4]} + pvlive_data.pvl.latest.return_value = mock_data + + result = pvlive_data.get_latest_data(period=30) + pvlive_data.pvl.latest.assert_called_once_with( + entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True + ) + assert result == mock_data def test_get_latest_data_error(pvlive_data): """ Test error handling in get_latest_data method. """ - with patch.object(pvlive_data.pvl, 'latest', side_effect=Exception("API Error")): - result = pvlive_data.get_latest_data(period=30) - assert result is None + pvlive_data.pvl.latest.side_effect = PVLiveException("Test error") + + with pytest.raises(PVLiveException, match="Test error"): + pvlive_data.get_latest_data(period=30) def test_get_data_between(pvlive_data): """ Test the get_data_between method. """ - mock_data = pd.DataFrame({"column1": [5, 6], "column2": [7, 8]}) + mock_data = {"column1": [5, 6], "column2": [7, 8]} + pvlive_data.pvl.between.return_value = mock_data + start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) - with patch.object(pvlive_data.pvl, 'between', return_value=mock_data) as mock_between: - result = pvlive_data.get_data_between(start, end) - mock_between.assert_called_once_with( - start=start, end=end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=True - ) - assert result.equals(mock_data) + result = pvlive_data.get_data_between(start, end) + pvlive_data.pvl.between.assert_called_once_with( + start=start, end=end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=True + ) + assert result == mock_data def test_get_data_between_error(pvlive_data): """ Test error handling in get_data_between method. """ + pvlive_data.pvl.between.side_effect = PVLiveException("Test error") + start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) - with patch.object(pvlive_data.pvl, 'between', side_effect=Exception("API Error")): - result = pvlive_data.get_data_between(start, end) - assert result is None + + with pytest.raises(PVLiveException, match="Test error"): + pvlive_data.get_data_between(start, end) def test_get_data_at_time(pvlive_data): """ Test the get_data_at_time method. """ - mock_data = pd.DataFrame({"column1": [9, 10], "column2": [11, 12]}) + mock_data = {"column1": [9, 10], "column2": [11, 12]} + pvlive_data.pvl.at_time.return_value = mock_data + dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - with patch.object(pvlive_data.pvl, 'at_time', return_value=mock_data) as mock_at_time: - result = pvlive_data.get_data_at_time(dt) - mock_at_time.assert_called_once_with( - dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True - ) - assert result.equals(mock_data) + result = pvlive_data.get_data_at_time(dt) + pvlive_data.pvl.at_time.assert_called_once_with( + dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True + ) + assert result == mock_data def test_get_data_at_time_error(pvlive_data): """ Test error handling in get_data_at_time method. """ + pvlive_data.pvl.at_time.side_effect = PVLiveException("Test error") + dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - with patch.object(pvlive_data.pvl, 'at_time', side_effect=Exception("API Error")): - result = pvlive_data.get_data_at_time(dt) - assert result is None \ No newline at end of file + + with pytest.raises(PVLiveException, match="Test error"): + pvlive_data.get_data_at_time(dt) \ No newline at end of file From 20cddd149870e8d40579054dac8a9d32f30f67df Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:42:40 +0530 Subject: [PATCH 12/15] Update mock data format to include meta field --- tests/test_pvlive.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/test_pvlive.py b/tests/test_pvlive.py index 50b323b..c697a10 100644 --- a/tests/test_pvlive.py +++ b/tests/test_pvlive.py @@ -32,7 +32,8 @@ def mock_requests(): "data": [ {"gsp_id": 0, "gsp_name": "National"}, {"gsp_id": 1, "gsp_name": "Region 1"} - ] + ], + "meta": ["gsp_id", "gsp_name"] }) yield mock_get @@ -43,7 +44,10 @@ def pvlive_data(): Fixture to create a PVLiveData instance with mocked PVLive methods. """ with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: - mock_fetch.return_value = {"data": [{"gsp_id": 0, "gsp_name": "National"}]} + mock_fetch.return_value = { + "data": [{"gsp_id": 0, "gsp_name": "National"}], + "meta": ["gsp_id", "gsp_name"] + } instance = PVLiveData() # Mock the methods after initialization instance.pvl.latest = MagicMock() @@ -56,7 +60,10 @@ def test_get_latest_data(pvlive_data): """ Test the get_latest_data method. """ - mock_data = {"column1": [1, 2], "column2": [3, 4]} + mock_data = { + "data": [{"generation_mw": 100, "datetime_gmt": "2021-01-01T12:00:00Z"}], + "meta": ["generation_mw", "datetime_gmt"] + } pvlive_data.pvl.latest.return_value = mock_data result = pvlive_data.get_latest_data(period=30) @@ -80,7 +87,13 @@ def test_get_data_between(pvlive_data): """ Test the get_data_between method. """ - mock_data = {"column1": [5, 6], "column2": [7, 8]} + mock_data = { + "data": [ + {"generation_mw": 100, "datetime_gmt": "2021-01-01T12:00:00Z"}, + {"generation_mw": 200, "datetime_gmt": "2021-01-01T12:30:00Z"} + ], + "meta": ["generation_mw", "datetime_gmt"] + } pvlive_data.pvl.between.return_value = mock_data start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) @@ -110,7 +123,10 @@ def test_get_data_at_time(pvlive_data): """ Test the get_data_at_time method. """ - mock_data = {"column1": [9, 10], "column2": [11, 12]} + mock_data = { + "data": [{"generation_mw": 100, "datetime_gmt": "2021-01-01T12:00:00Z"}], + "meta": ["generation_mw", "datetime_gmt"] + } pvlive_data.pvl.at_time.return_value = mock_data dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) From 4ef5eaa19dc833dd7ec71aa5c2333a3b78704c2f Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:46:46 +0530 Subject: [PATCH 13/15] Update mock data to use pandas DataFrames with pes_id --- tests/test_pvlive.py | 57 +++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/tests/test_pvlive.py b/tests/test_pvlive.py index c697a10..905e842 100644 --- a/tests/test_pvlive.py +++ b/tests/test_pvlive.py @@ -3,6 +3,7 @@ from datetime import datetime import pytz import requests +import pandas as pd from pvlive_api.pvlive import PVLiveException from open_data_pvnet.scripts.fetch_pvlive_data import PVLiveData @@ -30,10 +31,10 @@ def mock_requests(): # Mock the GSP list response mock_get.return_value = MockResponse({ "data": [ - {"gsp_id": 0, "gsp_name": "National"}, - {"gsp_id": 1, "gsp_name": "Region 1"} + {"gsp_id": 0, "gsp_name": "National", "pes_id": 0}, + {"gsp_id": 1, "gsp_name": "Region 1", "pes_id": 1} ], - "meta": ["gsp_id", "gsp_name"] + "meta": ["gsp_id", "gsp_name", "pes_id"] }) yield mock_get @@ -45,8 +46,8 @@ def pvlive_data(): """ with patch('pvlive_api.pvlive.PVLive._fetch_url', autospec=True) as mock_fetch: mock_fetch.return_value = { - "data": [{"gsp_id": 0, "gsp_name": "National"}], - "meta": ["gsp_id", "gsp_name"] + "data": [{"gsp_id": 0, "gsp_name": "National", "pes_id": 0}], + "meta": ["gsp_id", "gsp_name", "pes_id"] } instance = PVLiveData() # Mock the methods after initialization @@ -60,17 +61,21 @@ def test_get_latest_data(pvlive_data): """ Test the get_latest_data method. """ - mock_data = { - "data": [{"generation_mw": 100, "datetime_gmt": "2021-01-01T12:00:00Z"}], - "meta": ["generation_mw", "datetime_gmt"] - } + # Create a DataFrame with the required columns + mock_data = pd.DataFrame({ + "generation_mw": [100], + "datetime_gmt": [datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC)], + "pes_id": [0], + "gsp_id": [0], + "gsp_name": ["National"] + }) pvlive_data.pvl.latest.return_value = mock_data result = pvlive_data.get_latest_data(period=30) pvlive_data.pvl.latest.assert_called_once_with( entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True ) - assert result == mock_data + assert result.equals(mock_data) def test_get_latest_data_error(pvlive_data): @@ -87,13 +92,17 @@ def test_get_data_between(pvlive_data): """ Test the get_data_between method. """ - mock_data = { - "data": [ - {"generation_mw": 100, "datetime_gmt": "2021-01-01T12:00:00Z"}, - {"generation_mw": 200, "datetime_gmt": "2021-01-01T12:30:00Z"} + # Create a DataFrame with the required columns + mock_data = pd.DataFrame({ + "generation_mw": [100, 200], + "datetime_gmt": [ + datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC), + datetime(2021, 1, 1, 12, 30, tzinfo=pytz.UTC) ], - "meta": ["generation_mw", "datetime_gmt"] - } + "pes_id": [0, 0], + "gsp_id": [0, 0], + "gsp_name": ["National", "National"] + }) pvlive_data.pvl.between.return_value = mock_data start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) @@ -103,7 +112,7 @@ def test_get_data_between(pvlive_data): pvlive_data.pvl.between.assert_called_once_with( start=start, end=end, entity_type="gsp", entity_id=0, extra_fields="", dataframe=True ) - assert result == mock_data + assert result.equals(mock_data) def test_get_data_between_error(pvlive_data): @@ -123,10 +132,14 @@ def test_get_data_at_time(pvlive_data): """ Test the get_data_at_time method. """ - mock_data = { - "data": [{"generation_mw": 100, "datetime_gmt": "2021-01-01T12:00:00Z"}], - "meta": ["generation_mw", "datetime_gmt"] - } + # Create a DataFrame with the required columns + mock_data = pd.DataFrame({ + "generation_mw": [100], + "datetime_gmt": [datetime(2021, 1, 1, 12, 0, tzinfo=pytz.UTC)], + "pes_id": [0], + "gsp_id": [0], + "gsp_name": ["National"] + }) pvlive_data.pvl.at_time.return_value = mock_data dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) @@ -135,7 +148,7 @@ def test_get_data_at_time(pvlive_data): pvlive_data.pvl.at_time.assert_called_once_with( dt, entity_type="gsp", entity_id=0, extra_fields="", period=30, dataframe=True ) - assert result == mock_data + assert result.equals(mock_data) def test_get_data_at_time_error(pvlive_data): From 23b53bc64393be8f9fbbea71a4590cd9f6ef712a Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:50:39 +0530 Subject: [PATCH 14/15] Update error tests to check for None return value instead of exceptions --- tests/test_pvlive.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_pvlive.py b/tests/test_pvlive.py index 905e842..013f9ad 100644 --- a/tests/test_pvlive.py +++ b/tests/test_pvlive.py @@ -84,8 +84,8 @@ def test_get_latest_data_error(pvlive_data): """ pvlive_data.pvl.latest.side_effect = PVLiveException("Test error") - with pytest.raises(PVLiveException, match="Test error"): - pvlive_data.get_latest_data(period=30) + result = pvlive_data.get_latest_data(period=30) + assert result is None def test_get_data_between(pvlive_data): @@ -121,11 +121,11 @@ def test_get_data_between_error(pvlive_data): """ pvlive_data.pvl.between.side_effect = PVLiveException("Test error") - start = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - end = datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) - - with pytest.raises(PVLiveException, match="Test error"): - pvlive_data.get_data_between(start, end) + result = pvlive_data.get_data_between( + start=datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc), + end=datetime(2021, 1, 2, 12, 0, tzinfo=pytz.utc) + ) + assert result is None def test_get_data_at_time(pvlive_data): @@ -157,7 +157,7 @@ def test_get_data_at_time_error(pvlive_data): """ pvlive_data.pvl.at_time.side_effect = PVLiveException("Test error") - dt = datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) - - with pytest.raises(PVLiveException, match="Test error"): - pvlive_data.get_data_at_time(dt) \ No newline at end of file + result = pvlive_data.get_data_at_time( + datetime(2021, 1, 1, 12, 0, tzinfo=pytz.utc) + ) + assert result is None \ No newline at end of file From 71d7b75a5380ded25c422c85d2ea46e28248ca8f Mon Sep 17 00:00:00 2001 From: prasanna1504 Date: Tue, 18 Mar 2025 22:57:31 +0530 Subject: [PATCH 15/15] Fix tomllib import for Python 3.9 compatibility --- tests/test_metadata.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 9e781a4..e13eff6 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -1,4 +1,7 @@ -import tomllib +try: + import tomllib +except ImportError: + import tomli as tomllib import open_data_pvnet