azureml-registry-tools 0.1.0a13__tar.gz → 0.1.0a15__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {azureml_registry_tools-0.1.0a13/azureml_registry_tools.egg-info → azureml_registry_tools-0.1.0a15}/PKG-INFO +2 -2
  2. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_cli/registry_syndication_cli.py +31 -50
  3. azureml_registry_tools-0.1.0a15/azureml/registry/data/description.md.template +2 -0
  4. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/evaluation.md.template +1 -2
  5. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/notes.md.template +2 -3
  6. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/mgmt/asset_management.py +58 -70
  7. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15/azureml_registry_tools.egg-info}/PKG-INFO +2 -2
  8. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml_registry_tools.egg-info/SOURCES.txt +0 -1
  9. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml_registry_tools.egg-info/requires.txt +1 -1
  10. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/setup.py +2 -2
  11. azureml_registry_tools-0.1.0a13/azureml/registry/data/description.md.template +0 -3
  12. azureml_registry_tools-0.1.0a13/azureml/registry/mgmt/registry_config.py +0 -147
  13. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/LICENSE.txt +0 -0
  14. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/MANIFEST.in +0 -0
  15. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/__init__.py +0 -0
  16. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/__init__.py +0 -0
  17. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_cli/__init__.py +0 -0
  18. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_cli/repo2registry_cli.py +0 -0
  19. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_rest_client/__init__.py +0 -0
  20. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_rest_client/arm_client.py +0 -0
  21. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_rest_client/base_rest_client.py +0 -0
  22. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_rest_client/registry_management_client.py +0 -0
  23. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/_rest_client/registry_model_client.py +0 -0
  24. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/__init__.py +0 -0
  25. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/asset.yaml.template +0 -0
  26. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/model-variant.schema.json +0 -0
  27. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/model.schema.json +0 -0
  28. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/model.yaml.template +0 -0
  29. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/validate_model_schema.py +0 -0
  30. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/data/validate_model_variant_schema.py +0 -0
  31. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/mgmt/__init__.py +0 -0
  32. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/mgmt/create_asset_template.py +0 -0
  33. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/mgmt/create_manifest.py +0 -0
  34. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/mgmt/create_model_spec.py +0 -0
  35. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/mgmt/model_management.py +0 -0
  36. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/mgmt/syndication_manifest.py +0 -0
  37. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/tools/__init__.py +0 -0
  38. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/tools/config.py +0 -0
  39. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/tools/create_or_update_assets.py +0 -0
  40. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/tools/registry_utils.py +0 -0
  41. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml/registry/tools/repo2registry_config.py +0 -0
  42. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml_registry_tools.egg-info/dependency_links.txt +0 -0
  43. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml_registry_tools.egg-info/entry_points.txt +0 -0
  44. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/azureml_registry_tools.egg-info/top_level.txt +0 -0
  45. {azureml_registry_tools-0.1.0a13 → azureml_registry_tools-0.1.0a15}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: azureml-registry-tools
3
- Version: 0.1.0a13
3
+ Version: 0.1.0a15
4
4
  Summary: AzureML Registry tools and CLI
5
5
  Author: Microsoft Corp
6
6
  License: https://aka.ms/azureml-sdk-license
@@ -10,7 +10,7 @@ Requires-Dist: azure-identity<2.0
10
10
  Requires-Dist: ruamel-yaml<0.19,>=0.17.21
11
11
  Requires-Dist: diskcache~=5.6
12
12
  Requires-Dist: azure-ai-ml<2.0
13
- Requires-Dist: azureml-assets<=1.16.86
13
+ Requires-Dist: azureml-assets<2.0
14
14
  Dynamic: author
15
15
  Dynamic: license
16
16
  Dynamic: license-file
@@ -15,7 +15,6 @@ from azureml.registry.mgmt.create_manifest import generate_syndication_manifest
15
15
  from azureml.registry.mgmt.model_management import (
16
16
  model_delete, model_get, model_list, parse_asset_id
17
17
  )
18
- from azureml.registry.mgmt.registry_config import create_registry_config
19
18
  from azureml.registry.mgmt.syndication_manifest import ResyncAssetsInManifestDto, SyndicationManifest
20
19
 
21
20
 
