Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions sdk/ai/azure-ai-projects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@

### Breaking Changes

* Renamed model `AgentEndpoint` to `AgentEndpointConfig`.
* Agent Endpoint beta operations: Removed required parameters `user_isolation_key` and `chat_isolation_key` from the `HeaderIsolationKeySource` class constructor.
* Agent Endpoint beta operations:
* Renamed model `AgentEndpoint` to `AgentEndpointConfig`.
* Removed previously required parameters `user_isolation_key` and `chat_isolation_key` from the `HeaderIsolationKeySource` class constructor.

### Bugs Fixed
* Fixed telemetry instrumentor to correctly call is_recording() as a method on spans, ensuring non-recording spans are properly skipped (e.g., when sampling is configured) ([GitHub issue 46544](https://github.com/Azure/azure-sdk-for-python/issues/46544)).
Expand Down
39 changes: 39 additions & 0 deletions sdk/ai/azure-ai-projects/azure/ai/projects/models/_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize
"""

import warnings
from typing import Final, FrozenSet, List, Dict, Mapping, Optional, Any, Tuple
from azure.core.polling import LROPoller, AsyncLROPoller, PollingMethod, AsyncPollingMethod
from azure.core.polling.base_polling import (
Expand Down Expand Up @@ -390,10 +391,48 @@ def from_continuation_token(
] # Add all objects you want publicly available to users at this package level


# Deprecated names handled via _models_getattr injected by patch_sdk()
_DEPRECATED_NAMES: Dict[str, str] = {
# Deprecated Name: Replacement Name
"AgentEndpoint": "AgentEndpointConfig", # Deprecated in v2.2.0
}

def _models_getattr(name: str) -> Any:
"""Module-level __getattr__ for deprecation warnings on azure.ai.projects.models.

This function is injected into the models module by patch_sdk() to handle
deprecated name lookups (PEP 562).

:param name: The attribute name being accessed.
:type name: str
:return: The replacement attribute value.
:rtype: Any
:raises AttributeError: If the attribute is not found.
"""
import sys

if name in _DEPRECATED_NAMES:
replacement = _DEPRECATED_NAMES[name]
warnings.warn(
f"'{name}' is deprecated and will be removed in the next release. "
f"Use '{replacement}' instead.",
DeprecationWarning,
stacklevel=2,
)
return getattr(sys.modules["azure.ai.projects.models"], replacement)
raise AttributeError(f"module 'azure.ai.projects.models' has no attribute {name!r}")


def patch_sdk():
"""Do not remove from this file.

`patch_sdk` is a last resort escape hatch that allows you to do customizations
you can't accomplish using the techniques described in
https://aka.ms/azsdk/python/dpcodegen/python/customize
"""
import sys

# Inject __getattr__ into the models module for PEP 562 deprecation handling (https://peps.python.org/pep-0562/)
models_module = sys.modules.get("azure.ai.projects.models")
if models_module is not None:
models_module.__getattr__ = _models_getattr # type: ignore[attr-defined]
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

"""Tests for AgentEndpoint deprecation warning."""

import warnings

class TestAgentEndpointDeprecation:
"""Test that AgentEndpoint is deprecated but still functional (PEP 562 __getattr__)."""

def test_agent_endpoint_emits_deprecation_warning_on_access(self):
"""Test that accessing AgentEndpoint emits a DeprecationWarning (PEP 562)."""
import azure.ai.projects.models as models

with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
# Warning is emitted on attribute access, not instantiation
_ = models.AgentEndpoint # type: ignore[attr-defined]

assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert "AgentEndpoint" in str(w[0].message)
assert "AgentEndpointConfig" in str(w[0].message)
Comment thread
dargilco marked this conversation as resolved.

def test_agent_endpoint_config_no_warning(self):
"""Test that using AgentEndpointConfig does not emit a warning."""
import azure.ai.projects.models as models

with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
_ = models.AgentEndpointConfig
config = models.AgentEndpointConfig()

# Filter only DeprecationWarnings related to AgentEndpoint
deprecation_warnings = [
warning for warning in w
if issubclass(warning.category, DeprecationWarning)
and "AgentEndpoint" in str(warning.message)
]
assert len(deprecation_warnings) == 0

def test_agent_endpoint_is_same_class_as_config(self):
"""Test that AgentEndpoint returns the same class as AgentEndpointConfig (PEP 562)."""
import azure.ai.projects.models as models

with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
# With PEP 562 __getattr__, AgentEndpoint IS AgentEndpointConfig
assert models.AgentEndpoint is models.AgentEndpointConfig # type: ignore[attr-defined]

def test_agent_endpoint_instance_is_config_instance(self):
"""Test that AgentEndpoint instance is also an AgentEndpointConfig instance."""
import azure.ai.projects.models as models

with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
endpoint = models.AgentEndpoint() # type: ignore[attr-defined]

assert isinstance(endpoint, models.AgentEndpointConfig)

def test_agent_endpoint_functionality_preserved(self):
"""Test that AgentEndpoint still works with all its parameters."""
import azure.ai.projects.models as models

with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
endpoint = models.AgentEndpoint( # type: ignore[attr-defined]
protocols=[models.AgentEndpointProtocol.A2A],
)

assert endpoint.protocols == [models.AgentEndpointProtocol.A2A]