diff --git a/packages/datacommons-mcp/.env.sample b/packages/datacommons-mcp/.env.sample index 0853676..5401ea7 100644 --- a/packages/datacommons-mcp/.env.sample +++ b/packages/datacommons-mcp/.env.sample @@ -62,16 +62,13 @@ DC_TYPE=base # ============================================================================= # Use these variables to run the server against non-prod (autopush, staging) or local instances -# of the Data Commons API and Search endpoints. +# of the Data Commons API. # When using a local instance, you may also need to use the # --skip-api-key-validation command-line flag if running without a DC_API_KEY. # Root URL for a non-prod or local Data Commons API (mixer) instance # DC_API_ROOT=http://localhost:8081/v2 -# Root URL for a non-prod or local Data Commons Search (website) instance -# DC_SEARCH_ROOT=http://localhost:8080 - # Root URL for Data Commons API key validation # Configure for non-prod environments # DC_API_KEY_VALIDATION_ROOT=https://api.datacommons.org diff --git a/packages/datacommons-mcp/datacommons_mcp/clients.py b/packages/datacommons-mcp/datacommons_mcp/clients.py index ad364b4..cc6113d 100644 --- a/packages/datacommons-mcp/datacommons_mcp/clients.py +++ b/packages/datacommons-mcp/datacommons_mcp/clients.py @@ -21,7 +21,6 @@ import re from pathlib import Path -import requests from datacommons_client.client import DataCommonsClient from datacommons_mcp._constrained_vars import place_statvar_constraint_mapping @@ -60,13 +59,8 @@ def __init__( self, dc: DataCommonsClient, search_scope: SearchScope = SearchScope.BASE_ONLY, - base_index: str = "base_uae_mem", - custom_index: str | None = None, - sv_search_base_url: str = "https://datacommons.org", topic_store: TopicStore | None = None, _place_like_constraints: list[str] | None = None, - *, - use_search_indicators: bool = False, ) -> None: """ Initialize the DCClient with a DataCommonsClient and search configuration. @@ -74,9 +68,6 @@ def __init__( Args: dc: DataCommonsClient instance search_scope: SearchScope enum controlling search behavior - base_index: Index to use for base DC searches - custom_index: Index to use for custom DC searches (None for base DC) - sv_search_base_url: Base URL for SV search endpoint topic_store: Optional TopicStore for caching # TODO(@jm-rivera): Remove this parameter once new endpoint is live. @@ -84,11 +75,6 @@ def __init__( """ self.dc = dc self.search_scope = search_scope - self.base_index = base_index - self.custom_index = custom_index - # Precompute search indices to validate configuration at instantiation time - self.search_indices = self._compute_search_indices() - self.sv_search_base_url = sv_search_base_url self.variable_cache = LruCache(128) if topic_store is None: @@ -100,31 +86,9 @@ def __init__( else: self._place_like_statvar_store = {} - self.use_search_indicators = use_search_indicators - # # Initialization & Configuration # - def _compute_search_indices(self) -> list[str]: - """Compute and validate search indices based on the configured search_scope. - - Raises a ValueError immediately for invalid configurations (e.g., CUSTOM_ONLY - without a custom_index). - """ - indices: list[str] = [] - - if self.search_scope in [SearchScope.CUSTOM_ONLY, SearchScope.BASE_AND_CUSTOM]: - if self.custom_index is not None and self.custom_index != "": - indices.append(self.custom_index) - elif self.search_scope == SearchScope.CUSTOM_ONLY: - raise ValueError( - "Custom index not configured but CUSTOM_ONLY search scope requested" - ) - - if self.search_scope in [SearchScope.BASE_ONLY, SearchScope.BASE_AND_CUSTOM]: - indices.append(self.base_index) - - return indices def _compute_place_like_statvar_store(self, constraints: list[str]) -> None: """Compute and cache place-like to statistical variable mappings. @@ -275,10 +239,6 @@ def _get_topic_places_with_data( return places_with_data - # - # New Search Indicators Endpoint (/api/nl/search-indicators) - # - def _check_topic_exists_recursive( self, topic_dcid: str, place_dcids: list[str] ) -> bool: @@ -359,60 +319,6 @@ def _expand_topics_to_variables( return list(expanded_variables.values()) - async def _call_search_indicators_temp( - self, queries: list[str], *, max_results: int = 10 - ) -> dict: - """ - Temporary method that mirrors search_svs but calls the new search-indicators endpoint. - - This method takes the same arguments and returns the same structure as search_svs, - but uses the new /api/nl/search-indicators endpoint instead of /api/nl/search-vector. - - This method is temporary to create a minimal delta between the two endpoints to minimize the impact of the change. - After the 1.0 release, this method should be removed in favor of a more complete implementation. - - Returns: - Dictionary mapping query strings to lists of results with 'SV' and 'CosineScore' keys - """ - results_map = {} - endpoint_url = f"{self.sv_search_base_url}/api/nl/search-indicators" - headers = {"Content-Type": "application/json", **SURFACE_HEADER} - - # Use precomputed indices based on configured search scope - indices = self.search_indices - - for query in queries: - # Prepare parameters for the new endpoint - params = { - "queries": [query], - "limit_per_index": max_results, - "index": indices, - } - - try: - response = await asyncio.to_thread( - requests.get, - endpoint_url, - params=params, - headers=headers, # noqa: S113 - ) - response.raise_for_status() - api_response = response.json() - - # Transform the response to match search_svs format - transformed_results = self._transform_search_indicators_to_svs_format( - api_response, max_results=max_results - ) - results_map[query] = transformed_results - - except Exception as e: # noqa: BLE001 - logger.error( - "An unexpected error occurred for query '%s': %s", query, e - ) - results_map[query] = [] - - return results_map - def _call_fetch_indicators(self, queries: list[str]) -> dict: """ Helper method to call the datacommons-client fetch_indicators and transform the response. @@ -473,43 +379,6 @@ def _call_fetch_indicators(self, queries: list[str]) -> dict: return results_map - def _transform_search_indicators_to_svs_format( - self, api_response: dict, *, max_results: int = 10 - ) -> list[dict]: - """ - Transform search-indicators response to match search_svs format. - - Returns: - List of dictionaries with 'SV' and 'CosineScore' keys - """ - results = [] - query_results = api_response.get("queryResults", []) - - for query_result in query_results: - for index_result in query_result.get("indexResults", []): - for indicator in index_result.get("results", []): - dcid = indicator.get("dcid") - if not dcid: - continue - - # Extract score (default to 0.0 if not present) - score = indicator.get("score", 0.0) - - results.append( - { - "SV": dcid, - "CosineScore": score, - "description": indicator.get("description"), - "alternate_descriptions": indicator.get( - "search_descriptions" - ), - } - ) - - # Sort by score descending, then limit results - results.sort(key=lambda x: x["CosineScore"], reverse=True) - return results[:max_results] - async def fetch_indicators( self, query: str, @@ -616,25 +485,24 @@ async def fetch_indicators( } async def _search_vector( - self, query: str, max_results: int = 10, *, include_topics: bool = True + self, + query: str, + # TODO(keyurs): Use max_results once it's supported by the underlying client. + # The noqa: ARG002 is to suppress the unused argument error. + max_results: int = 10, # noqa: ARG002 + *, + include_topics: bool = True, ) -> dict: """ - Search for topics and variables using the search-indicators or search-vector endpoint. + Search for topics and variables using the fetch_indicators library method. """ # Always include topics since we need to expand topics to variables. - if self.use_search_indicators: - logger.info("Calling legacy search-indicators endpoint for: '%s'", query) - search_results = await self._call_search_indicators_temp( - queries=[query], - max_results=max_results, - ) - else: - logger.info("Calling client library fetch_indicators for: '%s'", query) - # Run the synchronous client method in a thread - search_results = await asyncio.to_thread( - self._call_fetch_indicators, - queries=[query], - ) + logger.info("Calling client library fetch_indicators for: '%s'", query) + # Run the synchronous client method in a thread + search_results = await asyncio.to_thread( + self._call_fetch_indicators, + queries=[query], + ) results = search_results.get(query, []) @@ -839,7 +707,6 @@ def _create_base_dc_client(settings: BaseDCSettings) -> DCClient: } if settings.api_root: logger.info("Using API root for base DC: %s", settings.api_root) - logger.info("Using search root for base DC: %s", settings.search_root) dc_client_args["url"] = settings.api_root dc = DataCommonsClient(**dc_client_args) @@ -847,11 +714,7 @@ def _create_base_dc_client(settings: BaseDCSettings) -> DCClient: return DCClient( dc=dc, search_scope=SearchScope.BASE_ONLY, - base_index=settings.base_index, - custom_index=None, - sv_search_base_url=settings.search_root, topic_store=topic_store, - use_search_indicators=settings.use_search_indicators, ) @@ -884,11 +747,7 @@ def _create_custom_dc_client(settings: CustomDCSettings) -> DCClient: return DCClient( dc=dc, search_scope=search_scope, - base_index=settings.base_index, - custom_index=settings.custom_index, - sv_search_base_url=settings.custom_dc_url, # Use custom_dc_url as sv_search_base_url topic_store=topic_store, # TODO (@jm-rivera): Remove place-like parameter new search endpoint is live. _place_like_constraints=settings.place_like_constraints, - use_search_indicators=settings.use_search_indicators, ) diff --git a/packages/datacommons-mcp/datacommons_mcp/data_models/settings.py b/packages/datacommons-mcp/datacommons_mcp/data_models/settings.py index 08bc379..2ade789 100644 --- a/packages/datacommons-mcp/datacommons_mcp/data_models/settings.py +++ b/packages/datacommons-mcp/datacommons_mcp/data_models/settings.py @@ -47,12 +47,6 @@ class DCSettings(BaseSettings): default="", alias="DC_API_KEY", description="API key for Data Commons" ) - use_search_indicators: bool = Field( - default=False, - alias="DC_USE_SEARCH_INDICATORS", - description="Whether to use the legacy search-indicators endpoint (True) or the client library (False) for fetching indicators.", - ) - instructions_dir: str | None = Field( default=None, alias="DC_INSTRUCTIONS_DIR", @@ -71,16 +65,6 @@ def __init__(self, **kwargs: dict[str, Any]) -> None: alias="DC_TYPE", description="Type of Data Commons (must be 'base')", ) - search_root: str = Field( - default="https://datacommons.org", - alias="DC_SEARCH_ROOT", - description="Search base URL for base DC", - ) - base_index: str = Field( - default="base_uae_mem", - alias="DC_BASE_INDEX", - description="Search index for base DC", - ) topic_cache_paths: list[str] | None = Field( default=None, alias="DC_TOPIC_CACHE_PATHS", @@ -130,16 +114,6 @@ def __init__(self, **kwargs: dict[str, Any]) -> None: alias="DC_SEARCH_SCOPE", description="Search scope for queries", ) - base_index: str = Field( - default="medium_ft", - alias="DC_BASE_INDEX", - description="Search index for base DC", - ) - custom_index: str = Field( - default="user_all_minilm_mem", - alias="DC_CUSTOM_INDEX", - description="Search index for custom DC", - ) root_topic_dcids: list[str] | None = Field( default=None, alias="DC_ROOT_TOPIC_DCIDS", diff --git a/packages/datacommons-mcp/tests/test_dc_client.py b/packages/datacommons-mcp/tests/test_dc_client.py index 2bd2745..bfd9269 100644 --- a/packages/datacommons-mcp/tests/test_dc_client.py +++ b/packages/datacommons-mcp/tests/test_dc_client.py @@ -22,7 +22,7 @@ """ import os -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import Mock, patch import pytest from datacommons_client.client import DataCommonsClient @@ -59,7 +59,7 @@ def mocked_datacommons_client(): class TestDCClientConstructor: - """Tests for the DCClient constructor and search indices computation.""" + """Tests for the DCClient constructor.""" def test_dc_client_constructor_base_dc(self, mocked_datacommons_client): """ @@ -71,9 +71,6 @@ def test_dc_client_constructor_base_dc(self, mocked_datacommons_client): # Assert: Verify the client is configured correctly assert client_under_test.dc == mocked_datacommons_client assert client_under_test.search_scope == SearchScope.BASE_ONLY - assert client_under_test.base_index == "base_uae_mem" - assert client_under_test.custom_index is None - assert client_under_test.search_indices == ["base_uae_mem"] def test_dc_client_constructor_custom_dc(self, mocked_datacommons_client): """ @@ -83,16 +80,11 @@ def test_dc_client_constructor_custom_dc(self, mocked_datacommons_client): client_under_test = DCClient( dc=mocked_datacommons_client, search_scope=SearchScope.CUSTOM_ONLY, - base_index="medium_ft", - custom_index="user_all_minilm_mem", ) # Assert: Verify the client is configured correctly assert client_under_test.dc == mocked_datacommons_client assert client_under_test.search_scope == SearchScope.CUSTOM_ONLY - assert client_under_test.base_index == "medium_ft" - assert client_under_test.custom_index == "user_all_minilm_mem" - assert client_under_test.search_indices == ["user_all_minilm_mem"] def test_dc_client_constructor_base_and_custom(self, mocked_datacommons_client): """ @@ -102,47 +94,10 @@ def test_dc_client_constructor_base_and_custom(self, mocked_datacommons_client): client_under_test = DCClient( dc=mocked_datacommons_client, search_scope=SearchScope.BASE_AND_CUSTOM, - base_index="medium_ft", - custom_index="user_all_minilm_mem", ) # Assert: Verify the client is configured correctly assert client_under_test.search_scope == SearchScope.BASE_AND_CUSTOM - assert client_under_test.search_indices == ["user_all_minilm_mem", "medium_ft"] - - def test_compute_search_indices_validation_custom_only_without_index( - self, mocked_datacommons_client - ): - """ - Test that CUSTOM_ONLY search scope without custom_index raises ValueError. - """ - # Arrange & Act & Assert: Creating client with invalid configuration should raise ValueError - with pytest.raises( - ValueError, - match="Custom index not configured but CUSTOM_ONLY search scope requested", - ): - DCClient( - dc=mocked_datacommons_client, - search_scope=SearchScope.CUSTOM_ONLY, - custom_index=None, - ) - - def test_compute_search_indices_validation_custom_only_with_empty_index( - self, mocked_datacommons_client - ): - """ - Test that CUSTOM_ONLY search scope with empty custom_index raises ValueError. - """ - # Arrange & Act & Assert: Creating client with invalid configuration should raise ValueError - with pytest.raises( - ValueError, - match="Custom index not configured but CUSTOM_ONLY search scope requested", - ): - DCClient( - dc=mocked_datacommons_client, - search_scope=SearchScope.CUSTOM_ONLY, - custom_index="", - ) @pytest.mark.asyncio @@ -219,9 +174,8 @@ async def test_fetch_indicators_include_topics_true( """Test basic functionality without place filtering.""" # Arrange: Create client for the old path and mock search results client_under_test = DCClient(dc=mocked_datacommons_client) - client_under_test.use_search_indicators = True - # Mock search_svs to return topics and variables + # Mock search results to return topics and variables mock_search_results = { "test query": [ {"SV": "dc/topic/Health", "CosineScore": 0.9}, @@ -231,8 +185,8 @@ async def test_fetch_indicators_include_topics_true( ] } - # Mock the _call_search_indicators_temp method - client_under_test._call_search_indicators_temp = AsyncMock( + # Mock the _call_fetch_indicators method + client_under_test._call_fetch_indicators = Mock( return_value=mock_search_results ) @@ -289,9 +243,8 @@ async def test_fetch_indicators_include_topics_false( """Test basic functionality without place filtering.""" # Arrange: Create client for the old path and mock search results client_under_test = DCClient(dc=mocked_datacommons_client) - client_under_test.use_search_indicators = True - # Mock search_svs to return topics and variables + # Mock search results to return topics and variables mock_search_results = { "test query": [ {"SV": "dc/variable/Count_Person", "CosineScore": 0.7}, @@ -299,8 +252,8 @@ async def test_fetch_indicators_include_topics_false( ] } - # Mock the _call_search_indicators_temp method - client_under_test._call_search_indicators_temp = AsyncMock( + # Mock the _call_fetch_indicators method + client_under_test._call_fetch_indicators = Mock( return_value=mock_search_results ) @@ -353,9 +306,8 @@ async def test_fetch_indicators_include_topics_with_places( """Test functionality with place filtering.""" # Arrange: Create client for the old path and mock search results client_under_test = DCClient(dc=mocked_datacommons_client) - client_under_test.use_search_indicators = True - # Mock search_svs to return topics and variables + # Mock search results to return topics and variables mock_search_results = { "test query": [ {"SV": "dc/topic/Health", "CosineScore": 0.9}, @@ -363,8 +315,8 @@ async def test_fetch_indicators_include_topics_with_places( ] } - # Mock the _call_search_indicators_temp method - client_under_test._call_search_indicators_temp = AsyncMock( + # Mock the _call_fetch_indicators method + client_under_test._call_fetch_indicators = Mock( return_value=mock_search_results ) @@ -507,9 +459,8 @@ async def test_search_entities_filters_invalid_topics( """Test that _search_entities filters out topics that don't exist in the topic store.""" # Arrange: Create client for the old path and mock search results client_under_test = DCClient(dc=mocked_datacommons_client) - client_under_test.use_search_indicators = True - # Mock search_svs to return topics (some valid, some invalid) and variables + # Mock search results to return topics (some valid, some invalid) and variables mock_search_results = { "test query": [ {"SV": "dc/topic/Health", "CosineScore": 0.9}, # Valid topic @@ -522,8 +473,8 @@ async def test_search_entities_filters_invalid_topics( ] } - # Mock the _call_search_indicators_temp method - client_under_test._call_search_indicators_temp = AsyncMock( + # Mock the _call_fetch_indicators method + client_under_test._call_fetch_indicators = Mock( return_value=mock_search_results ) @@ -563,9 +514,8 @@ async def test_search_entities_with_no_topic_store(self, mocked_datacommons_clie """ # Arrange: Create client and mock search results client_under_test = DCClient(dc=mocked_datacommons_client) - client_under_test.use_search_indicators = True - # Mock search_svs to return topics and variables + # Mock search results to return topics and variables mock_search_results = { "test query": [ {"SV": "dc/topic/Health", "CosineScore": 0.9}, @@ -573,8 +523,8 @@ async def test_search_entities_with_no_topic_store(self, mocked_datacommons_clie ] } - # Mock the _call_search_indicators_temp method - client_under_test._call_search_indicators_temp = AsyncMock( + # Mock the _call_fetch_indicators method + client_under_test._call_fetch_indicators = Mock( return_value=mock_search_results ) @@ -597,84 +547,6 @@ async def test_search_entities_with_no_topic_store(self, mocked_datacommons_clie assert len(result["variables"]) == 1 assert "dc/variable/Count_Person" in result["variables"] - @pytest.mark.asyncio - async def test_fetch_indicators_checks_flag(self, mocked_datacommons_client: Mock): - """ - Test that _search_vector calls the correct method based on use_search_indicators. - """ - # Arrange - client_under_test = DCClient(dc=mocked_datacommons_client) - # Default is False - assert client_under_test.use_search_indicators is False - - # Mock _call_fetch_indicators - mock_results = {"test query": []} - client_under_test._call_fetch_indicators = Mock(return_value=mock_results) - client_under_test._call_search_indicators_temp = AsyncMock() - - # Act - await client_under_test._search_vector("test query") - - # Assert - # Should call _call_fetch_indicators (in a thread, so we check the mock) - client_under_test._call_fetch_indicators.assert_called_once_with( - queries=["test query"] - ) - # Should NOT call _call_search_indicators_temp - client_under_test._call_search_indicators_temp.assert_not_called() - - # Step 2: Set flag to True - client_under_test.use_search_indicators = True - client_under_test._call_fetch_indicators.reset_mock() - client_under_test._call_search_indicators_temp.reset_mock() - client_under_test._call_search_indicators_temp.return_value = {} - - # Act - await client_under_test._search_vector("test query") - - # Assert - # Should call _call_search_indicators_temp - client_under_test._call_search_indicators_temp.assert_awaited_once() - # Should NOT call _call_fetch_indicators - client_under_test._call_fetch_indicators.assert_not_called() - - @pytest.mark.asyncio - async def test_search_entities_with_per_search_limit( - self, mocked_datacommons_client: Mock - ): - """ - Test _search_vector with per_search_limit parameter. - """ - client_under_test = DCClient(dc=mocked_datacommons_client) - client_under_test.use_search_indicators = True - - # Mock search_svs to return results - mock_search_results = { - "test query": [ - {"SV": "Count_Person", "CosineScore": 0.8}, - {"SV": "Count_Household", "CosineScore": 0.7}, - ] - } - client_under_test._call_search_indicators_temp = AsyncMock( - return_value=mock_search_results - ) - - result = await client_under_test._search_vector( # Corrected method name - "test query", include_topics=True, max_results=2 - ) - - # Verify that _call_search_indicators_temp was called with max_results=2 - client_under_test._call_search_indicators_temp.assert_awaited_once_with( - queries=["test query"], max_results=2 - ) - - # Should return variables (no topics since topic_store is None by default) - assert "topics" in result - assert "variables" in result - assert len(result["variables"]) == 2 # Both variables should be included - assert "Count_Person" in result["variables"] - assert "Count_Household" in result["variables"] - def test_call_fetch_indicators_passes_target_default( self, mocked_datacommons_client ): @@ -704,7 +576,6 @@ def test_call_fetch_indicators_passes_target_custom( client_under_test = DCClient( dc=mocked_datacommons_client, search_scope=SearchScope.CUSTOM_ONLY, - custom_index="test_index", ) # Mock the resolve endpoint @@ -745,8 +616,6 @@ def test_create_dc_client_base_dc( assert isinstance(result, DCClient) assert result.dc == mock_dc_instance assert result.search_scope == SearchScope.BASE_ONLY - assert result.base_index == "base_uae_mem" - assert result.custom_index is None mock_dc_client.assert_called_with( api_key="test_api_key", surface_header_value=SURFACE_HEADER_VALUE, @@ -778,12 +647,6 @@ def test_create_dc_client_custom_dc( assert isinstance(result, DCClient) assert result.dc == mock_dc_instance assert result.search_scope == SearchScope.BASE_AND_CUSTOM - assert result.base_index == "medium_ft" - assert result.custom_index == "user_all_minilm_mem" - assert ( - result.sv_search_base_url - == "https://staging-datacommons-web-service-650536812276.northamerica-northeast1.run.app" - ) # Should have called DataCommonsClient with computed api_base_url expected_api_url = "https://staging-datacommons-web-service-650536812276.northamerica-northeast1.run.app/core/api/v2/" mock_dc_client.assert_called_with( diff --git a/packages/datacommons-mcp/tests/test_settings.py b/packages/datacommons-mcp/tests/test_settings.py index b36b63f..893e450 100644 --- a/packages/datacommons-mcp/tests/test_settings.py +++ b/packages/datacommons-mcp/tests/test_settings.py @@ -35,8 +35,6 @@ def test_loads_with_minimal_config(self): assert isinstance(settings, BaseDCSettings) assert settings.api_key == "test_key" - assert settings.search_root == "https://datacommons.org" - assert settings.base_index == "base_uae_mem" assert settings.topic_cache_paths is None def test_loads_with_env_var_overrides(self): @@ -44,16 +42,12 @@ def test_loads_with_env_var_overrides(self): env_vars = { "DC_API_KEY": "test_key", "DC_TYPE": "base", - "DC_SEARCH_ROOT": "https://custom.com", - "DC_BASE_INDEX": "custom_index", "DC_TOPIC_CACHE_PATHS": "/path/to/cache1.json, /path/to/cache2.json", } with patch.dict(os.environ, env_vars): settings = get_dc_settings() assert isinstance(settings, BaseDCSettings) - assert settings.search_root == "https://custom.com" - assert settings.base_index == "custom_index" assert settings.topic_cache_paths == [ "/path/to/cache1.json", "/path/to/cache2.json", @@ -86,8 +80,6 @@ def test_loads_with_minimal_config(self): assert settings.custom_dc_url == "https://test.com" assert settings.api_base_url == "https://test.com/core/api/v2/" assert settings.search_scope == SearchScope.BASE_AND_CUSTOM - assert settings.base_index == "medium_ft" - assert settings.custom_index == "user_all_minilm_mem" assert settings.root_topic_dcids is None def test_loads_with_env_var_overrides(self): @@ -97,8 +89,6 @@ def test_loads_with_env_var_overrides(self): "DC_TYPE": "custom", "CUSTOM_DC_URL": "https://test.com", "DC_SEARCH_SCOPE": "custom_only", - "DC_BASE_INDEX": "custom_base", - "DC_CUSTOM_INDEX": "custom_custom", "DC_ROOT_TOPIC_DCIDS": "topic1, topic2", } with patch.dict(os.environ, env_vars): @@ -106,8 +96,6 @@ def test_loads_with_env_var_overrides(self): assert isinstance(settings, CustomDCSettings) assert settings.search_scope == SearchScope.CUSTOM_ONLY - assert settings.base_index == "custom_base" - assert settings.custom_index == "custom_custom" assert settings.root_topic_dcids == ["topic1", "topic2"] def test_missing_custom_url_raises_error(self):