Skip to content

Commit b0b8ea7

Browse files
authored
azure-ai-projects SDK 1.1.0b5 (#43379)
* Re-emit * update tests assets * Fix quality gates and formatting * Fix links
1 parent fd0a7b0 commit b0b8ea7

24 files changed

+321
-302
lines changed

sdk/ai/azure-ai-projects/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Release History
22

3+
## 1.1.0b5 (Unreleased)
4+
5+
### Features added
6+
37
## 1.1.0b4 (2025-09-12)
48

59
### Bugs Fixed

sdk/ai/azure-ai-projects/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "python",
44
"TagPrefix": "python/ai/azure-ai-projects",
5-
"Tag": "python/ai/azure-ai-projects_e1ef59ae5f"
5+
"Tag": "python/ai/azure-ai-projects_17a05ba347"
66
}

sdk/ai/azure-ai-projects/azure/ai/projects/_client.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,14 @@ class AIProjectClient:
4545
:ivar red_teams: RedTeamsOperations operations
4646
:vartype red_teams: azure.ai.projects.operations.RedTeamsOperations
4747
:param endpoint: Project endpoint. In the form
48-
"https://your-ai-services-account-name.services.ai.azure.com/api/projects/_project"
49-
if your Foundry Hub has only one Project, or to use the default Project in your Hub. Or in the
50-
form "https://your-ai-services-account-name.services.ai.azure.com/api/projects/your-project-name"
51-
if you want to explicitly specify the Foundry Project name. Required.
48+
"`https://your-ai-services-account-name.services.ai.azure.com/api/projects/_project
49+
<https://your-ai-services-account-name.services.ai.azure.com/api/projects/_project>`_"
50+
if your Foundry Hub has only one Project, or to use the default Project in your Hub. Or in the
51+
form
52+
"`https://your-ai-services-account-name.services.ai.azure.com/api/projects/your-project-name
53+
<https://your-ai-services-account-name.services.ai.azure.com/api/projects/your-project-name>`_"
54+
if you want to explicitly
55+
specify the Foundry Project name. Required.
5256
:type endpoint: str
5357
:param credential: Credential used to authenticate requests to the service. Required.
5458
:type credential: ~azure.core.credentials.TokenCredential

sdk/ai/azure-ai-projects/azure/ai/projects/_configuration.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@ class AIProjectClientConfiguration: # pylint: disable=too-many-instance-attribu
2323
attributes.
2424
2525
:param endpoint: Project endpoint. In the form
26-
"https://your-ai-services-account-name.services.ai.azure.com/api/projects/_project"
27-
if your Foundry Hub has only one Project, or to use the default Project in your Hub. Or in the
28-
form "https://your-ai-services-account-name.services.ai.azure.com/api/projects/your-project-name"
29-
if you want to explicitly specify the Foundry Project name. Required.
26+
"`https://your-ai-services-account-name.services.ai.azure.com/api/projects/_project
27+
<https://your-ai-services-account-name.services.ai.azure.com/api/projects/_project>`_"
28+
if your Foundry Hub has only one Project, or to use the default Project in your Hub. Or in the
29+
form
30+
"`https://your-ai-services-account-name.services.ai.azure.com/api/projects/your-project-name
31+
<https://your-ai-services-account-name.services.ai.azure.com/api/projects/your-project-name>`_"
32+
if you want to explicitly
33+
specify the Foundry Project name. Required.
3034
:type endpoint: str
3135
:param credential: Credential used to authenticate requests to the service. Required.
3236
:type credential: ~azure.core.credentials.TokenCredential

sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
)
3434
if _console_logging_enabled:
3535
import sys
36+
3637
# Enable detailed console logs across Azure libraries
3738
azure_logger = logging.getLogger("azure")
3839
azure_logger.setLevel(logging.DEBUG)

sdk/ai/azure-ai-projects/azure/ai/projects/_utils/model_base.py

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from azure.core import CaseInsensitiveEnumMeta
3030
from azure.core.pipeline import PipelineResponse
3131
from azure.core.serialization import _Null
32+
from azure.core.rest import HttpResponse
3233

3334
_LOGGER = logging.getLogger(__name__)
3435

@@ -345,7 +346,7 @@ def _get_model(module_name: str, model_name: str):
345346

346347

347348
class _MyMutableMapping(MutableMapping[str, typing.Any]):
348-
def __init__(self, data: typing.Dict[str, typing.Any]) -> None:
349+
def __init__(self, data: dict[str, typing.Any]) -> None:
349350
self._data = data
350351

351352
def __contains__(self, key: typing.Any) -> bool:
@@ -425,7 +426,7 @@ def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
425426
return self._data.pop(key)
426427
return self._data.pop(key, default)
427428

