Skip to content

Migrate 6 API versions to shared arm_ml_service client#47787

Open
saanikaguptamicrosoft wants to merge 134 commits into
Azure:mainfrom
saanikaguptamicrosoft:saanika/migrate_tsp_final
Open

Migrate 6 API versions to shared arm_ml_service client#47787
saanikaguptamicrosoft wants to merge 134 commits into
Azure:mainfrom
saanikaguptamicrosoft:saanika/migrate_tsp_final

Conversation

@saanikaguptamicrosoft

@saanikaguptamicrosoft saanikaguptamicrosoft commented Jul 1, 2026

Copy link
Copy Markdown
Member

Notes

  • Reuse the existing arm_ml_service generated client which is on stable version 2025-12-01, instead of importing from the per-version restclient package. Versions migrated-
    • 2020-09-01-dataplanepreview
    • 2021-10-01-dataplanepreview
    • 2023-04-01-preview
    • 2023-08-01-preview
    • 2024-01-01-preview
    • 2024-04-01-preview
  • Added smoke serialization tests which can be reused for future migration work also
  • Related PR (hotfix for a Sev2): Fix datastore create TypeError: serialize msrest body for the TypeSpec client #47944 (moved to a durable long-term fix as part of this migration)

Description

Please add an informative description that covers that changes made by the pull request and link all relevant issues.

If an SDK is being regenerated based on a new API spec, a link to the pull request containing these API spec changes should be included above.

All SDK Contribution checklist:

  • The pull request does not introduce [breaking changes]
  • CHANGELOG is updated for new features, bug fixes or other significant changes.
  • I have read the contribution guidelines.

General Guidelines and Best Practices

  • Title of the pull request is clear and informative.
  • There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, see this page.

Testing Guidelines

  • Pull request includes test coverage for the included changes.

…ression

DatastoreOperations.create_or_update was migrated to the arm_ml_service client
(which serializes the request body via json.dumps(body, cls=SdkJSONEncoder)) in
PR Azure#47554, but the datastore ENTITIES still returned v2023_04_01_preview msrest
Datastore models. SdkJSONEncoder can only serialize arm hybrid models, so every
datastore create/update raised:
    TypeError: Object of type Datastore is not JSON serializable

The bug was invisible to CI: unit tests mock the client (body never serialized),
the datastore create e2e tests are skip/live_test_only, and notebook samples reuse
the workspace default datastore instead of creating one.

Fix: migrate the datastore entities (Blob/File/ADLS Gen2/Gen1/OneLake) and the
shared datastore credentials to the arm_ml_service hybrid models so _to_rest_object()
serializes cleanly through the operation client's encoder.

Adds tests/datastore/unittests/test_datastore_serialization_regression.py: an
offline Class-A (mixed-tree) guard that serializes each datastore body via
SdkJSONEncoder exactly as the operation does.

Note: the experimental HDFS on-prem datastore (model absent in arm_ml_service)
is migrated separately via JSON-direct in the broader version migration.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a production serialization regression in azure-ai-ml datastores. In PR #47554, DatastoreOperations.create_or_update was migrated to the shared arm_ml_service generated client, whose operation serializes the request body via json.dumps(body, cls=SdkJSONEncoder, ...). However, the datastore entities still emitted v2023_04_01_preview msrest models, which SdkJSONEncoder cannot serialize, so every datastore create/update raised TypeError: Object of type Datastore is not JSON serializable. This PR migrates the datastore entities (Blob/File/ADLS Gen2/Gen1/OneLake) and the shared datastore credential conversions to the arm_ml_service hybrid models, and adds an offline regression test that serializes each datastore body exactly as the operation does.

Changes:

  • Repoint datastore entity/credential/schema REST imports from v2023_04_01_preview to arm_ml_service so _to_rest_object() produces an all-hybrid tree that serializes cleanly.
  • Add test_datastore_serialization_regression.py, an offline guard that runs each datastore body through SdkJSONEncoder.
  • Update test_datastore_schema.py assertions to expect arm_ml_service model types.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
