Skip to content

Commit 428677f

Browse files
committed
added changes for backup and retention
1 parent 9916616 commit 428677f

File tree

3 files changed

+711
-7
lines changed

3 files changed

+711
-7
lines changed

ads/model/model_metadata.py

Lines changed: 251 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,19 +1770,19 @@ class CustomerNotificationType(str, metaclass=ExtendedEnumMeta):
17701770
ON_SUCCESS = "ON_SUCCESS"
17711771

17721772

1773-
class ModelBackupSettingDetailsMetadata:
1773+
class ModelBackupSetting:
17741774
"""
17751775
Class that represents Model Backup Setting Details Metadata.
17761776
17771777
Methods
17781778
-------
17791779
to_dict(self) -> Dict:
17801780
Serializes the backup settings into a dictionary.
1781-
from_dict(cls, data: Dict) -> 'ModelBackupSettingDetailsMetadata':
1781+
from_dict(cls, data: Dict) -> 'ModelBackupSetting':
17821782
Constructs backup settings from a dictionary.
17831783
to_json(self) -> str:
17841784
Serializes the backup settings into a JSON string.
1785-
from_json(cls, json_str: str) -> 'ModelBackupSettingDetailsMetadata':
1785+
from_json(cls, json_str: str) -> 'ModelBackupSetting':
17861786
Constructs backup settings from a JSON string.
17871787
to_yaml(self) -> str:
17881788
Serializes the backup settings into a YAML string.
@@ -1805,7 +1805,7 @@ def to_dict(self) -> Dict:
18051805
}
18061806

18071807
@classmethod
1808-
def from_dict(cls, data: Dict) -> 'ModelBackupSettingDetailsMetadata':
1808+
def from_dict(cls, data: Dict) -> 'ModelBackupSetting':
18091809
"""Constructs backup settings from a dictionary."""
18101810
return cls(
18111811
is_backup_enabled=data.get("is_backup_enabled"),
@@ -1818,7 +1818,7 @@ def to_json(self) -> str:
18181818
return json.dumps(self.to_dict())
18191819

18201820
@classmethod
1821-
def from_json(cls, json_str: str) -> 'ModelBackupSettingDetailsMetadata':
1821+
def from_json(cls, json_str: str) -> 'ModelBackupSetting':
18221822
"""Constructs backup settings from a JSON string."""
18231823
data = json.loads(json_str)
18241824
return cls.from_dict(data)
@@ -1838,6 +1838,251 @@ def validate(self) -> bool:
18381838
return True
18391839

18401840
def __repr__(self):
1841-
return f"ModelBackupSettingDetailsMetadata(is_backup_enabled={self.is_backup_enabled}, backup_region={self.backup_region}, customer_notification_type={self.customer_notification_type})"
1841+
return f"ModelBackupSetting(is_backup_enabled={self.is_backup_enabled}, backup_region={self.backup_region}, customer_notification_type={self.customer_notification_type})"
1842+
1843+
1844+
class ModelRetentionSetting:
1845+
"""
1846+
Class that represents Model Retention Setting Details Metadata.
1847+
1848+
Methods
1849+
-------
1850+
to_dict(self) -> Dict:
1851+
Serializes the retention settings into a dictionary.
1852+
from_dict(cls, data: Dict) -> 'ModelRetentionSetting':
1853+
Constructs retention settings from a dictionary.
1854+
to_json(self) -> str:
1855+
Serializes the retention settings into a JSON string.
1856+
from_json(cls, json_str: str) -> 'ModelRetentionSetting':
1857+
Constructs retention settings from a JSON string.
1858+
to_yaml(self) -> str:
1859+
Serializes the retention settings into a YAML string.
1860+
validate(self) -> bool:
1861+
Validates the retention settings details.
1862+
"""
1863+
1864+
def __init__(self, archive_after_days: Optional[int] = None, delete_after_days: Optional[int] = None,
1865+
customer_notification_type: Optional[CustomerNotificationType] = None):
1866+
self.archive_after_days = archive_after_days
1867+
self.delete_after_days = delete_after_days
1868+
self.customer_notification_type = customer_notification_type if customer_notification_type is not None else CustomerNotificationType.NONE
1869+
1870+
def to_dict(self) -> Dict:
1871+
"""Serializes the retention settings into a dictionary."""
1872+
return {
1873+
"archive_after_days": self.archive_after_days,
1874+
"delete_after_days": self.delete_after_days,
1875+
"customer_notification_type": self.customer_notification_type.value
1876+
}
1877+
1878+
@classmethod
1879+
def from_dict(cls, data: Dict) -> 'ModelRetentionSetting':
1880+
"""Constructs retention settings from a dictionary."""
1881+
return cls(
1882+
archive_after_days=data.get("archive_after_days"),
1883+
delete_after_days=data.get("delete_after_days"),
1884+
customer_notification_type=CustomerNotificationType(data.get("customer_notification_type", CustomerNotificationType.NONE.value))
1885+
)
1886+
1887+
def to_json(self) -> str:
1888+
"""Serializes the retention settings into a JSON string."""
1889+
return json.dumps(self.to_dict())
1890+
1891+
@classmethod
1892+
def from_json(cls, json_str: str) -> 'ModelRetentionSetting':
1893+
"""Constructs retention settings from a JSON string."""
1894+
data = json.loads(json_str)
1895+
return cls.from_dict(data)
1896+
1897+
def to_yaml(self) -> str:
1898+
"""Serializes the retention settings into a YAML string."""
1899+
return yaml.dump(self.to_dict())
1900+
1901+
def validate(self) -> bool:
1902+
"""Validates the retention settings details. Returns True if valid, False otherwise."""
1903+
if self.archive_after_days is not None and (not isinstance(self.archive_after_days, int) or self.archive_after_days < 0):
1904+
return False
1905+
if self.delete_after_days is not None and (not isinstance(self.delete_after_days, int) or self.delete_after_days < 0):
1906+
return False
1907+
if not isinstance(self.customer_notification_type, CustomerNotificationType):
1908+
return False
1909+
return True
1910+
1911+
def __repr__(self):
1912+
return f"ModelRetentionSetting(archive_after_days={self.archive_after_days}, delete_after_days={self.delete_after_days}, customer_notification_type={self.customer_notification_type})"
1913+
1914+
1915+
class SettingStatus(str, ExtendedEnumMeta):
1916+
"""Enum to represent the status of retention settings."""
1917+
PENDING = "PENDING"
1918+
SUCCEEDED = "SUCCEEDED"
1919+
FAILED = "FAILED"
1920+
1921+
class ModelRetentionOperationDetails:
1922+
"""
1923+
Class that represents Model Retention Operation Details Metadata.
1924+
1925+
Methods
1926+
-------
1927+
to_dict(self) -> Dict:
1928+
Serializes the retention operation details into a dictionary.
1929+
from_dict(cls, data: Dict) -> 'ModelRetentionOperationDetails':
1930+
Constructs retention operation details from a dictionary.
1931+
to_json(self) -> str:
1932+
Serializes the retention operation details into a JSON string.
1933+
from_json(cls, json_str: str) -> 'ModelRetentionOperationDetails':
1934+
Constructs retention operation details from a JSON string.
1935+
to_yaml(self) -> str:
1936+
Serializes the retention operation details into a YAML string.
1937+
validate(self) -> bool:
1938+
Validates the retention operation details.
1939+
"""
1940+
1941+
def __init__(self,
1942+
archive_state: Optional[SettingStatus] = None,
1943+
archive_state_details: Optional[str] = None,
1944+
delete_state: Optional[SettingStatus] = None,
1945+
delete_state_details: Optional[str] = None,
1946+
time_archival_scheduled: Optional[int] = None,
1947+
time_deletion_scheduled: Optional[int] = None):
1948+
self.archive_state = archive_state if archive_state is not None else SettingStatus.PENDING
1949+
self.archive_state_details = archive_state_details
1950+
self.delete_state = delete_state if delete_state is not None else SettingStatus.PENDING
1951+
self.delete_state_details = delete_state_details
1952+
self.time_archival_scheduled = time_archival_scheduled
1953+
self.time_deletion_scheduled = time_deletion_scheduled
1954+
1955+
def to_dict(self) -> Dict:
1956+
"""Serializes the retention operation details into a dictionary."""
1957+
return {
1958+
"archive_state": self.archive_state.value,
1959+
"archive_state_details": self.archive_state_details,
1960+
"delete_state": self.delete_state.value,
1961+
"delete_state_details": self.delete_state_details,
1962+
"time_archival_scheduled": self.time_archival_scheduled,
1963+
"time_deletion_scheduled": self.time_deletion_scheduled
1964+
}
1965+
1966+
@classmethod
1967+
def from_dict(cls, data: Dict) -> 'ModelRetentionOperationDetails':
1968+
"""Constructs retention operation details from a dictionary."""
1969+
return cls(
1970+
archive_state=SettingStatus(data.get("archive_state", SettingStatus.PENDING.value)),
1971+
archive_state_details=data.get("archive_state_details"),
1972+
delete_state=SettingStatus(data.get("delete_state", SettingStatus.PENDING.value)),
1973+
delete_state_details=data.get("delete_state_details"),
1974+
time_archival_scheduled=data.get("time_archival_scheduled"),
1975+
time_deletion_scheduled=data.get("time_deletion_scheduled")
1976+
)
1977+
1978+
def to_json(self) -> str:
1979+
"""Serializes the retention operation details into a JSON string."""
1980+
return json.dumps(self.to_dict())
1981+
1982+
@classmethod
1983+
def from_json(cls, json_str: str) -> 'ModelRetentionOperationDetails':
1984+
"""Constructs retention operation details from a JSON string."""
1985+
data = json.loads(json_str)
1986+
return cls.from_dict(data)
1987+
1988+
def to_yaml(self) -> str:
1989+
"""Serializes the retention operation details into a YAML string."""
1990+
return yaml.dump(self.to_dict())
1991+
1992+
def validate(self) -> bool:
1993+
"""Validates the retention operation details."""
1994+
if not isinstance(self.archive_state, SettingStatus):
1995+
return False
1996+
if not isinstance(self.delete_state, SettingStatus):
1997+
return False
1998+
if self.time_archival_scheduled is not None and not isinstance(self.time_archival_scheduled, int):
1999+
return False
2000+
if self.time_deletion_scheduled is not None and not isinstance(self.time_deletion_scheduled, int):
2001+
return False
2002+
return True
2003+
2004+
def __repr__(self):
2005+
return (f"ModelRetentionOperationDetails("
2006+
f"archive_state={self.archive_state}, "
2007+
f"archive_state_details={self.archive_state_details}, "
2008+
f"delete_state={self.delete_state}, "
2009+
f"delete_state_details={self.delete_state_details}, "
2010+
f"time_archival_scheduled={self.time_archival_scheduled}, "
2011+
f"time_deletion_scheduled={self.time_deletion_scheduled})")
2012+
2013+
2014+
class ModelBackupOperationDetails:
2015+
"""
2016+
Class that represents Model Backup Operation Details Metadata.
2017+
2018+
Methods
2019+
-------
2020+
to_dict(self) -> Dict:
2021+
Serializes the backup operation details into a dictionary.
2022+
from_dict(cls, data: Dict) -> 'ModelBackupOperationDetails':
2023+
Constructs backup operation details from a dictionary.
2024+
to_json(self) -> str:
2025+
Serializes the backup operation details into a JSON string.
2026+
from_json(cls, json_str: str) -> 'ModelBackupOperationDetails':
2027+
Constructs backup operation details from a JSON string.
2028+
to_yaml(self) -> str:
2029+
Serializes the backup operation details into a YAML string.
2030+
validate(self) -> bool:
2031+
Validates the backup operation details.
2032+
"""
2033+
2034+
def __init__(self,
2035+
backup_state: Optional['SettingStatus'] = None,
2036+
backup_state_details: Optional[str] = None,
2037+
time_last_backed_up: Optional[int] = None):
2038+
self.backup_state = backup_state if backup_state is not None else SettingStatus.PENDING
2039+
self.backup_state_details = backup_state_details
2040+
self.time_last_backed_up = time_last_backed_up
2041+
2042+
def to_dict(self) -> Dict:
2043+
"""Serializes the backup operation details into a dictionary."""
2044+
return {
2045+
"backup_state": self.backup_state.value,
2046+
"backup_state_details": self.backup_state_details,
2047+
"time_last_backed_up": self.time_last_backed_up
2048+
}
2049+
2050+
@classmethod
2051+
def from_dict(cls, data: Dict) -> 'ModelBackupOperationDetails':
2052+
"""Constructs backup operation details from a dictionary."""
2053+
return cls(
2054+
backup_state=SettingStatus(data.get("backup_state", SettingStatus.PENDING.value)),
2055+
backup_state_details=data.get("backup_state_details"),
2056+
time_last_backed_up=data.get("time_last_backed_up")
2057+
)
2058+
2059+
def to_json(self) -> str:
2060+
"""Serializes the backup operation details into a JSON string."""
2061+
return json.dumps(self.to_dict())
2062+
2063+
@classmethod
2064+
def from_json(cls, json_str: str) -> 'ModelBackupOperationDetails':
2065+
"""Constructs backup operation details from a JSON string."""
2066+
data = json.loads(json_str)
2067+
return cls.from_dict(data)
2068+
2069+
def to_yaml(self) -> str:
2070+
"""Serializes the backup operation details into a YAML string."""
2071+
return yaml.dump(self.to_dict())
2072+
2073+
def validate(self) -> bool:
2074+
"""Validates the backup operation details."""
2075+
if not isinstance(self.backup_state, SettingStatus):
2076+
return False
2077+
if self.time_last_backed_up is not None and not isinstance(self.time_last_backed_up, int):
2078+
return False
2079+
return True
2080+
2081+
def __repr__(self):
2082+
return (f"ModelBackupOperationDetails("
2083+
f"backup_state={self.backup_state}, "
2084+
f"backup_state_details={self.backup_state_details}, "
2085+
f"time_last_backed_up={self.time_last_backed_up})")
2086+
18422087

18432088

tests/unitary/default_setup/model/test_datascience_model.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
ModelTaxonomyMetadata,
3535
ModelCustomMetadataItem,
3636
MetadataCustomCategory,
37+
ModelBackupSetting,
38+
ModelRetentionSetting
3739
)
3840
from ads.model.service.oci_datascience_model import (
3941
ModelProvenanceNotFoundError,
@@ -44,7 +46,7 @@
4446
from ads.config import AQUA_SERVICE_MODELS_BUCKET as SERVICE_MODELS_BUCKET
4547

4648
MODEL_OCID = "ocid1.datasciencemodel.oc1.iad.<unique_ocid>"
47-
49+
4850
OCI_MODEL_PAYLOAD = {
4951
"id": MODEL_OCID,
5052
"compartment_id": "ocid1.compartment.oc1..<unique_ocid>",
@@ -72,6 +74,16 @@
7274
{"key": "Hyperparameters"},
7375
{"key": "ArtifactTestResults"},
7476
],
77+
"backupSetting": {
78+
"isBackupEnabled": True,
79+
"backupRegion": "us-phoenix-1",
80+
"customerNotificationType": "ALL"
81+
},
82+
"retentionSetting": {
83+
"archiveAfterDays": 30,
84+
"deleteAfterDays": 90,
85+
"customerNotificationType": "ALL"
86+
},
7587
"input_schema": '{"schema": [{"dtype": "int64", "feature_type": "Integer", "name": 0, "domain": {"values": "", "stats": {}, "constraints": []}, "required": true, "description": "0", "order": 0}], "version": "1.1"}',
7688
"output_schema": '{"schema": [{"dtype": "int64", "feature_type": "Integer", "name": 0, "domain": {"values": "", "stats": {}, "constraints": []}, "required": true, "description": "0", "order": 0}], "version": "1.1"}',
7789
}
@@ -148,6 +160,16 @@
148160
"training_id": None,
149161
"artifact_dir": "test_script_dir",
150162
},
163+
"backupSetting": {
164+
"isBackupEnabled": True,
165+
"backupRegion": "us-phoenix-1",
166+
"customerNotificationType": "ALL"
167+
},
168+
"retentionSetting": {
169+
"archiveAfterDays": 30,
170+
"deleteAfterDays": 90,
171+
"customerNotificationType": "ALL"
172+
},
151173
"artifact": "ocid1.datasciencemodel.oc1.iad.<unique_ocid>.zip",
152174
}
153175

@@ -307,6 +329,8 @@ def test_with_methods_1(self, mock_load_default_properties):
307329
.with_defined_metadata_list(self.payload["definedMetadataList"])
308330
.with_provenance_metadata(self.payload["provenanceMetadata"])
309331
.with_artifact(self.payload["artifact"])
332+
.with_backup_setting(self.payload['backupSetting'])
333+
.with_retention_setting(self.payload['retentionSetting'])
310334
)
311335
assert self.prepare_dict(dsc_model.to_dict()["spec"]) == self.prepare_dict(
312336
self.payload
@@ -334,6 +358,8 @@ def test_with_methods_2(self):
334358
ModelProvenanceMetadata.from_dict(self.payload["provenanceMetadata"])
335359
)
336360
.with_artifact(self.payload["artifact"])
361+
.with_backup_setting(ModelBackupSetting.from_dict(self.payload['backupSetting']))
362+
.with_retention_setting(ModelRetentionSetting.from_dict(self.payload['retentionSetting']))
337363
)
338364
assert self.prepare_dict(dsc_model.to_dict()["spec"]) == self.prepare_dict(
339365
self.payload
@@ -617,6 +643,16 @@ def test__update_from_oci_dsc_model(
617643
{"key": "Hyperparameters", "value": "new test"},
618644
{"key": "ArtifactTestResults", "value": "new test"},
619645
],
646+
"backup_setting": {
647+
"is_backup_enabled": True,
648+
"backup_region": "us-phoenix-1",
649+
"customer_notification_type": "ALL",
650+
},
651+
"retention_setting": {
652+
"archive_after_days": 30,
653+
"delete_after_days": 90,
654+
"customer_notification_type": "ALL",
655+
},
620656
"input_schema": '{"schema": [{"dtype": "int64", "feature_type": "Integer", "name": 1, "domain": {"values": "", "stats": {}, "constraints": []}, "required": true, "description": "0", "order": 0}], "version": "1.1"}',
621657
"output_schema": '{"schema": [{"dtype": "int64", "feature_type": "Integer", "name": 1, "domain": {"values": "", "stats": {}, "constraints": []}, "required": true, "description": "0", "order": 0}], "version": "1.1"}',
622658
}
@@ -681,6 +717,16 @@ def test__update_from_oci_dsc_model(
681717
{"key": "ArtifactTestResults", "value": "new test"},
682718
]
683719
},
720+
"backupSetting": {
721+
"isBackupEnabled": True,
722+
"backupRegion": "us-phoenix-1",
723+
"customerNotificationType": "ALL",
724+
},
725+
"retentionSetting": {
726+
"archiveAfterDays": 30,
727+
"deleteAfterDays": 90,
728+
"customerNotificationType": "ALL",
729+
},
684730
"provenanceMetadata": {
685731
"git_branch": "master",
686732
"git_commit": "7c8c8502896ba36837f15037b67e05a3cf9722c7",

0 commit comments

Comments
 (0)