428-
def popitem(self) -> typing.Tuple[str, typing.Any]:
429+
def popitem(self) -> tuple[str, typing.Any]:
429430
"""
430431
Removes and returns some (key, value) pair
431432
:returns: The (key, value) pair.
@@ -513,9 +514,7 @@ def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-m
513514
return o
514515

515516

516-
def _get_rest_field(
517-
attr_to_rest_field: typing.Dict[str, "_RestField"], rest_name: str
518-
) -> typing.Optional["_RestField"]:
517+
def _get_rest_field(attr_to_rest_field: dict[str, "_RestField"], rest_name: str) -> typing.Optional["_RestField"]:
519518
try:
520519
return next(rf for rf in attr_to_rest_field.values() if rf._rest_name == rest_name)
521520
except StopIteration:
@@ -538,7 +537,7 @@ class Model(_MyMutableMapping):
538537
_is_model = True
539538
# label whether current class's _attr_to_rest_field has been calculated
540539
# could not see _attr_to_rest_field directly because subclass inherits it from parent class
541-
_calculated: typing.Set[str] = set()
540+
_calculated: set[str] = set()
542541

543542
def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None:
544543
class_name = self.__class__.__name__
@@ -623,7 +622,7 @@ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self:
623622
# we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping',
624623
# 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object'
625624
mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order
626-
attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property
625+
attr_to_rest_field: dict[str, _RestField] = { # map attribute name to rest_field property
627626
k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type")
628627
}
629628
annotations = {
@@ -638,7 +637,7 @@ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self:
638637
rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None))
639638
if not rf._rest_name_input:
640639
rf._rest_name_input = attr
641-
cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items())
640+
cls._attr_to_rest_field: dict[str, _RestField] = dict(attr_to_rest_field.items())
642641
cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}")
643642

644643
return super().__new__(cls)
@@ -680,7 +679,7 @@ def _deserialize(cls, data, exist_discriminators):
680679
mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore # pylint: disable=no-member
681680
return mapped_cls._deserialize(data, exist_discriminators)
682681

683-
def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing.Any]:
682+
def as_dict(self, *, exclude_readonly: bool = False) -> dict[str, typing.Any]:
684683
"""Return a dict that can be turned into json using json.dump.
685684
686685
:keyword bool exclude_readonly: Whether to remove the readonly properties.
@@ -740,7 +739,7 @@ def _deserialize_with_union(deserializers, obj):
740739
def _deserialize_dict(
741740
value_deserializer: typing.Optional[typing.Callable],
742741
module: typing.Optional[str],
743-
obj: typing.Dict[typing.Any, typing.Any],
742+
obj: dict[typing.Any, typing.Any],
744743
):
745744
if obj is None:
746745
return obj
@@ -750,7 +749,7 @@ def _deserialize_dict(
750749

751750

752751
def _deserialize_multiple_sequence(
753-
entry_deserializers: typing.List[typing.Optional[typing.Callable]],
752+
entry_deserializers: list[typing.Optional[typing.Callable]],
754753
module: typing.Optional[str],
755754
obj,
756755
):
@@ -771,14 +770,14 @@ def _deserialize_sequence(
771770
return type(obj)(_deserialize(deserializer, entry, module) for entry in obj)
772771

773772

774-
def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.Any]:
773+
def _sorted_annotations(types: list[typing.Any]) -> list[typing.Any]:
775774
return sorted(
776775
types,
777776
key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"),
778777
)
779778

780779

781-
def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-branches
780+
def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-statements, too-many-branches
782781
annotation: typing.Any,
783782
module: typing.Optional[str],
784783
rf: typing.Optional["_RestField"] = None,
@@ -843,7 +842,10 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur
843842
return functools.partial(_deserialize_with_union, deserializers)
844843

845844
try:
846-
if annotation._name == "Dict": # pyright: ignore
845+
annotation_name = (
846+
annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore
847+
)
848+
if annotation_name.lower() == "dict":
847849
value_deserializer = _get_deserialize_callable_from_annotation(
848850
annotation.__args__[1], module, rf # pyright: ignore
849851
)
@@ -856,7 +858,10 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur
856858
except (AttributeError, IndexError):
857859
pass
858860
try:
859-
if annotation._name in ["List", "Set", "Tuple", "Sequence"]: # pyright: ignore
861+
annotation_name = (
862+
annotation.__name__ if hasattr(annotation, "__name__") else annotation._name # pyright: ignore
863+
)
864+
if annotation_name.lower() in ["list", "set", "tuple", "sequence"]:
860865
if len(annotation.__args__) > 1: # pyright: ignore
861866
entry_deserializers = [
862867
_get_deserialize_callable_from_annotation(dt, module, rf)
@@ -940,13 +945,13 @@ def _deserialize(
940945

941946
def _failsafe_deserialize(
942947
deserializer: typing.Any,
943-
value: typing.Any,
948+
response: HttpResponse,
944949
module: typing.Optional[str] = None,
945950
rf: typing.Optional["_RestField"] = None,
946951
format: typing.Optional[str] = None,
947952
) -> typing.Any:
948953
try:
949-
return _deserialize(deserializer, value, module, rf, format)
954+
return _deserialize(deserializer, response.json(), module, rf, format)
950955
except DeserializationError:
951956
_LOGGER.warning(
952957
"Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True
@@ -956,10 +961,10 @@ def _failsafe_deserialize(
956961

957962
def _failsafe_deserialize_xml(
958963
deserializer: typing.Any,
959-
value: typing.Any,
964+
response: HttpResponse,
960965
) -> typing.Any:
961966
try:
962-
return _deserialize_xml(deserializer, value)
967+
return _deserialize_xml(deserializer, response.text())
963968
except DeserializationError:
964969
_LOGGER.warning(
965970
"Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True
@@ -974,11 +979,11 @@ def __init__(
974979
name: typing.Optional[str] = None,
975980
type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin
976981
is_discriminator: bool = False,
977-
visibility: typing.Optional[typing.List[str]] = None,
982+
visibility: typing.Optional[list[str]] = None,
978983
default: typing.Any = _UNSET,
979984
format: typing.Optional[str] = None,
980985
is_multipart_file_input: bool = False,
981-
xml: typing.Optional[typing.Dict[str, typing.Any]] = None,
986+
xml: typing.Optional[dict[str, typing.Any]] = None,
982987
):
983988
self._type = type
984989
self._rest_name_input = name
@@ -1036,11 +1041,11 @@ def rest_field(
10361041
*,
10371042
name: typing.Optional[str] = None,
10381043
type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin
1039-
visibility: typing.Optional[typing.List[str]] = None,
1044+
visibility: typing.Optional[list[str]] = None,
10401045
default: typing.Any = _UNSET,
10411046
format: typing.Optional[str] = None,
10421047
is_multipart_file_input: bool = False,
1043-
xml: typing.Optional[typing.Dict[str, typing.Any]] = None,
1048+
xml: typing.Optional[dict[str, typing.Any]] = None,
10441049
) -> typing.Any:
10451050
return _RestField(
10461051
name=name,
@@ -1057,8 +1062,8 @@ def rest_discriminator(
10571062
*,
10581063
name: typing.Optional[str] = None,
10591064
type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin
1060-
visibility: typing.Optional[typing.List[str]] = None,
1061-
xml: typing.Optional[typing.Dict[str, typing.Any]] = None,
1065+
visibility: typing.Optional[list[str]] = None,
1066+
xml: typing.Optional[dict[str, typing.Any]] = None,
10621067
) -> typing.Any:
10631068
return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility, xml=xml)
10641069

@@ -1077,9 +1082,9 @@ def serialize_xml(model: Model, exclude_readonly: bool = False) -> str:
10771082
def _get_element(
10781083
o: typing.Any,
10791084
exclude_readonly: bool = False,
1080-
parent_meta: typing.Optional[typing.Dict[str, typing.Any]] = None,
1085+
parent_meta: typing.Optional[dict[str, typing.Any]] = None,
10811086
wrapped_element: typing.Optional[ET.Element] = None,
1082-
) -> typing.Union[ET.Element, typing.List[ET.Element]]:
1087+
) -> typing.Union[ET.Element, list[ET.Element]]:
10831088
if _is_model(o):
10841089
model_meta = getattr(o, "_xml", {})
10851090

@@ -1168,7 +1173,7 @@ def _get_element(
11681173
def _get_wrapped_element(
11691174
v: typing.Any,
11701175
exclude_readonly: bool,
1171-
meta: typing.Optional[typing.Dict[str, typing.Any]],
1176+
meta: typing.Optional[dict[str, typing.Any]],
11721177
) -> ET.Element:
11731178
wrapped_element = _create_xml_element(
11741179
meta.get("name") if meta else None, meta.get("prefix") if meta else None, meta.get("ns") if meta else None
@@ -1211,7 +1216,7 @@ def _deserialize_xml(
12111216
def _convert_element(e: ET.Element):
12121217
# dict case
12131218
if len(e.attrib) > 0 or len({child.tag for child in e}) > 1:
1214-
dict_result: typing.Dict[str, typing.Any] = {}
1219+
dict_result: dict[str, typing.Any] = {}
12151220
for child in e:
12161221
if dict_result.get(child.tag) is not None:
12171222
if isinstance(dict_result[child.tag], list):
@@ -1224,7 +1229,7 @@ def _convert_element(e: ET.Element):
12241229
return dict_result
12251230
# array case
12261231
if len(e) > 0:
1227-
array_result: typing.List[typing.Any] = []
1232+
array_result: list[typing.Any] = []
12281233
for child in e:
12291234
array_result.append(_convert_element(child))
12301235
return array_result

0 commit comments

Comments
 (0)