entities/_credentials.py Move datastore credential/secret REST imports to arm_ml_service; surfaces a latent resource_uri vs resource_url mismatch for certificate creds (see comment).
entities/_datastore/datastore.py Base datastore Datastore/DatastoreType imports moved to arm_ml_service.
entities/_datastore/azure_storage.py Blob/File/ADLS Gen2 REST models moved to arm_ml_service.
entities/_datastore/adls_gen1.py ADLS Gen1 REST models moved to arm_ml_service.
entities/_datastore/one_lake.py OneLake REST models moved to arm_ml_service.
_schema/_datastore/one_lake.py DatastoreType/OneLakeArtifactType enums moved to arm_ml_service.
tests/datastore/unittests/test_datastore_serialization_regression.py New offline serialization regression guard (account-key & service-principal creds only).
tests/datastore/unittests/test_datastore_schema.py Assertions updated to expect arm_ml_service model types.

Additional notes (outside the PR diff, so not inline comments): the CHANGELOG.md "1.35.0 (unreleased) → Bugs Fixed" section is still empty; per the contribution checklist this bug fix should be documented there.

Comment thread sdk/ml/azure-ai-ml/azure/ai/ml/entities/_credentials.py Outdated
Addresses PR review: CertificateConfiguration._to_datastore_rest_object passed
resource_uri= to the arm_ml_service CertificateDatastoreCredentials model, but
that model's field is resource_url. The old msrest model silently ignored the
unknown resource_uri kwarg; the arm hybrid model raises
    TypeError: CertificateDatastoreCredentials.__init__() got an unexpected
    keyword argument 'resource_uri'
so every certificate-authenticated datastore (ADLS Gen1/Gen2) create/update
would crash - the same serialization-regression class this PR fixes.

Fix both the write (resource_url=self.resource_url) and read
(resource_url=obj.resource_url) paths, and extend the serialization regression
test to cover certificate credentials on ADLS Gen1 and Gen2 (the original test
only exercised account-key and service-principal creds).
Migrate the asset entities off the v2023_04_01_preview msrest models onto the
shared arm_ml_service hybrid client:
- Data / Model / Environment version models -> arm_ml_service.
- AutoDeleteSetting, IntellectualProperty, ModelConfiguration are absent from
  arm_ml_service (2025-12); serialize them JSON-direct (plain camelCase dict)
  and read them back via mapping access, per the reuse-existing-client approach.
- data.py: preserve the `autoDeleteSetting` wire field via mapping assignment
  (dropped from the arm model) and gate referenced_uris on the arm field set.
- environment.py: read intellectual_property defensively (arm dict or msrest),
  coerce is_anonymous default to False (arm hybrid defaults to None).
- component.py / pipeline_component.py: IntellectualProperty._to_rest_object now
  returns the wire dict directly, so drop the obsolete .serialize() call.

Validated: model, environment, dataset, model_package, component unit suites
(254 passed).
…024-01)

Migrate the entire AutoML entity surface (tabular, image, and NLP jobs plus
their settings/search-space models) off the per-version msrest restclients onto
the shared arm_ml_service hybrid client, using the proven to_hybrid_rest_model
boundary pattern for shared children (outputs/identity).

- Tabular: regression/classification/forecasting jobs + featurization/limit/
  training/forecasting settings, CustomTargetLags values->values_property,
  n_cross_validations/forecast-horizon discriminated children as wire dicts.
- Image: 4 image jobs + model/sweep/limit settings via the boundary pattern.
- NLP: text classification / multilabel / NER jobs; arm-absent NlpFixedParameters,
  NlpParameterSubspace, and NlpSweepSettings emitted JSON-direct; fixedParameters/
  searchSpace/sweepSettings/maxNodes carried as wire-keys; local NlpLearningRate
  scheduler + TrainingMode enums replace the arm-absent generated enums.

