diff --git a/biolearn/data_library.py b/biolearn/data_library.py index b0c62f9..a3a3ec9 100644 --- a/biolearn/data_library.py +++ b/biolearn/data_library.py @@ -1029,7 +1029,15 @@ def _check_keys_exist(self, data, keys: list[str]): def _create_metadata(self, metadata_query_url): response = requests.get(metadata_query_url) - json_data = response.json() + response.raise_for_status() + try: + json_data = response.json() + except ValueError as e: + # NCBI serves an HTML CAPTCHA page when it blocks automated requests + raise ValueError( + f"GEO metadata query did not return JSON: {metadata_query_url}. " + "NCBI may be blocking automated requests." + ) from e smaples = [item for item in json_data["GeoMetaData"]] return self._convert_to_metadata_df(self.metadata_keys, smaples) diff --git a/biolearn/test/test_autoscan_geo_matrix_parser.py b/biolearn/test/test_autoscan_geo_matrix_parser.py index 207a9ad..1e5b30b 100644 --- a/biolearn/test/test_autoscan_geo_matrix_parser.py +++ b/biolearn/test/test_autoscan_geo_matrix_parser.py @@ -1,6 +1,12 @@ +import pandas as pd import pytest +from unittest.mock import Mock, patch -from biolearn.data_library import DataLibrary, NoMatrixDataError +from biolearn.data_library import ( + AutoScanGeoMatrixParser, + DataLibrary, + NoMatrixDataError, +) from biolearn.util import get_data_file @@ -28,5 +34,29 @@ def test_series_has_no_matrix_data_error(): library_file=get_data_file("geo_autoscan_library.yaml") ) - with pytest.raises(NoMatrixDataError): - library.get("GSE121633").load() + # geo2r now answers scripted requests with a CAPTCHA page, so stub the + # metadata call and exercise only the matrix check under test + stub_metadata = pd.DataFrame({"id": ["GSE121633"]}) + with patch.object( + AutoScanGeoMatrixParser, "_create_metadata", return_value=stub_metadata + ): + with pytest.raises(NoMatrixDataError): + library.get("GSE121633").load() + + +def test_metadata_query_non_json_response_error(): + parser = AutoScanGeoMatrixParser( + { + "matrix_file": "unused", + "metadata_keys_parse": {}, + "metadata_query": "unused", + } + ) + html_response = Mock() + html_response.json.side_effect = ValueError("Expecting value") + + with patch( + "biolearn.data_library.requests.get", return_value=html_response + ): + with pytest.raises(ValueError, match="did not return JSON"): + parser._create_metadata("https://example.org/geo2r")