aipmodel 0.2.72__tar.gz → 0.2.74__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.72
3
+ Version: 0.2.74
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,12 @@ 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
+ # Registry<->storage integrity (zombie/orphan) checks - opt-in, default off.
48
+ # When false, verify_model_integrity / verify_all_models / find_orphan_models
49
+ # raise IntegrityDisabledError instead of running the (S3-listing) consistency
50
+ # scan. Also settable per instance: MLOpsManager(..., INTEGRITY_ENABLED=True).
51
+ INTEGRITY_ENABLED="false"
52
+
47
53
  # Optional overrides (all have sane defaults if omitted)
48
54
  SDK_REQUEST_TIMEOUT="30"
49
55
  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.72"
14
+ __version__ = "0.2.74"
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,7 @@ class MLOpsManager:
368
368
  skip_connection_check=False,
369
369
  ACL_API_HOST=None,
370
370
  ACL_ENABLED=None,
371
+ INTEGRITY_ENABLED=None,
371
372
  MLOPS_CORE_API_HOST=None,
372
373
  MLOPS_CORE_WEB_HOST=None
373
374
  ):
@@ -491,6 +492,16 @@ class MLOpsManager:
491
492
  )
492
493
  self.ACL_API_HOST = ACL_API_HOST or os.environ.get("ACL_API_HOST")
493
494
 
495
+ # --- Registry <-> Storage integrity checks (zombie/orphan detection) ---
496
+ # Toggle controlled by INTEGRITY_ENABLED (kwarg or .env). When disabled
497
+ # (the default), verify_model_integrity / verify_all_models /
498
+ # find_orphan_models refuse to run — the consistency scan lists S3 for
499
+ # every model, so it is opt-in rather than on by default.
500
+ self.INTEGRITY_ENABLED = self._to_bool(
501
+ INTEGRITY_ENABLED if INTEGRITY_ENABLED is not None else os.environ.get("INTEGRITY_ENABLED"),
502
+ default=False
503
+ )
504
+
494
505
  if self.ACL_ENABLED:
495
506
  if not self.ACL_API_HOST:
496
507
  error_msg = "ACL_ENABLED is true but ACL_API_HOST is not configured"
@@ -1677,12 +1688,19 @@ class MLOpsManager:
1677
1688
 
1678
1689
  Returns:
1679
1690
  {
1680
- "model_id", "model_name", "status": "ok"|"missing_files"|"orphan_files",
1691
+ "model_id", "model_name",
1692
+ "status": "ok"|"missing_files"|"orphan_files"|"empty",
1681
1693
  "versions": [{"version","path","files_exist","status"}...],
1682
1694
  "orphan_folders": [<S3 folders under the model not referenced by any version>],
1683
1695
  }
1684
1696
  Raises ModelNotFoundError if the model is not in the registry at all.
1697
+ Raises IntegrityDisabledError if INTEGRITY_ENABLED is off (the default).
1685
1698
  """
1699
+ if not self.INTEGRITY_ENABLED:
1700
+ raise IntegrityDisabledError(
1701
+ "Integrity checks are disabled. Enable them with INTEGRITY_ENABLED=true "
1702
+ "(constructor kwarg or environment variable)."
1703
+ )
1686
1704
  if not model_id:
1687
1705
  model_id = self.get_model_id_by_name(model_name)
1688
1706
  if not model_id:
@@ -1733,12 +1751,27 @@ class MLOpsManager:
1733
1751
  report["status"] = "missing_files"
1734
1752
  elif report["orphan_folders"]:
1735
1753
  report["status"] = "orphan_files"
1754
+ elif not versions_map:
1755
+ # Registry holds the model container but NO versions and NO files.
1756
+ # This is the shell an interrupted add leaves behind when the process
1757
+ # is hard-killed mid-upload (pod rollout, OOM, node eviction) — the
1758
+ # in-process rollback in add_model never runs in that case. Surface it
1759
+ # (it was previously reported "ok") so it can be cleaned up or the add
1760
+ # retried. Note: a version add still in flight shows its temp folder as
1761
+ # an orphan_folder above, so it reports "orphan_files", not "empty".
1762
+ report["status"] = "empty"
1736
1763
  return report
1737
1764
 
1738
1765
  def verify_all_models(self):
1739
1766
  """Run verify_model_integrity over every model in the user's project.
1740
1767
  Returns a list of per-model reports (never raises per-model; a model
1741
- that fails to verify is reported with status "error")."""
1768
+ that fails to verify is reported with status "error").
1769
+ Raises IntegrityDisabledError if INTEGRITY_ENABLED is off (the default)."""
1770
+ if not self.INTEGRITY_ENABLED:
1771
+ raise IntegrityDisabledError(
1772
+ "Integrity checks are disabled. Enable them with INTEGRITY_ENABLED=true "
1773
+ "(constructor kwarg or environment variable)."
1774
+ )
1742
1775
  reports = []
1743
1776
  models = self.models.get_all(self.project_id) or []
1744
1777
  for m in models:
@@ -1760,7 +1793,13 @@ class MLOpsManager:
1760
1793
  Find S3 model folders (under `_models/`) that the registry does NOT
1761
1794
  know about — e.g. leftovers after a registry (Mlops-Core) data loss.
1762
1795
  Returns [{"model_id", "recoverable" (has _meta.json), "meta": {...}|None}].
1796
+ Raises IntegrityDisabledError if INTEGRITY_ENABLED is off (the default).
1763
1797
  """
1798
+ if not self.INTEGRITY_ENABLED:
1799
+ raise IntegrityDisabledError(
1800
+ "Integrity checks are disabled. Enable them with INTEGRITY_ENABLED=true "
1801
+ "(constructor kwarg or environment variable)."
1802
+ )
1764
1803
  mgr = self._get_ceph_manager(False)
1765
1804
  registry_ids = {m.get("id") for m in (self.models.get_all(self.project_id) or [])}
1766
1805
  s3_ids = set()
@@ -1813,6 +1852,23 @@ class MLOpsManager:
1813
1852
  self.delete_model(model_name=model_name, version=version)
1814
1853
  print(f"[SDK_SUCCESS] Synced: removed zombie version '{version}' of '{model_name}' from registry.")
1815
1854
 
1855
+ def remove_empty_model(self, model_name=None, model_id=None):
1856
+ """
1857
+ Sync-repair for an EMPTY model container: the registry holds the model
1858
+ but it has no versions and no stored files — the shell an interrupted /
1859
+ hard-killed add leaves behind. Deletes the container so the registry is
1860
+ clean. Refuses to run if the model actually has versions or files (so a
1861
+ real model, or an add still in flight, is never removed by mistake).
1862
+ """
1863
+ report = self.verify_model_integrity(model_name=model_name, model_id=model_id)
1864
+ if report["status"] != "empty":
1865
+ raise ValueError(
1866
+ f"Model '{report['model_name']}' is not empty (status={report['status']}); "
1867
+ f"refusing to remove it. Use delete_model for a real delete."
1868
+ )
1869
+ self.delete_model(model_id=report["model_id"])
1870
+ print(f"[SDK_SUCCESS] Removed empty model shell '{report['model_name']}'.")
1871
+
1816
1872
  def purge_orphan_folders(self, model_name=None, model_id=None):
1817
1873
  """
1818
1874
  Sync-repair for ORPHAN folders inside a registered model: S3 folders
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aipmodel
3
- Version: 0.2.72
3
+ Version: 0.2.74
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.72",
34
+ version="0.2.74",
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