@@ -141,14 +140,6 @@ def show_command(registry_name: str, as_arm_object: bool) -> object:
141
140
  return discovery
142
141
 
143
142
 
144
- def validate_registry_cfg(cfg_file_name) -> str:
145
- """Validate if registry config extension is .cfg."""
146
- cfg_file_path = Path(cfg_file_name)
147
- if not cfg_file_path.suffix == ".cfg":
148
- raise argparse.ArgumentTypeError(f"--config arg {cfg_file_name} must be a path to a .cfg file")
149
- return cfg_file_path
150
-
151
-
152
143
  def _add_common_args(p, arg_dicts=None):
153
144
  if arg_dicts is None:
154
145
  arg_dicts = []
@@ -187,14 +178,11 @@ def main() -> None:
187
178
  # Validate an asset
188
179
  registry-mgmt asset validate --asset-path ./path-to-asset
189
180
 
190
- # Deploy an asset to registry (using config file)
191
- registry-mgmt asset deploy --asset-path ./path-to-asset --config ./registry-mgmt.cfg
181
+ # Preview an asset to registry
182
+ registry-mgmt asset preview --asset-path ./path-to-asset --registry-name myreg --subscription sub123 --resource-group rg123
192
183
 
193
- # Create registry configuration file
194
- registry-mgmt asset config --registry-name myreg --subscription sub123 --resource-group rg123 --tenant-id tenant123
195
-
196
- # Create registry configuration file with storage overrides
197
- registry-mgmt asset config --registry-name myreg --subscription sub123 --resource-group rg123 --tenant-id tenant123 --storage-name storage123 --container-name container123 --container-path path123
184
+ # Deploy an asset to registry
185
+ registry-mgmt asset deploy --asset-path ./path-to-asset --registry-name myreg --subscription sub123 --resource-group rg123
198
186
 
199
187
  # Create asset template files
200
188
  registry-mgmt asset template --folder ./folder-path
@@ -352,21 +340,19 @@ def main() -> None:
352
340
  asset_validate_parser.add_argument("--asset-path", type=Path, help="Path to the asset folder to validate.")
353
341
  asset_validate_parser.add_argument("--allow-additional-properties", action="store_true",
354
342
  help="Allow additional properties not defined in the schema")
343
+ # asset preview command
344
+ asset_preview_parser = asset_subparsers.add_parser("preview", help="Preview a model card to registry.")
345
+ _add_common_args(asset_preview_parser, [registry_name_arg, subscription_arg, resource_group_arg, dry_run_arg])
346
+ asset_preview_parser.add_argument("--asset-path", type=Path, help="Path to the asset folder to preview.")
347
+ asset_preview_parser.add_argument("--allow-additional-properties", action="store_true",
348
+ help="Allow additional properties not defined in the schema")
355
349
 
356
350
  # asset deploy command
357
- asset_deploy_parser = asset_subparsers.add_parser("deploy", help="Deploy an asset to registry.")
358
- _add_common_args(asset_deploy_parser, [dry_run_arg])
359
- asset_deploy_parser.add_argument("-c", "--config", type=validate_registry_cfg, required=True, help="Path to registry config file.")
351
+ asset_deploy_parser = asset_subparsers.add_parser("deploy", help="Deploy a model to registry.")
352
+ _add_common_args(asset_deploy_parser, [registry_name_arg, subscription_arg, resource_group_arg, dry_run_arg])
360
353
  asset_deploy_parser.add_argument("--asset-path", type=Path, help="Path to the asset folder to deploy.")
361
-
362
- # asset config command
363
- asset_config_parser = asset_subparsers.add_parser("config", help="Create registry configuration file.")
364
- _add_common_args(asset_config_parser, [registry_name_arg, subscription_arg, resource_group_arg])
365
- asset_config_parser.add_argument("--tenant-id", type=str, required=True, help="Registry Tenant ID.")
366
- asset_config_parser.add_argument("-c", "--config-file", type=validate_registry_cfg, help="Registry config file path to write to (default: registry-mgmt.cfg).")
367
- asset_config_parser.add_argument("--storage-name", type=str, help="Storage account name for storage overrides.")
368
- asset_config_parser.add_argument("--container-name", type=str, help="Container name for storage overrides.")
369
- asset_config_parser.add_argument("--container-path", type=str, help="Container path for storage overrides.")
354
+ asset_deploy_parser.add_argument("--allow-additional-properties", action="store_true",
355
+ help="Allow additional properties not defined in the schema")
370
356
 
