{aimanager} Improve az aimanager list/show table output - #10322
{aimanager} Improve az aimanager list/show table output#10322Liqian Luo (circy9) wants to merge 16 commits into
az aimanager list/show table output#10322Conversation
Drop the `ETag` column and add `ProvisioningState` and `Subscription` columns to the `-o table` output for `az aimanager list` and `az aimanager show`, matching the information shown by peer commands such as `az aks list`. Fixes AB#39624822 Co-Authored-By: Claude <noreply@anthropic.com>
|
Hi Liqian Luo (@circy9), |
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
🟡 Changes recommended
The new table formatter can raise at runtime when properties is present but null, which would break -o table output for certain API responses.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR improves the default -o table output for az aimanager list and az aimanager show by replacing the implicit table projection (which exposed ETag) with explicit table transformers that surface more user-relevant fields like provisioning state and subscription.
Changes:
- Added
azext_aimanager/_format.pywith table transformer functions for single and list AI Manager results. - Wired the new table transformers into
aimanager showandaimanager listcommand registrations. - Added unit tests for the new table formatting and bumped the extension version + release notes.
File summaries
| File | Description |
|---|---|
| src/aimanager/setup.py | Bumps extension version to 1.5.3b1. |
| src/aimanager/HISTORY.rst | Documents the table output change in release notes. |
| src/aimanager/azext_aimanager/_format.py | Introduces explicit table formatters for AI Manager list/show. |
| src/aimanager/azext_aimanager/commands.py | Hooks the new formatters into the CLI commands. |
| src/aimanager/azext_aimanager/tests/latest/test_aimanager_format.py | Adds unit tests validating column selection and basic parsing. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Order as Name, ProvisioningState, ResourceGroup, Subscription, Location. Co-Authored-By: Claude <noreply@anthropic.com>
Guard against `properties` being present but null (Optional in the vendored model) so `-o table` does not raise AttributeError. Add a regression test for the null-properties case. Co-Authored-By: Claude <noreply@anthropic.com>
Subscription is constant within a single list call, so remove it. Table columns are now Name, ProvisioningState, ResourceGroup, Location. Co-Authored-By: Claude <noreply@anthropic.com>
Format `az aimanager namespace list` and `show` `-o table` output with Name, ProvisioningState, AIManager (parent, parsed from id) and ResourceGroup columns. Add unit tests. Co-Authored-By: Claude <noreply@anthropic.com>
Format `az aimanager namespace modeldeployment list` and `show` `-o table` output with Name, ProvisioningState, ModelId, Replicas (current/desired), Endpoint, Namespace, AIManager and ResourceGroup. ModelId is the human-readable model identifier: the custom list/show functions best-effort resolve the deployment's modelResourceId to the AIModel's properties.modelId; the formatter falls back to the AIModel resource name when resolution is unavailable. Co-Authored-By: Claude <noreply@anthropic.com>
Build the AIModel client once per list/show and cache lookups by (location, ai_model_name), so a namespace with many deployments that reference the same model incurs one GET per distinct model instead of one per deployment. Co-Authored-By: Claude <noreply@anthropic.com>
Namespace table: keep only Name and ProvisioningState. Modeldeployment table: drop AIManager and ResourceGroup, keeping Name, ProvisioningState, ModelId, Replicas, Endpoint and Namespace. Co-Authored-By: Claude <noreply@anthropic.com>
Render the Kubernetes namespace labels (properties.labels) as comma-joined key=value pairs, sorted for stable output, similar to kubectl get ns --show-labels. Co-Authored-By: Claude <noreply@anthropic.com>
Derive Age from systemData.createdAt and render it kubectl-style (e.g. 45d, 3h12m), placed just before Labels. Best-effort: blank when the timestamp is missing or unparseable. Co-Authored-By: Claude <noreply@anthropic.com>
Columns are now Namespace, Name, ProvisioningState, Replicas, Age, ModelId, Endpoint. Age is derived from systemData.createdAt. Co-Authored-By: Claude <noreply@anthropic.com>
Remove the unused eTag sample field and the redundant assertNotIn("ETag")
assertions; the exact key-list assertions already prove ETag is absent.
Co-Authored-By: Claude <noreply@anthropic.com>
Do not fall back to the raw AIModel resource name (not human-readable); leave the ModelId column blank when the human-readable id is unavailable. Co-Authored-By: Claude <noreply@anthropic.com>
|
Reviewed the PR and did some testing. This PR change doesn't break the existing functionality such as creating aimanager, namespace and model deployment. The only missing part is the "ModelId" doesn't show up. Testing result: |
thats cause there is no modelid column in azure-cli 2.76 and up, it returns blank. so custom.py:654 writes modelId onto the deployment object. That key isn't a declared field on ModelDeployment; it's declared on AIModel. The CLI converts the object to a dict before the transformer runs, and azure-cli changed that conversion in core 2.76.0 (commit 4254e5467, July 2025). New cores copy declared fields only, so the key is dropped and _format.py:104 reads nothing. |
|
would prob need to resolve the model or return a plain dicts from show/list instead |
The resolved modelId was injected as an extra attribute on the ModelDeployment SDK model, but azure-cli core 2.76+ copies only declared fields when converting a model for output, silently dropping it — so the ModelId column always rendered blank. Return plain dicts from list/show_modeldeployment with modelId set, so the value survives output conversion. Add regression tests covering the plain-dict result, per-model memoization, and blank-on-failure. Reported by @xmzhao0822; root cause diagnosed by @PugDeveloper. Co-Authored-By: Claude <noreply@anthropic.com>
|
Thanks Ximeng Zhao (@xmzhao0822) for testing and PugDeveloper for the precise root cause — that's exactly it.
Fixed in Could you re-test when you get a chance? The |
Adopt reviewer suggestion: convert deployments (and the resolved AIModel) with azure.cli.core.util.todict instead of dict(). todict recurses into nested objects, so properties/status become plain dicts too and the camelCase JSON keys the formatter reads are preserved. Co-Authored-By: Claude <noreply@anthropic.com>
reviewing |
|
Looks good to me. It can list/show the Model ID. |
Ximeng Zhao (xmzhao0822)
left a comment
There was a problem hiding this comment.
Approved
|
Hi Julie Zhu (@yanzhudd), Ethan Yang (@necusjz), this PR only update the format for show/list. Verified and tested, please help to merge, thanks. |
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). |
|
Please fix CI issues first. |

