aipmodel 0.2.73__tar.gz → 0.2.75__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aipmodel
3
- Version: 0.2.73
3
+ Version: 0.2.75
4
4
  Summary: SDK for model registration, versioning, and storage
5
5
  Home-page: https://github.com/AIP-MLOPS/model-registry
6
6
  Author: AIP MLOPS Team
@@ -44,6 +44,25 @@ CEPH_ADMIN_SECRET_KEY="your_public_bucket_secret_key"
44
44
  ACL_ENABLED="false"
45
45
  ACL_API_HOST="http://your-acl-server:30011"
46
46
 
47
+ # Where per-user credentials come from. Default true: resolve the user's S3 +
48
+ # Mlops-Core keys from the user-management service using the bearer token.
49
+ # Set false to run WITHOUT user-management (other systems / testing): the SDK
50
+ # then reads the keys straight from the env vars below instead.
51
+ USER_MANAGEMENT_ENABLED="true"
52
+ # Only used when USER_MANAGEMENT_ENABLED="false":
53
+ # CEPH_USER_ACCESS_KEY="..." # the user's S3 access key
54
+ # CEPH_USER_SECRET_KEY="..." # the user's S3 secret key
55
+ # CEPH_USER_BUCKET="..." # the user's bucket
56
+ # MLOPS_CORE_ACCESS_KEY="..." # Mlops-Core basic-auth access key
57
+ # MLOPS_CORE_SECRET_KEY="..." # Mlops-Core basic-auth secret key
58
+ # MLOPS_CORE_USERNAME="..." # display/owner name
59
+
60
+ # Registry<->storage integrity (zombie/orphan) checks - opt-in, default off.
61
+ # When false, verify_model_integrity / verify_all_models / find_orphan_models
62
+ # raise IntegrityDisabledError instead of running the (S3-listing) consistency
63
+ # scan. Also settable per instance: MLOpsManager(..., INTEGRITY_ENABLED=True).
64
+ INTEGRITY_ENABLED="false"
65
+
47
66
  # Optional overrides (all have sane defaults if omitted)
48
67
  SDK_REQUEST_TIMEOUT="30"
49
68
  MODEL_ALLOWED_CATEGORIES="Text Generation,Image Classification"
@@ -11,5 +11,5 @@ if _os.environ.get("AIPMODEL_UPDATE_CHECK", "").lower() in ("1", "true", "yes"):
11
11
 
12
12
  __all__ = ["MLOpsManager", "CephS3Manager"]
13
13
 
14
- __version__ = "0.2.73"
14
+ __version__ = "0.2.75"
15
15
  __description__ = "SDK for model registration, versioning, and storage"
@@ -21,3 +21,8 @@ class MetadataError(ModelRegistryError):
21
21
 
22
22
  class StorageError(ModelRegistryError):
23
23
  """S3 / Ceph operation failed (upload, download, copy, delete)."""
24
+
25
+
26
+ class IntegrityDisabledError(ModelRegistryError):
27
+ """An integrity/zombie-check operation was called while INTEGRITY_ENABLED is
28
+ off (the default). Enable it (kwarg or env) to run consistency scans."""
@@ -18,7 +18,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
18
18
 
19
19
  from .CephS3Manager import CephS3Manager
20
20
  from .acl_manager import AclManager
21
- from .exceptions import ModelRegistryError, ModelNotFoundError, MetadataError, StorageError
21
+ from .exceptions import ModelRegistryError, ModelNotFoundError, MetadataError, StorageError, IntegrityDisabledError
22
22
 
23
23
  load_dotenv()
24
24
 
@@ -368,6 +368,8 @@ class MLOpsManager:
368
368
  skip_connection_check=False,
369
369
  ACL_API_HOST=None,
370
370
  ACL_ENABLED=None,
371
+ INTEGRITY_ENABLED=None,
372
+ USER_MANAGEMENT_ENABLED=None,
371
373
  MLOPS_CORE_API_HOST=None,
372
374
  MLOPS_CORE_WEB_HOST=None
373
375
  ):
@@ -407,19 +409,52 @@ class MLOpsManager:
407
409
 
408
410
  self.USER_MANAGEMENT_API = USER_MANAGEMENT_API or os.environ.get("USER_MANAGEMENT_API")
409
411
  self.CEPH_ENDPOINT_URL = CEPH_ENDPOINT_URL or os.environ.get("CEPH_ENDPOINT_URL")