371
357
  # asset template command
372
358
  asset_template_parser = asset_subparsers.add_parser("template", help="Create asset template files.")
@@ -448,27 +434,23 @@ def main() -> None:
448
434
  syndication_target_set(args.registry_name, args.value, args.dry_run)
449
435
  elif args.command == "asset":
450
436
  if args.asset_subcommand == "validate":
451
- # Config file is not needed for validation
452
437
  asset_validate(args.asset_path, args.dry_run, args.allow_additional_properties)
438
+ elif args.asset_subcommand == "preview":
439
+ asset_deploy(asset_path=args.asset_path,
440
+ registry_name=args.registry_name,
441
+ subscription_id=args.subscription,
442
+ resource_group=args.resource_group,
443
+ dry_run=args.dry_run,
444
+ allow_additional_properties=args.allow_additional_properties,
445
+ override_storage=True)
453
446
  elif args.asset_subcommand == "deploy":
454
- # Config file is required for deployment
455
- asset_deploy(args.asset_path, args.config, args.dry_run)
456
- elif args.asset_subcommand == "config":
457
- # Validate storage parameters - all or none must be provided
458
- storage_args = [args.storage_name, args.container_name, args.container_path]
459
- if any(storage_args) and not all(storage_args):
460
- parser.error("When using storage overrides, --storage-name, --container-name, and --container-path are all required.")
461
-
462
- create_registry_config(
463
- registry_name=args.registry_name,
464
- subscription_id=args.subscription,
465
- resource_group=args.resource_group,
466
- tenant_id=args.tenant_id,
467
- config_file_path=args.config_file,
468
- storage_name=args.storage_name,
469
- container_name=args.container_name,
470
- container_path=args.container_path
471
- )
447
+ asset_deploy(asset_path=args.asset_path,
448
+ registry_name=args.registry_name,
449
+ subscription_id=args.subscription,
450
+ resource_group=args.resource_group,
451
+ dry_run=args.dry_run,
452
+ allow_additional_properties=args.allow_additional_properties,
453
+ override_storage=False)
472
454
  elif args.asset_subcommand == "template":
473
455
  # Create asset template files
474
456
  asset_template(args.folder, args.dry_run)
@@ -516,8 +498,7 @@ def main() -> None:
516
498
  if not registry_name or not model_name or not version:
517
499
  print("Error: Registry name, model name, and version must be provided", file=sys.stderr)
518
500
  sys.exit(1)