🤖 PR Validation — ️✔️ All clear
Related command
az aimanager list/show,az aimanager namespace list/show,az aimanager namespace modeldeployment list/showDescription
Improves the
-o tableoutput across theaz aimanagercommand surface. Previously the default table projection surfaced the internalETagcolumn while omitting useful status fields. This PR adds dedicated table transformers (azext_aimanager/_format.py) for each resource.az aimanager list/showaz aimanager namespace list/showaz aimanager namespace modeldeployment list/showNotes
ResourceGroup,Namespaceand parent info are parsed from the resourceidviaparse_resource_id, so a callable transformer is used rather than a JMESPath string.Ageis derived fromsystemData.createdAtand rendered kubectl-style (e.g.45d,3h12m); blank when the timestamp is missing or unparseable.Labels(namespace) renders the Kubernetes namespace labels (properties.labels) as sorted, comma-joinedkey=valuepairs, similar tokubectl get ns --show-labels.ModelIdis the human-readable model identifier (e.g.meta-llama/Llama-3-8B). The custommodeldeploymentlist/show functions best-effort resolve each deployment'smodelResourceIdto the AIModel'sproperties.modelId; AIModel lookups are memoized by(location, ai_model_name)so a namespace with many deployments referencing the same model incurs one GET per distinct model. When resolution fails the column is left blank (the raw AIModel resource name is not human-readable, so it is not used as a fallback).Replicasis renderedcurrent/desired, using-for counts not yet reported.properties/statusbeing present but null.Changes
azext_aimanager/_format.pywith table formatters for aimanager, namespace and modeldeployment.list/showcommands incommands.py.ModelIdincustom.py(_annotate_model_ids) with memoized AIModel lookups.test_aimanager_format.py).1.5.3b1and updateHISTORY.rst.General Guidelines
About Extension Publish
Only
setup.pyandHISTORY.rstversion info were updated;src/index.jsonis untouched.