410
-
412
+
413
+ # Where per-user credentials come from. Default True: resolve the user's
414
+ # S3 + Mlops-Core keys from the user-management service via the bearer
415
+ # token (production). Set USER_MANAGEMENT_ENABLED=false to run on a system
416
+ # WITHOUT user-management — the keys are then read straight from env:
417
+ # CEPH_USER_ACCESS_KEY / CEPH_USER_SECRET_KEY / CEPH_USER_BUCKET /
418
+ # MLOPS_CORE_ACCESS_KEY / MLOPS_CORE_SECRET_KEY / MLOPS_CORE_USERNAME.
419
+ self.USER_MANAGEMENT_ENABLED = self._to_bool(
420
+ USER_MANAGEMENT_ENABLED if USER_MANAGEMENT_ENABLED is not None else os.environ.get("USER_MANAGEMENT_ENABLED"),
421
+ default=True
422
+ )
423
+
411
424
  # Public Bucket Configuration
412
425
  self.CEPH_PUBLIC_BUCKET_NAME = os.environ.get("CEPH_PUBLIC_BUCKET_NAME", "aip-public")
413
426
  self.PUBLIC_ACCESS_KEY = os.environ.get("CEPH_ADMIN_ACCESS_KEY")
414
427
  self.PUBLIC_SECRET_KEY = os.environ.get("CEPH_ADMIN_SECRET_KEY")
415
428
 
416
- user_info, self.MLOPS_CORE_USERNAME = get_user_metadata(bearer_token=user_token, user_management_url=self.USER_MANAGEMENT_API)
429
+ if self.USER_MANAGEMENT_ENABLED:
430
+ user_info, self.MLOPS_CORE_USERNAME = get_user_metadata(bearer_token=user_token, user_management_url=self.USER_MANAGEMENT_API)
431
+ else:
432
+ # Direct-credential mode — no user-management call; keys come from env.
433
+ self.MLOPS_CORE_USERNAME = os.environ.get("MLOPS_CORE_USERNAME") or os.environ.get("CLEARML_USERNAME") or "local"
434
+ user_info = {
435
+ "s3_access_key": os.environ.get("CEPH_USER_ACCESS_KEY") or os.environ.get("CEPH_ADMIN_ACCESS_KEY"),
436
+ "s3_secret_key": os.environ.get("CEPH_USER_SECRET_KEY") or os.environ.get("CEPH_ADMIN_SECRET_KEY"),
437
+ "s3_bucket": os.environ.get("CEPH_USER_BUCKET"),
438
+ "clearml_access_key": os.environ.get("MLOPS_CORE_ACCESS_KEY") or os.environ.get("CLEARML_ACCESS_KEY"),
439
+ "clearml_secret_key": os.environ.get("MLOPS_CORE_SECRET_KEY") or os.environ.get("CLEARML_SECRET_KEY"),
440
+ }
441
+ missing_creds = [k for k, v in user_info.items() if not v]
442
+ if missing_creds:
443
+ raise ValueError(
444
+ "USER_MANAGEMENT_ENABLED is false but direct credentials are missing from env: "
445
+ + ", ".join(missing_creds)
446
+ + " (set CEPH_USER_ACCESS_KEY / CEPH_USER_SECRET_KEY / CEPH_USER_BUCKET / "
447
+ "MLOPS_CORE_ACCESS_KEY / MLOPS_CORE_SECRET_KEY)."
448
+ )
417
449
 
418
- missing_cfg = [k for k, v in {
450
+ # USER_MANAGEMENT_API is only required when that service is actually used.
451
+ required_cfg = {
419
452
  "MLOPS_CORE_API_HOST": self.MLOPS_CORE_API_HOST,
420
- "USER_MANAGEMENT_API": self.USER_MANAGEMENT_API,
421
453
  "CEPH_ENDPOINT_URL": self.CEPH_ENDPOINT_URL,
422
- }.items() if not v]
454
+ }
455
+ if self.USER_MANAGEMENT_ENABLED:
456
+ required_cfg["USER_MANAGEMENT_API"] = self.USER_MANAGEMENT_API
457
+ missing_cfg = [k for k, v in required_cfg.items() if not v]
423
458
  if missing_cfg:
424
459
  error_msg = f"Missing required configuration: {', '.join(missing_cfg)}"
425
460
  print(f"[SDK_FAIL] {error_msg}")
@@ -448,7 +483,7 @@ class MLOpsManager:
448
483
  if not skip_connection_check:
449
484
  if self.verbose:
450
485
  print("[SDK_INFO] Performing health checks...")
451
- if not self.check_user_management_service():
486
+ if self.USER_MANAGEMENT_ENABLED and not self.check_user_management_service():
452
487
  raise ValueError("User Management API unreachable")