519
-
520
- # Single call to model_get with args values directly
501
+ # Get model
521
502
  print(model_get(
522
503
  registry_name=registry_name,
523
504
  name=model_name,
@@ -553,7 +534,7 @@ def main() -> None:
553
534
  print("Error: Registry name and model name must be provided", file=sys.stderr)
554
535
  sys.exit(1)
555
536
 
556
- # Single call to model_delete with args values directly
537
+ # Delete model
557
538
  model_delete(
558
539
  registry_name=registry_name,
559
540
  name=model_name,
@@ -0,0 +1,2 @@
1
+ <!-- REMOVE THESE HEADERS AFTER UPDATING -->
2
+ <!-- `description.md` is required. -->
@@ -1,3 +1,2 @@
1
- <!-- DO NOT CHANGE MARKDOWN HEADERS. IF CHANGED, MODEL CARD MAY BE REJECTED BY A REVIEWER -->
2
-
1
+ <!-- REMOVE THESE HEADERS AFTER UPDATING -->
3
2
  <!-- `evaluation.md` is highly recommended, but not required. It captures information about the performance of the model. We highly recommend including this section as this information is often used to decide what model to use. -->
@@ -1,3 +1,2 @@
1
- <!-- DO NOT CHANGE MARKDOWN HEADERS. IF CHANGED, MODEL CARD MAY BE REJECTED BY A REVIEWER -->
2
-
3
- <!-- `notes.md` is highly recommended, but not required. It captures information about how your model is created. We highly recommend including this section to provide transparency for the customers. -->
1
+ <!-- REMOVE THESE HEADERS AFTER UPDATING -->
2
+ <!-- `notes.md` is highly recommended, but not required. It captures information about how your model is created. We highly recommend including this section to provide transparency for the customers. -->
@@ -7,7 +7,7 @@ import sys
7
7
  import shutil
8
8
  import tempfile
9
9
  import yaml
10
- from datetime import datetime, timedelta
10
+ from datetime import datetime
11
11
  from pathlib import Path
12
12
  from typing import List
13
13
 
@@ -16,7 +16,6 @@ from azure.identity import DefaultAzureCredential
16
16
 
17
17
  from azureml.registry.data.validate_model_schema import validate_model_schema
18
18
  from azureml.registry.data.validate_model_variant_schema import validate_model_variant_schema
19
- from azureml.registry.mgmt.registry_config import RegistryConfig
20
19
 
21
20
  # Windows compatibility patch - must be applied before importing azureml.assets
22
21
  from subprocess import run
@@ -34,7 +33,7 @@ publish_utils.run_command = patched_run_command
34
33
 
35
34
  import azureml.assets as assets # noqa: E402
36
35
  import azureml.assets.util as util # noqa: E402
37
- from azureml.assets.config import AssetConfig, AssetType, AzureBlobstoreAssetPath # noqa: E402
36
+ from azureml.assets.config import AssetConfig, AssetType # noqa: E402
38
37
  from azureml.assets.publish_utils import create_asset # noqa: E402
39
38
  from azureml.assets.validate_assets import validate_assets # noqa: E402
40
39
 
@@ -88,34 +87,13 @@ def validate_model(asset_path: Path, allow_additional_properties: bool = False)
88
87
  return True
89
88
 
90
89
 
91
- def set_storage_and_sas(asset: AssetConfig, storage_config: dict):
92
- """Use storage configuration and generate/set SAS token.
93
-
94
- Args:
95
- asset (AssetConfig): Asset configuration object to modify
96
- storage_config (dict): Storage configuration dictionary
97
- """
98
- if not storage_config:
99
- # No storage overrides provided, skip storage configuration
100
- return
101
-
102
- print("Overriding storage configuration with provided values...")
103
- extra_config = asset.extra_config_as_object()
104
- extra_config._path = AzureBlobstoreAssetPath(
105
- storage_name=storage_config["storage_name"],
106
- container_name=storage_config["container_name"],
107
- container_path=storage_config["container_path"]
108
- )
109
- _ = extra_config.path.get_uri(token_expiration=timedelta(hours=1))
110
-
111
-
112
- def build_mutable_asset(base_asset: AssetConfig, mutable_asset_dir: str, storage_overrides_exist: bool = False) -> AssetConfig:
90
+ def build_mutable_asset(base_asset: AssetConfig, mutable_asset_dir: str, override_storage: bool = False) -> AssetConfig:
113
91
  """Build a mutable copy of the asset in a temporary directory.
114
92
 
115
93
  Args:
116
94
  base_asset (AssetConfig): Base asset configuration to copy
117
95
  mutable_asset_dir (str): Directory path for the mutable asset copy
118
- storage_overrides_exist (bool, optional): If True, model config will be modified to set type to custom_model.
96
+ override_storage (bool, optional): If True, model config will be modified to reference a local temp file.
119
97
 
120
98
  Returns:
121
99
  AssetConfig: Mutable asset configuration object
@@ -136,63 +114,75 @@ def build_mutable_asset(base_asset: AssetConfig, mutable_asset_dir: str, storage
136
114
  spec_config_file = mutable_asset_dir / base_spec_file.relative_to(common_dir)
137
115
  model_config_file = mutable_asset_dir / base_model_file.relative_to(common_dir)
138
116
 
139
- # Autoincrement version for mutable asset
140
- with open(spec_config_file, "r") as f:
141
- spec_config = yaml.safe_load(f)
142
- spec_config["version"] = datetime.now().strftime("%Y%m%d%H%M%S")
143
-
144
- with open(spec_config_file, "w") as f:
145
- yaml.dump(spec_config, f)
146
-
147
- # If storage overrides are provided, default set model type to custom_model
148
- if storage_overrides_exist:
149
- print("Storage overrides provided, default setting model type to custom_model")
150
- with open(model_config_file, "r") as f:
151
- model_config = yaml.safe_load(f)
152
- model_config["publish"]["type"] = "custom_model"
153
-
117
+ # Override storage info for model card preview
118
+ if override_storage:
119
+ print("Model card preview - Default setting version and storage info")
120
+
121
+ # Autoincrement version for mutable asset
122
+ with open(spec_config_file, "r") as f:
123
+ spec_config = yaml.safe_load(f)
124
+ spec_config["version"] = datetime.now().strftime("%Y%m%d%H%M%S")
125
+
126
+ with open(spec_config_file, "w") as f:
127
+ yaml.dump(spec_config, f)
128
+
129
+ # Create dummy file to upload to storage
130
+ with open(mutable_asset_dir / "dummy.txt", "w") as f:
131
+ f.write("This is a dummy file used in the artifact for model card preview.")
132
+
133
+ yaml_content = """
134
+ path:
135
+ uri: ./dummy.txt
136
+ type: local
137
+ publish:
138
+ description: description.md
139
+ type: custom_model
140
+ """
141
+ new_model_config = yaml.safe_load(yaml_content)
142
+
143
+ # Overwrite model config
154
144
  with open(model_config_file, "w") as f:
155
- yaml.dump(model_config, f)
145
+ yaml.dump(new_model_config, f)
156
146
 
157
147
  mutable_asset = AssetConfig(asset_config_file)
158
148
 
159
149
  return mutable_asset
160
150
 
161
151
 
162
- def create_or_update_asset(readonly_asset: AssetConfig, config: RegistryConfig):
152
+ def create_or_update_asset(readonly_asset: AssetConfig, registry_name: str, subscription_id: str, resource_group: str, override_storage: bool = False):
163
153
  """Create or update an asset in the AzureML registry.
164
154
 
165
155
  Args:
166
156
  readonly_asset (AssetConfig): Asset configuration to create or update
167
- config (RegistryConfig): Registry configuration settings
157
+ registry_name (str): Name of AzureML registry to deploy to
158
+ subscription_id (str): Subscription ID of AzureML registry to deploy to
159
+ resource_group (str): Resource group of AzureML registry to deploy to
160
+ override_storage (bool): Whether to override storage settings
168
161
  """
169
162
  print("[CREATING/UPDATING ASSET]")
170
- print(f"Using registry configuration from: {config.config_path}")
163
+ print(f"Registry name: {registry_name}, Subscription ID: {subscription_id}, Resource group: {resource_group}")
164
+
171
165
  # Create ML client
172
166
  ml_client = MLClient(
173
- subscription_id=config.subscription_id,
174
- resource_group_name=config.resource_group,
175
- registry_name=config.registry_name,
167
+ subscription_id=subscription_id,
168
+ resource_group_name=resource_group,
169
+ registry_name=registry_name,
176
170
  credential=DefaultAzureCredential(),
177
171
  )
178
172
 
179
173
  with tempfile.TemporaryDirectory() as mutable_asset_dir:
180
- mutable_asset = build_mutable_asset(base_asset=readonly_asset, mutable_asset_dir=mutable_asset_dir, storage_overrides_exist=bool(config.storage_config))
181
- # autoincrement version
174
+ mutable_asset = build_mutable_asset(base_asset=readonly_asset, mutable_asset_dir=mutable_asset_dir, override_storage=override_storage)
182
175
  try:
183
- set_storage_and_sas(mutable_asset, config.storage_config)
184
- success = create_asset(mutable_asset, config.registry_name, ml_client)
176
+ success = create_asset(mutable_asset, registry_name, ml_client)
177
+ if not success:
178
+ raise RuntimeError(f"Failed to create/update asset: create_asset 'success' returned {success}")
185
179
  except Exception as e:
186
180
  print(f"Failed to create/update asset: {e}")
187
181
  raise
188
182
 
189
- if not success:
190
- print(f"Failed to create/update asset: create_asset 'success' returned {success}")
191
- raise
192
-
193
183
  print("\n[VALIDATE YOUR ASSET IN THE UI HERE]")
194
- print(f" - Model Catalog link: https://ai.azure.com/explore/models/{mutable_asset.name}/version/{mutable_asset.version}/registry/{config.registry_name}?tid={config.tenant_id}")
195
- print(f" - Azure Portal link: https://ml.azure.com/registries/{config.registry_name}/models/{mutable_asset.name}/version/{mutable_asset.version}?tid={config.tenant_id}")
184
+ print(f" - Model Catalog link: https://ai.azure.com/explore/models/{mutable_asset.name}/version/{mutable_asset.version}/registry/{registry_name}")
185
+ print(f" - Azure Portal link: https://ml.azure.com/registries/{registry_name}/models/{mutable_asset.name}/version/{mutable_asset.version}")
196
186
 
197
187
 
198
188
  def asset_validate(asset_path: Path, dry_run: bool = False, allow_additional_properties: bool = False) -> bool:
@@ -237,31 +227,29 @@ def asset_validate(asset_path: Path, dry_run: bool = False, allow_additional_pro
237
227
  return validate_model(readonly_asset.file_path, allow_additional_properties)
238
228
 
239
229
 
240
- def asset_deploy(asset_path: Path, config_path: Path, dry_run: bool = False) -> bool:
241
- """Deploy an asset using configuration file.
230
+ def asset_deploy(asset_path: Path, registry_name: str, subscription_id: str, resource_group: str, dry_run: bool = False, allow_additional_properties: bool = False, override_storage: bool = False) -> bool:
231
+ """Deploy an asset to a registry.
242
232
 
243
233
  Args:
244
234
  asset_path (Path): Path to the asset folder to deploy
245
- config_path (Path): Path to configuration file
246
235
  dry_run (bool): If True, perform a dry run without deploying
236
+ allow_additional_properties (bool): Whether to allow additional properties not defined in schema
237
+ override_storage (bool): Whether to override storage settings
247
238
 
248
239
  Returns:
249
240
  bool: True if deployment succeeds, False otherwise
250
241
  """
251
- try:
252
- config = RegistryConfig(config_path)
253
- except Exception as e:
254
- print(f"❌ [ERROR]: Configuration validation failed: {e}")
255
- return False
256
-
257
242
  if dry_run:
258
- print(f"[DRY RUN] Would deploy asset at {asset_path} to registry {config.registry_name}")
243
+ if override_storage:
244
+ print(f"[DRY RUN] Would preview asset at {asset_path} to registry {registry_name}")
245
+ else:
246
+ print(f"[DRY RUN] Would deploy asset at {asset_path} to registry {registry_name}")
259
247
  return True
260
248
 
261
249
  asset_path = asset_path.resolve()
262
250
 
263
251
  # Validate asset before deployment
264
- if not asset_validate(asset_path, dry_run=False):
252
+ if not asset_validate(asset_path, dry_run=False, allow_additional_properties=allow_additional_properties):
265
253
  print("❌ [ERROR]: Asset validation failed. Asset deployment aborted.")
266
254
  return False
267
255
 
@@ -269,7 +257,7 @@ def asset_deploy(asset_path: Path, config_path: Path, dry_run: bool = False) ->
269
257
  readonly_asset = assets.AssetConfig(asset_path / assets.DEFAULT_ASSET_FILENAME)
270
258
 
271
259
  try:
272
- create_or_update_asset(readonly_asset, config)
260
+ create_or_update_asset(readonly_asset, registry_name, subscription_id, resource_group, override_storage)
273
261
  return True
274
262
  except Exception as e:
275
263
  print(f"❌ [ERROR]: Failed to deploy asset: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: azureml-registry-tools
3
- Version: 0.1.0a13
3
+ Version: 0.1.0a15
4
4
  Summary: AzureML Registry tools and CLI
5
5
  Author: Microsoft Corp
6
6
  License: https://aka.ms/azureml-sdk-license
@@ -10,7 +10,7 @@ Requires-Dist: azure-identity<2.0
10
10
  Requires-Dist: ruamel-yaml<0.19,>=0.17.21
11
11
  Requires-Dist: diskcache~=5.6
12
12
  Requires-Dist: azure-ai-ml<2.0
13
- Requires-Dist: azureml-assets<=1.16.86
13
+ Requires-Dist: azureml-assets<2.0
14
14
  Dynamic: author
15
15
  Dynamic: license
16
16
  Dynamic: license-file
@@ -28,7 +28,6 @@ azureml/registry/mgmt/create_asset_template.py
28
28
  azureml/registry/mgmt/create_manifest.py
29
29
  azureml/registry/mgmt/create_model_spec.py
30
30
  azureml/registry/mgmt/model_management.py
31
- azureml/registry/mgmt/registry_config.py
32
31
  azureml/registry/mgmt/syndication_manifest.py
33
32
  azureml/registry/tools/__init__.py
34
33
  azureml/registry/tools/config.py
@@ -2,4 +2,4 @@ azure-identity<2.0
2
2
  ruamel-yaml<0.19,>=0.17.21
3
3
  diskcache~=5.6
4
4
  azure-ai-ml<2.0
5
- azureml-assets<=1.16.86
5
+ azureml-assets<2.0
@@ -11,14 +11,14 @@ DEPENDENCIES = [
11
11
  "ruamel-yaml>=0.17.21,<0.19",
12
12
  "diskcache~=5.6",
13
13
  "azure-ai-ml<2.0",
14
- "azureml-assets<=1.16.86"
14
+ "azureml-assets<2.0"
15
15
  ]
16
16
 
17
17
  exclude_list = ["*.tests"]
18
18
 
19
19
  setup(
20
20
  name='azureml-registry-tools',
21
- version="0.1.0a13",
21
+ version="0.1.0a15",
22
22
  description='AzureML Registry tools and CLI',
23
23
  author='Microsoft Corp',
24
24
  license="https://aka.ms/azureml-sdk-license",
@@ -1,3 +0,0 @@
1
- <!-- DO NOT CHANGE MARKDOWN HEADERS. IF CHANGED, MODEL CARD MAY BE REJECTED BY A REVIEWER -->
2
-
3
- <!-- `description.md` is required. -->
@@ -1,147 +0,0 @@
1
- # ---------------------------------------------------------
2
- # Copyright (c) Microsoft Corporation. All rights reserved.
3
- # ---------------------------------------------------------
4
-
5
- """RegistryConfig class."""
6
-
7
- import configparser
8
- from pathlib import Path
9
- from typing import Dict
10
-
11
-
12
- class RegistryConfig:
13
- """RegistryConfig class."""
14
-
15
- def __init__(self, config_path: Path = None):
16
- """Registry config init.
17
-
18
- Args:
19
- config_path (Path, optional): Path to configuration file. Defaults to "registry-mgmt.cfg".
20
- """
21
- if config_path is None:
22
- print("No config path provided, using default 'registry-mgmt.cfg'.")
23
- config_path = Path("registry-mgmt.cfg")
24
- self.config_path = config_path
25
- if not self.config_path.is_file():
26
- raise FileNotFoundError(f"File '{self.config_path.resolve().as_posix()}' does not exist.")
27
-
28
- self.config = configparser.ConfigParser()
29
- self.config.read(self.config_path)
30
- self._validate_schema()
31
-
32
- def _validate_schema(self) -> None:
33
- """Validate registry config schema."""
34
- config_file_name = str(self.config_path)
35
-
36
- if not self.config.has_section("registry"):
37
- raise Exception(f'"registry" section not found in config file {config_file_name}')
38
-
39
- # Validate registry section
40
- if not self.config.has_option("registry", "registry_name"):
41
- raise Exception(f'Key "registry_name" not found under "registry" section in config file {config_file_name}')
42
- if not self.config.has_option("registry", "tenant_id"):
43
- raise Exception(f'Key "tenant_id" not found under "registry" section in config file {config_file_name}')
44
- if not self.config.has_option("registry", "subscription_id"):
45
- raise Exception(f'Key "subscription_id" not found under "registry" section in config file {config_file_name}')
46
- if not self.config.has_option("registry", "resource_group"):
47
- raise Exception(f'Key "resource_group" not found under "registry" section in config file {config_file_name}')
48
-
49
- # Validate that values are not empty
50
- required_settings = ["registry_name", "tenant_id", "subscription_id", "resource_group"]
51
- for setting in required_settings:
52
- if not self.config.get("registry", setting).strip():
53
- raise Exception(f'Value for "{setting}" is empty in "registry" section in config file {config_file_name}')
54
-
55
- # Validate storage_overrides section (optional, but if present, validate its contents)
56
- if self.config.has_section("storage_overrides"):
57
- allowed_storage_keys = {"storage_name", "container_name", "container_path"}
58
- actual_storage_keys = set(self.config.options("storage_overrides"))
59
-
60
- # Check for unexpected keys
61
- unexpected_keys = actual_storage_keys - allowed_storage_keys
62
- if unexpected_keys:
63
- raise Exception(f'Unexpected keys {sorted(unexpected_keys)} found in "storage_overrides" section in config file {config_file_name}. Only {sorted(allowed_storage_keys)} are allowed.')
64
-
65
- # Check for required keys
66
- if not self.config.has_option("storage_overrides", "storage_name"):
67
- raise Exception(f'Key "storage_name" not found under "storage_overrides" section in config file {config_file_name}')
68
- if not self.config.has_option("storage_overrides", "container_name"):
69
- raise Exception(f'Key "container_name" not found under "storage_overrides" section in config file {config_file_name}')
70
- if not self.config.has_option("storage_overrides", "container_path"):
71
- raise Exception(f'Key "container_path" not found under "storage_overrides" section in config file {config_file_name}')
72
-
73
- # Validate that storage values are not empty
74
- required_storage_settings = ["storage_name", "container_name", "container_path"]
75
- for setting in required_storage_settings:
76
- if not self.config.get("storage_overrides", setting).strip():
77
- raise Exception(f'Value for "{setting}" is empty in "storage_overrides" section in config file {config_file_name}')
78
-
79
- @property
80
- def registry_name(self) -> str:
81
- """Get registry name from config."""
82
- return self.config.get("registry", "registry_name")
83
-
84
- @property
85
- def tenant_id(self) -> str:
86
- """Get tenant ID from config."""
87
- return self.config.get("registry", "tenant_id")
88
-
89
- @property
90
- def subscription_id(self) -> str:
91
- """Get subscription ID from config."""
92
- return self.config.get("registry", "subscription_id")
93
-
94
- @property
95
- def resource_group(self) -> str:
96
- """Get resource group from config."""
97
- return self.config.get("registry", "resource_group")
98
-
99
- @property
100
- def storage_config(self) -> Dict[str, str]:
101
- """Get storage configuration."""
102
- if self.config.has_section("storage_overrides"):
103
- return dict(self.config["storage_overrides"])
104
- return {}
105
-
106
-
107
- def create_registry_config(registry_name: str, subscription_id: str, resource_group: str, tenant_id: str,
108
- config_file_path: Path, storage_name: str = None, container_name: str = None,
109
- container_path: str = None):
110
- """Create registry config.
111
-
112
- Args:
113
- registry_name (str): Registry name.
114
- subscription_id (str): Registry subscription id.
115
- resource_group (str): Registry resource group.
116
- tenant_id (str): Tenant ID.
117
- config_file_path (Path): Path to config file.
118
- storage_name (str, optional): Storage account name for storage overrides. Defaults to None.
119
- container_name (str, optional): Container name for storage overrides. Defaults to None.
120
- container_path (str, optional): Container path for storage overrides. Defaults to None.
121
- """
122
- print("Creating registry config...")
123
-
124
- registry_config = configparser.ConfigParser()
125
- registry_config.add_section("registry")
126
- registry_config.set("registry", "registry_name", registry_name)
127
- registry_config.set("registry", "subscription_id", subscription_id)
128
- registry_config.set("registry", "resource_group", resource_group)
129
- registry_config.set("registry", "tenant_id", tenant_id)
130
-
131
- # Add storage overrides if provided
132
- if storage_name and container_name and container_path:
133
- registry_config.add_section("storage_overrides")
134
- registry_config.set("storage_overrides", "storage_name", storage_name)
135
- registry_config.set("storage_overrides", "container_name", container_name)
136
- registry_config.set("storage_overrides", "container_path", container_path)
137
-
138
- # Write to path
139
- if config_file_path is None:
140
- print('No config file path provided, using default "registry-mgmt.cfg"')
141
- config_file_path = Path("registry-mgmt.cfg")
142
- with open(config_file_path, "w") as config_file:
143
- registry_config.write(config_file)
144
-
145
- config_abs_path = Path(config_file_path).resolve().as_posix()
146
-
147
- print(f"Wrote registry config file to {config_abs_path}")