Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
1 change: 1 addition & 0 deletions sdk/ml/azure-ai-ml/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Other Changes

- Ensuring that azureml-dataprep-rslex is only installed for PyPy below 3.10 and CPython below 3.13.
- Adding support for Python 3.14.

## 1.30.0 (2025-10-29)

Expand Down
2 changes: 1 addition & 1 deletion sdk/ml/azure-ai-ml/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ We are excited to introduce the GA of Azure Machine Learning Python SDK v2. The
| [Samples][ml_samples]


This package has been tested with Python 3.8, 3.9, 3.10, 3.11, 3.12 and 3.13.
This package has been tested with Python 3.8, 3.9, 3.10, 3.11, 3.12, 3.13 and 3.14.

For a more complete set of Azure libraries, see https://aka.ms/azsdk/python/all

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,9 +517,17 @@ def __eq__(self, other: object) -> bool:
"""
if not isinstance(other, DistillationJob):
return False
parent_eq = super().__eq__(other)

if parent_eq is NotImplemented:
# Parent doesn't implement comparison, we'll continue comparison on our end
pass
elif not parent_eq:
# Parent says objects are not equal
return False

return (
super().__eq__(other)
and self.data_generation_type == other.data_generation_type
self.data_generation_type == other.data_generation_type
and self.data_generation_task_type == other.data_generation_task_type
and self.teacher_model_endpoint_connection.name == other.teacher_model_endpoint_connection.name
and self.student_model == other.student_model
Expand Down
4 changes: 2 additions & 2 deletions sdk/ml/azure-ai-ml/dev_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ pytest-mock
pytest
pydash
azure-mgmt-msi
pywin32==306 ; sys_platform == 'win32'
pywin32==311 ; sys_platform == 'win32'
docker;platform.python_implementation!="PyPy"
numpy;platform.python_implementation!="PyPy"
scikit-image;platform.python_implementation!="PyPy"
scikit-image;platform.python_implementation!="PyPy" and python_version < "3.14"
mldesigner
azure-mgmt-resourcegraph<9.0.0,>=2.0.0
azure-mgmt-resource<23.0.0,>=3.0.0
Expand Down
1 change: 1 addition & 0 deletions sdk/ml/azure-ai-ml/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"License :: OSI Approved :: MIT License",
],
zip_safe=False,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import pytest
import yaml
import json
import copy
import json
import sys

import pytest
import yaml
from test_utilities.utils import verify_entity_load_and_dump
from azure.ai.ml._restclient.v2022_02_01_preview.models import (
OnlineEndpointData,
EndpointAuthKeys as RestEndpointAuthKeys,
EndpointAuthToken as RestEndpointAuthToken,
)
from azure.ai.ml._restclient.v2023_10_01.models import BatchEndpoint as BatchEndpointData

from azure.ai.ml import load_batch_endpoint, load_online_endpoint
from azure.ai.ml._restclient.v2022_02_01_preview.models import EndpointAuthKeys as RestEndpointAuthKeys
from azure.ai.ml._restclient.v2022_02_01_preview.models import EndpointAuthToken as RestEndpointAuthToken
from azure.ai.ml._restclient.v2022_02_01_preview.models import OnlineEndpointData
from azure.ai.ml._restclient.v2023_10_01.models import BatchEndpoint as BatchEndpointData
from azure.ai.ml.entities import (
BatchEndpoint,
ManagedOnlineEndpoint,
KubernetesOnlineEndpoint,
OnlineEndpoint,
EndpointAuthKeys,
EndpointAuthToken,
KubernetesOnlineEndpoint,
ManagedOnlineEndpoint,
OnlineEndpoint,
)
from azure.ai.ml.exceptions import ValidationException

Expand Down Expand Up @@ -332,15 +332,12 @@ def test_dump(self) -> None:
assert online_endpoint_dict["identity"]["type"] == online_endpoint.identity.type
assert online_endpoint_dict["traffic"] == online_endpoint.traffic

@pytest.mark.skipif(
condition=sys.version_info >= (3, 13), reason="historical implementation doesn't support Python 3.13+"
)
def test_equality(self) -> None:
online_endpoint = load_online_endpoint(TestManagedOnlineEndpoint.ONLINE_ENDPOINT)
batch_online_endpoint = load_batch_endpoint(TestManagedOnlineEndpoint.BATCH_ENDPOINT_WITH_BLUE)

assert online_endpoint.__eq__(None)
assert online_endpoint.__eq__(batch_online_endpoint)
assert online_endpoint.__eq__(None) is NotImplemented
assert online_endpoint.__eq__(batch_online_endpoint) is NotImplemented

other_online_endpoint = copy.deepcopy(online_endpoint)
assert online_endpoint == other_online_endpoint
Expand Down
10 changes: 4 additions & 6 deletions sdk/ml/azure-ai-ml/tests/dataset/unittests/test_data_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys
from collections import OrderedDict
from pathlib import Path
from unittest.mock import Mock, patch
import sys

import pytest

Expand Down Expand Up @@ -97,10 +97,6 @@ def test_read_mltable_metadata_contents(
read_local_mltable_metadata_contents(path=mltable_folder / "should-fail")
assert "No such file or directory" in str(ex)

@pytest.mark.skipif(
sys.version_info >= (3, 13),
reason="Failing in spacific use case of TemporaryDirectory in Python 3.13 in test case only, skipping the test for now.",
)
@patch("azure.ai.ml._utils._data_utils.get_datastore_info")
@patch("azure.ai.ml._utils._data_utils.get_storage_client")
def test_read_remote_mltable_metadata_contents(
Expand All @@ -126,7 +122,9 @@ def test_read_remote_mltable_metadata_contents(
tmp_metadata_file.write_text(file_contents)

# remote azureml accessible
with patch("azure.ai.ml._utils._data_utils.TemporaryDirectory", return_value=mltable_folder):
with patch("azure.ai.ml._utils._data_utils.TemporaryDirectory") as mock_tmp:
mock_tmp.return_value.__enter__.return_value = str(mltable_folder)
mock_tmp.return_value.__exit__.return_value = None
contents = read_remote_mltable_metadata_contents(
datastore_operations=mock_datastore_operations,
base_uri="azureml://datastores/mydatastore/paths/images/dogs",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
import sys

import pytest

from azure.ai.ml._restclient.v2024_01_01_preview.models import MLFlowModelJobInput, UriFileJobInput
from azure.ai.ml.constants import DataGenerationTaskType, DataGenerationType
from azure.ai.ml.constants._common import AssetTypes
Expand All @@ -14,9 +15,6 @@
from azure.ai.ml.entities._workspace.connections.workspace_connection import WorkspaceConnection


@pytest.mark.skipif(
condition=sys.version_info >= (3, 13), reason="historical implementation doesn't support Python 3.13+"
)
class TestDistillationJobConversion:
@pytest.mark.parametrize(
"data_generation_task_type",
Expand Down
72 changes: 43 additions & 29 deletions sdk/ml/azure-ai-ml/tests/dsl/unittests/test_dsl_group.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import inspect
import sys
from enum import Enum as PyEnum
from io import StringIO
Expand Down Expand Up @@ -71,9 +72,6 @@ def test_restore_flattened_inputs(self) -> None:
assert isinstance(result.ab, _GroupAttrDict)
assert isinstance(result.ab.c, PipelineInput)

@pytest.mark.skipif(
condition=sys.version_info >= (3, 13), reason="historical implementation doesn't support Python 3.13+"
)
def test_auto_generated_functions(self) -> None:
class EnumOps(PyEnum):
Option1 = "Option1"
Expand All @@ -89,15 +87,27 @@ class MixedGroup:

# __init__ func test
assert hasattr(MixedGroup, "__init__") is True
original_out = sys.stdout
sys.stdout = stdout_str_IO = StringIO()
help(MixedGroup.__init__)
assert (
"__init__(self,*,int_param:int=None,str_param:str=None,enum_param:str=None,"
"str_default_param:str='test',optional_int_param:int=5)->None"
in remove_extra_character(stdout_str_IO.getvalue())
)
sys.stdout = original_out
sig = inspect.signature(MixedGroup.__init__)
params = sig.parameters

# Verify all expected parameters exist
assert "self" in params
assert "int_param" in params
assert "str_param" in params
assert "enum_param" in params
assert "str_default_param" in params
assert "optional_int_param" in params

# Verify default values
assert params["int_param"].default is None
assert params["str_param"].default is None
assert params["enum_param"].default is None
assert params["str_default_param"].default == "test"
assert params["optional_int_param"].default == 5

# Verify keyword-only parameters (after *)
assert params["int_param"].kind == inspect.Parameter.KEYWORD_ONLY
assert params["str_param"].kind == inspect.Parameter.KEYWORD_ONLY

# __repr__ func test
var = MixedGroup(
Expand Down Expand Up @@ -415,9 +425,6 @@ def my_pipeline(my_inputs: PortInputs):

assert "Only primitive types can be used as input of group, got uri_file" in str(e.value)

@pytest.mark.skipif(
condition=sys.version_info >= (3, 13), reason="historical implementation doesn't support Python 3.13+"
)
def test_group_defaults_with_outputs(self):
@group
class MixedGroup:
Expand All @@ -428,21 +435,28 @@ class MixedGroup:
optional_int_param: Input(type="integer", optional=True) = 5
output_folder: Output(type="uri_folder")

# __init__ func test
assert hasattr(MixedGroup, "__init__") is True
original_out = sys.stdout
sys.stdout = stdout_str_IO = StringIO()
help(MixedGroup.__init__)
assert (
"__init__(self,*,"
"int_param:int=None,"
"str_default_param:str='test',"
"str_param:str=None,"
"input_folder:{'type':'uri_folder'}=None,"
"optional_int_param:int=5,"
"output_folder:{'type':'uri_folder'}=None)"
"->None" in remove_extra_character(stdout_str_IO.getvalue())
)
sys.stdout = original_out
sig = inspect.signature(MixedGroup.__init__)
params = sig.parameters

# Verify all expected parameters exist
assert "int_param" in params
assert "str_default_param" in params
assert "str_param" in params
assert "input_folder" in params
assert "optional_int_param" in params
assert "output_folder" in params

# Verify default values
assert params["int_param"].default is None
assert params["str_default_param"].default == "test"
assert params["str_param"].default is None
assert params["optional_int_param"].default == 5
# input_folder and output_folder should have None as default
assert params["input_folder"].default is None
assert params["output_folder"].default is None

# __repr__ func test
var = MixedGroup(
int_param=1, str_param="test-str", input_folder=Input(path="input"), output_folder=Output(path="output")
Expand Down
Loading