453
488
  if not self.check_mlops_core_service():
454
489
  raise ValueError("Mlops-Core Server down")
@@ -491,6 +526,16 @@ class MLOpsManager:
491
526
  )
492
527
  self.ACL_API_HOST = ACL_API_HOST or os.environ.get("ACL_API_HOST")
493
528
 
529
+ # --- Registry <-> Storage integrity checks (zombie/orphan detection) ---
530
+ # Toggle controlled by INTEGRITY_ENABLED (kwarg or .env). When disabled
531
+ # (the default), verify_model_integrity / verify_all_models /
532
+ # find_orphan_models refuse to run — the consistency scan lists S3 for
533
+ # every model, so it is opt-in rather than on by default.
534
+ self.INTEGRITY_ENABLED = self._to_bool(
535
+ INTEGRITY_ENABLED if INTEGRITY_ENABLED is not None else os.environ.get("INTEGRITY_ENABLED"),
536
+ default=False
537
+ )
538
+
494
539
  if self.ACL_ENABLED:
495
540
  if not self.ACL_API_HOST:
496
541
  error_msg = "ACL_ENABLED is true but ACL_API_HOST is not configured"
@@ -1683,7 +1728,13 @@ class MLOpsManager:
1683
1728
  "orphan_folders": [<S3 folders under the model not referenced by any version>],
1684
1729
  }
1685
1730
  Raises ModelNotFoundError if the model is not in the registry at all.
1731
+ Raises IntegrityDisabledError if INTEGRITY_ENABLED is off (the default).
1686
1732
  """
1733
+ if not self.INTEGRITY_ENABLED:
1734
+ raise IntegrityDisabledError(
1735
+ "Integrity checks are disabled. Enable them with INTEGRITY_ENABLED=true "
1736
+ "(constructor kwarg or environment variable)."
1737
+ )
1687
1738
  if not model_id:
1688
1739
  model_id = self.get_model_id_by_name(model_name)
1689
1740
  if not model_id:
@@ -1748,7 +1799,13 @@ class MLOpsManager:
1748
1799
  def verify_all_models(self):
1749
1800
  """Run verify_model_integrity over every model in the user's project.
1750
1801
  Returns a list of per-model reports (never raises per-model; a model
1751
- that fails to verify is reported with status "error")."""
1802
+ that fails to verify is reported with status "error").
1803
+ Raises IntegrityDisabledError if INTEGRITY_ENABLED is off (the default)."""
1804
+ if not self.INTEGRITY_ENABLED:
1805
+ raise IntegrityDisabledError(
1806
+ "Integrity checks are disabled. Enable them with INTEGRITY_ENABLED=true "
1807
+ "(constructor kwarg or environment variable)."
1808
+ )
1752
1809
  reports = []
1753
1810
  models = self.models.get_all(self.project_id) or []
1754
1811
  for m in models:
@@ -1770,7 +1827,13 @@ class MLOpsManager:
1770
1827
  Find S3 model folders (under `_models/`) that the registry does NOT
1771
1828
  know about — e.g. leftovers after a registry (Mlops-Core) data loss.
1772
1829
  Returns [{"model_id", "recoverable" (has _meta.json), "meta": {...}|None}].
1830
+ Raises IntegrityDisabledError if INTEGRITY_ENABLED is off (the default).
1773
1831
  """
1832
+ if not self.INTEGRITY_ENABLED:
1833
+ raise IntegrityDisabledError(
1834
+ "Integrity checks are disabled. Enable them with INTEGRITY_ENABLED=true "
1835
+ "(constructor kwarg or environment variable)."
1836
+ )
1774
1837
  mgr = self._get_ceph_manager(False)
1775
1838
  registry_ids = {m.get("id") for m in (self.models.get_all(self.project_id) or [])}
1776
1839
  s3_ids = set()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aipmodel
3
- Version: 0.2.73
3
+ Version: 0.2.75
4
4
  Summary: SDK for model registration, versioning, and storage
5
5
  Home-page: https://github.com/AIP-MLOPS/model-registry
6
6
  Author: AIP MLOPS Team
@@ -31,7 +31,7 @@ version, description = read_meta()
31
31
 
32
32
  setup(
33
33
  name="aipmodel",
34
- version="0.2.73",
34
+ version="0.2.75",
35
35
  description=description,
36
36
  author="AIP MLOPS Team",
37
37
  author_email="mohmmadweb@gmail.com",
File without changes
File without changes
File without changes