Python: Stop accessing private Azure SDK attributes in Azure AI Search connector#13971
Python: Stop accessing private Azure SDK attributes in Azure AI Search connector#13971SergeyMenshykh wants to merge 5 commits intomicrosoft:mainfrom
Conversation
…h connector Replace access to SearchIndexClient._endpoint and ._credential (removed in azure-search-documents 12.0.0 TypeSpec migration) with explicit endpoint and credential fields on AzureAISearchStore and AzureAISearchCollection. - Refactor _get_search_client() to accept explicit endpoint + credential params - Extract _resolve_credential() helper from _get_search_index_client() - Add search_endpoint and search_credential fields to Store and Collection - Add search_credential parameter to AzureAISearchCollection constructor - Update tests to assert on public fields instead of private SDK attributes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Python Azure AI Search vector store connector to avoid relying on private Azure SDK attributes (e.g., SearchIndexClient._endpoint / ._credential) that were removed in azure-search-documents==12.0.0, by threading endpoint and credential explicitly through the connector’s store/collection classes.
Changes:
- Refactors
_get_search_client()to take explicitendpoint+credentialparameters rather than reading fromSearchIndexClientinternals. - Extracts credential selection into a reusable
_resolve_credential()helper and updates index client creation to use it. - Stores
search_endpoint/search_credentialonAzureAISearchStoreandAzureAISearchCollection, and updates unit tests to assert via these public fields rather than SDK private attributes.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| python/semantic_kernel/connectors/azure_ai_search.py | Refactors client construction to stop depending on private Azure SDK fields; adds explicit endpoint/credential threading and _resolve_credential(). |
| python/tests/unit/connectors/memory/test_azure_ai_search.py | Updates tests to avoid checking SDK private attributes and adds coverage for _resolve_credential(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Align with azure-search-documents 11.7.0b2 which no longer accepts sync TokenCredential in async SearchClient and SearchIndexClient. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ent provided directly When AzureAISearchStore was created with a pre-built search_index_client, search_endpoint defaulted to empty string. get_collection() forwarded this to AzureAISearchSettings which treated it as an explicit (invalid) endpoint, preventing env var fallback and raising VectorStoreInitializationException. Change search_endpoint default from empty string to None on both AzureAISearchCollection and AzureAISearchStore so that KernelBaseSettings correctly falls back to environment variables. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The default distance_function fixture uses cosine_similarity which was never in Azure AI Search's DISTANCE_FUNCTION_MAP. Tests passed before because MagicMock(spec=SearchIndex) satisfied isinstance() with SDK v11, bypassing distance function validation. With SDK v12 the isinstance check fails, exposing the incorrect default. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Python Test Coverage Report •
Python Unit Test Overview
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Automated Code Review
Reviewers: 4 | Confidence: 92%
✓ Correctness
The PR correctly eliminates access to private Azure SDK attributes (
_endpoint,_credential) onSearchIndexClientby storing endpoint and credential as explicit fields. The credential/endpoint resolution logic is properly extracted into_resolve_credential(), and the fallback behavior whensearch_index_clientis provided directly (without explicit endpoint/credential) works correctly becauseKernelBaseSettings.__init__stripsNonekwargs (line 55 of kernel_pydantic.py), allowing Pydantic to fall back to environment variables. TheTokenCredential→AsyncTokenCredentialnarrowing is correct since the connector exclusively uses async clients. No correctness issues found.
✓ Security Reliability
This PR correctly eliminates reliance on private Azure SDK attributes (
_endpoint,_credential) that broke inazure-search-documents12.0.0. The refactoring stores endpoint and credential as explicit fields, threads them through construction, and introduces a_resolve_credentialhelper. No blocking security or reliability issues found. The credential fields useAnytyping on the Pydantic models, but since the existingsearch_clientandsearch_index_clientfields already store arbitrary SDK objects containing credentials, this doesn't change the risk surface. One minor observation:_resolve_credentialis called twice with the same arguments in bothAzureAISearchCollection.__init__(third path) andAzureAISearchStore.__init__, which creates distinctAzureKeyCredentialinstances when resolved fromapi_key, but this has no practical security or reliability impact.
✓ Test Coverage
The PR properly migrates away from private Azure SDK attributes and adds tests for the new
_resolve_credentialhelper and theget_collectionpath whensearch_index_clientis provided directly. Two test coverage gaps stand out: (1)test_resolve_credentialexcludesAZURE_AI_SEARCH_API_KEYfrom the environment, so theapi_keyfallback branch — the most common production path — is never directly tested; (2)test_get_collection_with_provided_search_index_clientverifies collection creation but doesn't assert that the collection'ssearch_endpointandsearch_credentialare properly resolved from environment variables, which is central to the PR's purpose.
✓ Design Approach
The private-attribute removal is headed in the right direction, but one construction path still drops the explicit endpoint/credential state the PR is trying to preserve:
AzureAISearchStoreignores caller-suplied connection arguments whenever a prebuiltsearch_index_clientis injected, soget_collection()can still fall back to env-based resolution instead of using the values the caller already provided.
Automated review by SergeyMenshykh's agents
When a caller passes a pre-built search_index_client alongside explicit connection args, the endpoint and credential were not captured because they were only resolved inside the 'if not search_index_client' branch. This caused get_collection() to forward None values, falling back to env vars instead of using the caller's explicit values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Motivation and Context
CI fails with
AttributeError: 'SearchIndexClient' object has no attribute '_endpoint'whenazure-search-documentsresolves to 12.0.0 (released 2026-04-01). The 12.0.0 release migrated from AutoRest to TypeSpec code generation, removing private attributes_endpointand_credentialfromSearchIndexClient.CI uses
uv sync -Uwhich upgrades past the lockfile, pulling in 12.0.0 sincepyproject.tomlspecifies>= 11.6.0b4with no upper bound.Description
Stop reading
SearchIndexClient._endpointand._credential. Instead, store endpoint and credential as explicit fields onAzureAISearchStoreandAzureAISearchCollection, and pass them directly when constructingSearchClient.Changes:
_get_search_client()accepts explicitendpoint+credentialparams instead of extracting fromSearchIndexClientprivate attrs_resolve_credential()new helper extracted from_get_search_index_client()for reuseAzureAISearchStore/AzureAISearchCollectionstoresearch_endpointandsearch_credentialas fields, thread them through constructionContribution Checklist
azure-search-documents==11.7.0b2and==12.0.0