All 262 AutoML unit tests pass.
Flip the SweepJob envelope and its children to the shared arm_ml_service
hybrid model, wrapping each nested child (trial distribution/resources,
sampling_algorithm, limits, early_termination, objective, inputs, outputs,
identity, queue_settings, resources) through to_hybrid_rest_model so the
body serializes via the hybrid SdkJSONEncoder. Set is_archived=False and
attach the arm-dropped `resources` field via wire-key after construction.

- sampling_algorithm read path: arm hybrids are MutableMapping (not dict
  subclass), so read the arm-dropped `logbase` unknown wire key via
  _is_model/Mapping check instead of isinstance(obj, dict).
- Read path _load_from_rest updated for arm mapping access (resources,
  searchSpace).
- Tests: flip identity expected-models (AmlToken/ManagedIdentity/
  UserIdentity) to arm_ml_service; introspect arm-dropped logbase/resources
  via mapping access; DSL test_set_limits expects camelCase jobLimitsType
  from arm CommandJobLimits as_dict.

Sweep UTs (82) + sweep wire smoke (6) + full pipeline_job (200) + dsl +
command + job_common all green. Retires v2023_08 consumers: sweep_job,
objective, sampling_algorithm, SweepJobLimits.
…ml_service

Flip the three sweep leaf models off v2023_08_01_preview onto the shared
arm_ml_service hybrid models, now that the SweepJob envelope (and the
arm-aware DSL node serializer) consume them.

- objective.py: RestObjective -> arm.
- sampling_algorithm.py: Random/Grid/Bayesian/base + SamplingAlgorithmType
  -> arm. arm RandomSamplingAlgorithm dropped `logbase`; preserve it as an
  unknown wire key on the hybrid model in _to_rest_object (set only when
  present) and read via _is_model/Mapping in _from_rest_object.
- job_limits.py: SweepJobLimits RestSweepJobLimits -> arm (CommandJobLimits
  was already arm).

Validated: sweep UTs (82) + sweep wire smoke + command_job UTs (108 total),
full dsl + pipeline_job (490 passed, 2 skipped). Retires three more
v2023_08 consumers.
…arm_ml_service

Flip AzureOpenAiFineTuningJob and AzureOpenAiHyperparameters off
v2024_01_01_preview onto the shared arm_ml_service hybrid models, mirroring
the already-arm custom_model_finetuning_job.

- azure_openai_finetuning_job.py: RestFineTuningJob/AzureOpenAiFineTuning ->
  arm; drop the msrest _resolve_inputs/_restore_inputs overrides (the arm
  FineTuningVertical base already provides arm-correct versions); rewrite
  _to_rest_object to build the arm envelope like custom_model.
- azure_openai_hyperparameters.py: RestAzureOpenAiHyperParameters -> arm so
  the child serializes in the arm tree (fixes Class-A smoke crash where the
  msrest child couldn't serialize under the hybrid SdkJSONEncoder).
- test_finetuning_job_convesion.py: repoint Aoai* isinstance assertions to
  arm types; properties bool coerces to str "True" per arm Dict[str,str]
  wire contract (aligns with existing custom_model test).

Validated: finetuning UTs + full smoke_serialization (184 passed, incl
byte-identical aoai wire oracle). Finetuning family now fully off v2024_01
(only distillation_job.py remains on that version).
…_attribute_dict in pipeline e2e casing asserts
…_from_rest_object (handles arm response + snake dicts)
…'t OOM

test_mount_persistent patched build_data_asset_uri as a bare Mock. The migrated
mount() now JSON-encodes the uri into an HttpRequest body via SdkJSONEncoder,
which recurses unboundedly on a Mock -> OOM/SIGKILL in CI (Build Test 3.10).
Return a real str (production always returns str) so the body serializes.
…est doesn't OOM

Twin of the data mount fix: migrated DatastoreOperations.mount() JSON-encodes the
uri into an HttpRequest body; a bare Mock uri recurses in SdkJSONEncoder -> OOM.
Pre-empts the next Build Test 3.10 OOM (datastore sorts after dataset).
… wire

The arm_ml_service hybrid SdkJSONEncoder serializes present-but-None fields as explicit JSON null, whereas the msrest clients it replaced omitted them. On the local-run re-submit (which re-PUTs a previously fetched job), the round-tripped body carried 22 null keys never sent on the wire before, breaking test_command_job_local playback. Serialize + strip None recursively so the wire stays byte-identical.
The previous commit eagerly serialized every job create body, which crashed when the body contained an unresolved entity (e.g. an inline Environment) since the mocked/real client had not serialized it yet. Gate the serialize+strip-None behind strip_none_body, used only by the local-run re-submit whose body is a fully-resolved server response. Fresh creates pass the model unchanged as before.
Copilot AI review requested due to automatic review settings July 21, 2026 08:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…ire coverage

Extends the offline golden-wire smoke suite (baseline 48c329c, released 1.34.0) with: model_package and workspace-connection write-path wire equivalence; a branch-only deployment serialization guard (baseline can't serialize the pre-migration mixed tree offline); and a new read-path round-trip layer (entity->rest->entity->rest vs baseline) covering datastores, connections, computes, automl, sweep, workspace, registry, schedule. Documents two benign findings: ModelPackage now honors tags (latent bug-fix via dropping the PackageRequest base) and 4 arm-vs-msrest deserialization-default round-trip diffs.
Copilot AI review requested due to automatic review settings July 21, 2026 09:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@github-actions

Copy link
Copy Markdown
Contributor
[Pilot] PR Pipeline Failure Analysis

A CI pipeline failed on this pull request. Here is an automated analysis of what went wrong and how to get the build green.

What failed

The apistub check for azure-ai-ml failed in the Python CI pipeline. The apiview-stub-generator timed out after 120 seconds while attempting to install the azure_ai_ml-1.35.0 wheel via pip install inside an isolated virtual environment. This is an infrastructure / tooling timeout — not a code correctness issue in the PR.

Recommended next steps

  • Re-run the failed pipeline — this is a transient infrastructure timeout and is likely to pass on retry.
  • If the timeout recurs consistently, it may indicate the azure-ai-ml wheel or its transitive dependencies have grown large enough to exceed the 120-second install budget inside apiview-stub-generator. In that case, consider raising an issue against the azure-sdk-tools / apiview-stub-generator tooling to increase the subprocess timeout or investigate the slow installation.
  • See the CI troubleshooting guide: https://aka.ms/ci-fix
  • Push new commits to address the failures; this comment updates automatically on the next failing run.
Raw pipeline analysis (azsdk ci analyze)
### Pipeline: https://dev.azure.com/azure-sdk/public/_build/results?buildId=6593648

Failed task: apistub check for azure-ai-ml

Error:
  subprocess.TimeoutExpired: Command
    [python, -m, pip, install, azure_ai_ml-1.35.0-py3-none-any.whl, -q]
  timed out after 120 seconds.

  azure-ai-ml exited with error 1: apistub command returned non-zero exit status 1.
  apistub check completed with exit code 1

Summary:
  PACKAGE                             CHECK    STATUS   DURATION(s)
  sdk/ml/azure-ai-ml                  apistub  FAIL(1)  436.53
  Total checks: 1 | Failed: 1 | Worst exit code: 1

##[error] The process python failed with exit code 1

Copilot detected the failing pipeline and generated the analysis above. To have it attempt a fix automatically, reply with @copilot please fix the failing pipeline on this PR.

Generated by Pipeline Analysis - Next Steps · 32.8 AIC · ⌖ 6.12 AIC · ⊞ 6.6K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants