oracle-ads 2.10.1__py3-none-any.whl → 2.11.1__py3-none-any.whl
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.
- ads/aqua/__init__.py +12 -0
- ads/aqua/base.py +324 -0
- ads/aqua/cli.py +19 -0
- ads/aqua/config/deployment_config_defaults.json +9 -0
- ads/aqua/config/resource_limit_names.json +7 -0
- ads/aqua/constants.py +45 -0
- ads/aqua/data.py +40 -0
- ads/aqua/decorator.py +101 -0
- ads/aqua/deployment.py +643 -0
- ads/aqua/dummy_data/icon.txt +1 -0
- ads/aqua/dummy_data/oci_model_deployments.json +56 -0
- ads/aqua/dummy_data/oci_models.json +1 -0
- ads/aqua/dummy_data/readme.md +26 -0
- ads/aqua/evaluation.py +1751 -0
- ads/aqua/exception.py +82 -0
- ads/aqua/extension/__init__.py +40 -0
- ads/aqua/extension/base_handler.py +138 -0
- ads/aqua/extension/common_handler.py +21 -0
- ads/aqua/extension/deployment_handler.py +202 -0
- ads/aqua/extension/evaluation_handler.py +135 -0
- ads/aqua/extension/finetune_handler.py +66 -0
- ads/aqua/extension/model_handler.py +59 -0
- ads/aqua/extension/ui_handler.py +201 -0
- ads/aqua/extension/utils.py +23 -0
- ads/aqua/finetune.py +579 -0
- ads/aqua/job.py +29 -0
- ads/aqua/model.py +819 -0
- ads/aqua/training/__init__.py +4 -0
- ads/aqua/training/exceptions.py +459 -0
- ads/aqua/ui.py +453 -0
- ads/aqua/utils.py +715 -0
- ads/cli.py +37 -6
- ads/common/decorator/__init__.py +7 -3
- ads/common/decorator/require_nonempty_arg.py +65 -0
- ads/common/object_storage_details.py +166 -7
- ads/common/oci_client.py +18 -1
- ads/common/oci_logging.py +2 -2
- ads/common/oci_mixin.py +4 -5
- ads/common/serializer.py +34 -5
- ads/common/utils.py +75 -10
- ads/config.py +40 -1
- ads/jobs/ads_job.py +43 -25
- ads/jobs/builders/infrastructure/base.py +4 -2
- ads/jobs/builders/infrastructure/dsc_job.py +49 -39
- ads/jobs/builders/runtimes/base.py +71 -1
- ads/jobs/builders/runtimes/container_runtime.py +4 -4
- ads/jobs/builders/runtimes/pytorch_runtime.py +10 -63
- ads/jobs/templates/driver_pytorch.py +27 -10
- ads/model/artifact_downloader.py +84 -14
- ads/model/artifact_uploader.py +25 -23
- ads/model/datascience_model.py +388 -38
- ads/model/deployment/model_deployment.py +10 -2
- ads/model/generic_model.py +8 -0
- ads/model/model_file_description_schema.json +68 -0
- ads/model/model_metadata.py +1 -1
- ads/model/service/oci_datascience_model.py +34 -5
- ads/opctl/operator/lowcode/anomaly/README.md +2 -1
- ads/opctl/operator/lowcode/anomaly/__main__.py +10 -4
- ads/opctl/operator/lowcode/anomaly/environment.yaml +2 -1
- ads/opctl/operator/lowcode/anomaly/model/automlx.py +12 -6
- ads/opctl/operator/lowcode/forecast/README.md +3 -2
- ads/opctl/operator/lowcode/forecast/environment.yaml +3 -2
- ads/opctl/operator/lowcode/forecast/model/automlx.py +12 -23
- ads/telemetry/base.py +62 -0
- ads/telemetry/client.py +105 -0
- ads/telemetry/telemetry.py +6 -3
- {oracle_ads-2.10.1.dist-info → oracle_ads-2.11.1.dist-info}/METADATA +37 -7
- {oracle_ads-2.10.1.dist-info → oracle_ads-2.11.1.dist-info}/RECORD +71 -36
- {oracle_ads-2.10.1.dist-info → oracle_ads-2.11.1.dist-info}/LICENSE.txt +0 -0
- {oracle_ads-2.10.1.dist-info → oracle_ads-2.11.1.dist-info}/WHEEL +0 -0
- {oracle_ads-2.10.1.dist-info → oracle_ads-2.11.1.dist-info}/entry_points.txt +0 -0
ads/cli.py
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# -*- coding: utf-8 -*--
|
3
3
|
|
4
|
-
# Copyright (c) 2021,
|
4
|
+
# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
7
|
import traceback
|
8
8
|
import sys
|
9
9
|
|
10
|
+
import fire
|
10
11
|
from ads.common import logger
|
12
|
+
from ads.aqua.cli import AquaCommand
|
11
13
|
|
12
14
|
try:
|
13
15
|
import click
|
@@ -37,14 +39,43 @@ ADS_VERSION = metadata.version("oracle_ads")
|
|
37
39
|
@click.group()
|
38
40
|
@click.version_option(version=ADS_VERSION, prog_name="ads")
|
39
41
|
@click.help_option("--help", "-h")
|
40
|
-
def
|
42
|
+
def click_cli():
|
41
43
|
pass
|
42
44
|
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
@click.command
|
47
|
+
def aqua_cli():
|
48
|
+
"""CLI for AQUA."""
|
49
|
+
# This is a dummy entry for click.
|
50
|
+
# The `ads aqua` commands are handled by AquaCommand
|
51
|
+
|
52
|
+
|
53
|
+
click_cli.add_command(ads.opctl.cli.commands)
|
54
|
+
click_cli.add_command(ads.jobs.cli.commands)
|
55
|
+
click_cli.add_command(ads.pipeline.cli.commands)
|
56
|
+
click_cli.add_command(ads.opctl.operator.cli.commands)
|
57
|
+
click_cli.add_command(aqua_cli, name="aqua")
|
58
|
+
|
59
|
+
|
60
|
+
# fix for fire issue with --help
|
61
|
+
# https://github.com/google/python-fire/issues/258
|
62
|
+
def _SeparateFlagArgs(args):
|
63
|
+
try:
|
64
|
+
index = args.index("--help")
|
65
|
+
args = args[:index]
|
66
|
+
return args, ["--help"]
|
67
|
+
except ValueError:
|
68
|
+
return args, []
|
69
|
+
|
70
|
+
|
71
|
+
fire.core.parser.SeparateFlagArgs = _SeparateFlagArgs
|
72
|
+
|
73
|
+
|
74
|
+
def cli():
|
75
|
+
if len(sys.argv) > 1 and sys.argv[1] == "aqua":
|
76
|
+
fire.Fire(AquaCommand, command=sys.argv[2:], name="ads aqua")
|
77
|
+
else:
|
78
|
+
click_cli()
|
48
79
|
|
49
80
|
|
50
81
|
if __name__ == "__main__":
|
ads/common/decorator/__init__.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
# -*- coding: utf-8
|
3
|
-
|
4
|
-
# Copyright (c) 2020, 2022 Oracle and its affiliates.
|
2
|
+
# -*- coding: utf-8 -*--
|
3
|
+
# Copyright (c) 2024 Oracle and/or its affiliates.
|
5
4
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
|
+
|
6
|
+
from ads.common.decorator.require_nonempty_arg import require_nonempty_arg
|
7
|
+
from ads.common.decorator.argument_to_case import argument_to_case
|
8
|
+
from ads.common.decorator.deprecate import deprecated
|
9
|
+
from ads.common.decorator.runtime_dependency import runtime_dependency
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*--
|
3
|
+
# Copyright (c) 2024 Oracle and/or its affiliates.
|
4
|
+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
|
+
|
6
|
+
import inspect
|
7
|
+
from functools import wraps
|
8
|
+
from typing import Any, Callable, List, Union
|
9
|
+
|
10
|
+
from ads.common.decorator.utils import _get_original_func
|
11
|
+
|
12
|
+
|
13
|
+
def require_nonempty_arg(
|
14
|
+
arg_name: Union[str, List[str]], error_msg: str = "A required argument is empty"
|
15
|
+
) -> Callable:
|
16
|
+
"""
|
17
|
+
A decorator to ensure that a specific argument of a function is not empty.
|
18
|
+
|
19
|
+
Parameters
|
20
|
+
----------
|
21
|
+
arg_name (Union[str, List[str]]): The name of the argument or the list of the arguments to check.
|
22
|
+
error_msg (str, optional)
|
23
|
+
The error message to raise if the check fails.
|
24
|
+
|
25
|
+
Returns
|
26
|
+
-------
|
27
|
+
Callable
|
28
|
+
A wrapped function that includes the check.
|
29
|
+
|
30
|
+
Raises
|
31
|
+
------
|
32
|
+
ValueError
|
33
|
+
If the specified argument is empty.
|
34
|
+
"""
|
35
|
+
|
36
|
+
def decorator(func: Callable) -> Callable:
|
37
|
+
@wraps(func)
|
38
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
39
|
+
# Retrieving the original function from the decorated one.
|
40
|
+
# This is necessary when the chain of decorators is used.
|
41
|
+
# The only original function arguments should be processed.
|
42
|
+
original_func = _get_original_func(func)
|
43
|
+
|
44
|
+
# Get the signature of the function
|
45
|
+
sig = inspect.signature(original_func)
|
46
|
+
bound_args = sig.bind(*args, **kwargs)
|
47
|
+
bound_args.apply_defaults()
|
48
|
+
|
49
|
+
# Check if the argument is present and not empty
|
50
|
+
if isinstance(arg_name, str):
|
51
|
+
arguments_to_check = [arg_name]
|
52
|
+
else:
|
53
|
+
arguments_to_check = arg_name
|
54
|
+
|
55
|
+
if not any(
|
56
|
+
check_name in bound_args.arguments and bound_args.arguments[check_name]
|
57
|
+
for check_name in arguments_to_check
|
58
|
+
):
|
59
|
+
raise ValueError(error_msg)
|
60
|
+
|
61
|
+
return func(*args, **kwargs)
|
62
|
+
|
63
|
+
return wrapper
|
64
|
+
|
65
|
+
return decorator
|
@@ -1,18 +1,24 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# -*- coding: utf-8 -*--
|
3
3
|
|
4
|
-
# Copyright (c) 2021,
|
4
|
+
# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
7
|
import json
|
8
8
|
import os
|
9
9
|
import re
|
10
10
|
from dataclasses import dataclass
|
11
|
-
from typing import Dict
|
11
|
+
from typing import Dict, List
|
12
12
|
from urllib.parse import urlparse
|
13
13
|
|
14
|
+
|
15
|
+
import oci
|
14
16
|
from ads.common import auth as authutil
|
15
17
|
from ads.common import oci_client
|
18
|
+
from ads.dataset.progress import TqdmProgressBar
|
19
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
20
|
+
|
21
|
+
THREAD_POOL_MAX_WORKERS = 10
|
16
22
|
|
17
23
|
|
18
24
|
class InvalidObjectStoragePath(Exception): # pragma: no cover
|
@@ -33,6 +39,8 @@ class ObjectStorageDetails:
|
|
33
39
|
The Object Storage namespace. Will be extracted automatically if not provided.
|
34
40
|
filepath: (str, optional). Defaults to empty string.
|
35
41
|
The path to the object.
|
42
|
+
version: (str, optional). Defaults to None.
|
43
|
+
The version of the object.
|
36
44
|
auth: (Dict, optional). Defaults to None.
|
37
45
|
ADS auth dictionary for OCI authentication.
|
38
46
|
This can be generated by calling ads.common.auth.api_keys() or ads.common.auth.resource_principal()
|
@@ -42,6 +50,7 @@ class ObjectStorageDetails:
|
|
42
50
|
bucket: str
|
43
51
|
namespace: str = ""
|
44
52
|
filepath: str = ""
|
53
|
+
version: str = None
|
45
54
|
auth: Dict = None
|
46
55
|
|
47
56
|
def __post_init__(self):
|
@@ -49,8 +58,16 @@ class ObjectStorageDetails:
|
|
49
58
|
self.auth = authutil.default_signer()
|
50
59
|
# Extract OS namespace if not provided.
|
51
60
|
if not self.namespace:
|
52
|
-
|
53
|
-
|
61
|
+
self.namespace = self.os_client.get_namespace().data
|
62
|
+
|
63
|
+
@property
|
64
|
+
def os_client(self):
|
65
|
+
if not hasattr(self, "__client"):
|
66
|
+
self.__client = self.create_os_client()
|
67
|
+
return self.__client
|
68
|
+
|
69
|
+
def create_os_client(self):
|
70
|
+
return oci_client.OCIClientFactory(**self.auth).object_storage
|
54
71
|
|
55
72
|
def __repr__(self):
|
56
73
|
return self.path
|
@@ -86,7 +103,7 @@ class ObjectStorageDetails:
|
|
86
103
|
url_parse = urlparse(env_path)
|
87
104
|
bucket_name = url_parse.username
|
88
105
|
namespace = url_parse.hostname
|
89
|
-
object_name = url_parse.path.
|
106
|
+
object_name = url_parse.path.lstrip("/")
|
90
107
|
return cls(bucket=bucket_name, namespace=namespace, filepath=object_name)
|
91
108
|
except:
|
92
109
|
raise Exception(
|
@@ -106,8 +123,7 @@ class ObjectStorageDetails:
|
|
106
123
|
Dict
|
107
124
|
The metadata in dictionary format.
|
108
125
|
"""
|
109
|
-
|
110
|
-
res = os_client.get_object(self.namespace, self.bucket, self.filepath)
|
126
|
+
res = self.os_client.get_object(self.namespace, self.bucket, self.filepath)
|
111
127
|
metadata = res.data.headers["opc-meta-manifest"]
|
112
128
|
metadata_json = json.loads(metadata)
|
113
129
|
return metadata_json
|
@@ -138,3 +154,146 @@ class ObjectStorageDetails:
|
|
138
154
|
if not uri:
|
139
155
|
return False
|
140
156
|
return uri.lower().startswith("oci://")
|
157
|
+
|
158
|
+
def is_bucket_versioned(self) -> bool:
|
159
|
+
"""Check if the given bucket is versioned.
|
160
|
+
Returns
|
161
|
+
-------
|
162
|
+
bool: return True if the bucket is versioned.
|
163
|
+
|
164
|
+
"""
|
165
|
+
res = self.os_client.get_bucket(
|
166
|
+
namespace_name=self.namespace, bucket_name=self.bucket
|
167
|
+
).data
|
168
|
+
return res.versioning == "Enabled"
|
169
|
+
|
170
|
+
def list_objects(self, **kwargs):
|
171
|
+
"""Lists objects in a given oss path
|
172
|
+
|
173
|
+
Parameters
|
174
|
+
-------
|
175
|
+
**kwargs:
|
176
|
+
namespace, bucket, filepath are set by the class. By default, fields gets all values. For other supported
|
177
|
+
parameters, check https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/ListObjects
|
178
|
+
|
179
|
+
Returns
|
180
|
+
-------
|
181
|
+
Object of type oci.object_storage.models.ListObjects
|
182
|
+
"""
|
183
|
+
fields = kwargs.pop(
|
184
|
+
"fields",
|
185
|
+
"name,etag,size,timeCreated,md5,timeModified,storageTier,archivalState",
|
186
|
+
)
|
187
|
+
|
188
|
+
objects = oci.pagination.list_call_get_all_results(
|
189
|
+
self.os_client.list_objects,
|
190
|
+
namespace_name=self.namespace,
|
191
|
+
bucket_name=self.bucket,
|
192
|
+
prefix=self.filepath,
|
193
|
+
fields=fields,
|
194
|
+
**kwargs,
|
195
|
+
).data
|
196
|
+
return objects
|
197
|
+
|
198
|
+
def list_object_versions(
|
199
|
+
self,
|
200
|
+
**kwargs,
|
201
|
+
):
|
202
|
+
"""Lists object versions in a given oss path
|
203
|
+
|
204
|
+
Parameters
|
205
|
+
-------
|
206
|
+
**kwargs:
|
207
|
+
namespace, bucket, filepath are set by the class. By default, fields gets all values. For other supported
|
208
|
+
parameters, check https://docs.oracle.com/iaas/api/#/en/objectstorage/20160918/Object/ListObjectVersions
|
209
|
+
|
210
|
+
Returns
|
211
|
+
-------
|
212
|
+
Object of type oci.object_storage.models.ObjectVersionCollection
|
213
|
+
"""
|
214
|
+
fields = kwargs.pop(
|
215
|
+
"fields",
|
216
|
+
"name,etag,size,timeCreated,md5,timeModified,storageTier,archivalState",
|
217
|
+
)
|
218
|
+
|
219
|
+
objects = oci.pagination.list_call_get_all_results(
|
220
|
+
self.os_client.list_object_versions,
|
221
|
+
namespace_name=self.namespace,
|
222
|
+
bucket_name=self.bucket,
|
223
|
+
prefix=self.filepath,
|
224
|
+
fields=fields,
|
225
|
+
**kwargs,
|
226
|
+
).data
|
227
|
+
return objects
|
228
|
+
|
229
|
+
def download_from_object_storage(
|
230
|
+
self,
|
231
|
+
path: "ObjectStorageDetails",
|
232
|
+
target_dir: str,
|
233
|
+
progress_bar: TqdmProgressBar = None,
|
234
|
+
):
|
235
|
+
"""Downloads the files with object versions set in the paths dict.
|
236
|
+
|
237
|
+
Parameters
|
238
|
+
----------
|
239
|
+
path:
|
240
|
+
OSS path along with a value of file version id.
|
241
|
+
If version_id is not available, download the latest version.
|
242
|
+
target_dir:
|
243
|
+
Local directory to save the files
|
244
|
+
progress_bar:
|
245
|
+
an instance of the TqdmProgressBar, can update description in the calling progress bar
|
246
|
+
|
247
|
+
Returns
|
248
|
+
-------
|
249
|
+
None
|
250
|
+
"""
|
251
|
+
if progress_bar:
|
252
|
+
progress_bar.update(
|
253
|
+
description=f"Copying model artifacts by reference from {path.path} to {target_dir}",
|
254
|
+
n=0,
|
255
|
+
)
|
256
|
+
res = self.os_client.get_object(
|
257
|
+
namespace_name=path.namespace,
|
258
|
+
bucket_name=path.bucket,
|
259
|
+
object_name=path.filepath,
|
260
|
+
version_id=path.version,
|
261
|
+
)
|
262
|
+
local_filepath = os.path.join(target_dir, path.bucket, path.filepath)
|
263
|
+
os.makedirs(os.path.dirname(local_filepath), exist_ok=True)
|
264
|
+
|
265
|
+
with open(local_filepath, "wb") as _file:
|
266
|
+
for chunk in res.data.iter_content(chunk_size=4096):
|
267
|
+
_file.write(chunk)
|
268
|
+
|
269
|
+
def bulk_download_from_object_storage(
|
270
|
+
self,
|
271
|
+
paths: List["ObjectStorageDetails"],
|
272
|
+
target_dir: str,
|
273
|
+
progress_bar: TqdmProgressBar = None,
|
274
|
+
):
|
275
|
+
"""Downloads the files with object versions set in the paths dict parallely.
|
276
|
+
|
277
|
+
Parameters
|
278
|
+
----------
|
279
|
+
paths:
|
280
|
+
Contains a list of OSS paths along with a value of file version id.
|
281
|
+
If version_id is not available, download the latest version.
|
282
|
+
target_dir:
|
283
|
+
Local directory to save the files
|
284
|
+
progress_bar:
|
285
|
+
an instance of the TqdmProgressBar, can update description in the calling progress bar
|
286
|
+
|
287
|
+
Returns
|
288
|
+
-------
|
289
|
+
None
|
290
|
+
"""
|
291
|
+
with ThreadPoolExecutor(max_workers=THREAD_POOL_MAX_WORKERS) as pool:
|
292
|
+
futures = {
|
293
|
+
pool.submit(
|
294
|
+
self.download_from_object_storage, path, target_dir, progress_bar
|
295
|
+
): path
|
296
|
+
for path in paths
|
297
|
+
}
|
298
|
+
for future in as_completed(futures):
|
299
|
+
future.result()
|
ads/common/oci_client.py
CHANGED
@@ -20,12 +20,14 @@ from oci.object_storage import ObjectStorageClient
|
|
20
20
|
from oci.resource_search import ResourceSearchClient
|
21
21
|
from oci.secrets import SecretsClient
|
22
22
|
from oci.vault import VaultsClient
|
23
|
+
from oci.logging import LoggingManagementClient
|
24
|
+
from oci.core import VirtualNetworkClient
|
25
|
+
from oci.limits import LimitsClient
|
23
26
|
|
24
27
|
logger = logging.getLogger(__name__)
|
25
28
|
|
26
29
|
|
27
30
|
class OCIClientFactory:
|
28
|
-
|
29
31
|
"""
|
30
32
|
A factory class to create OCI client objects. The constructor takes in config, signer and client_kwargs. `client_kwargs` is passed
|
31
33
|
to the client constructor as key word arguments.
|
@@ -72,6 +74,9 @@ class OCIClientFactory:
|
|
72
74
|
"data_labeling_cp": DataLabelingManagementClient,
|
73
75
|
"resource_search": ResourceSearchClient,
|
74
76
|
"data_catalog": DataCatalogClient,
|
77
|
+
"logging_management": LoggingManagementClient,
|
78
|
+
"virtual_network": VirtualNetworkClient,
|
79
|
+
"limits": LimitsClient,
|
75
80
|
"marketplace": MarketplaceClient,
|
76
81
|
"artifacts": ArtifactsClient,
|
77
82
|
}
|
@@ -149,6 +154,18 @@ class OCIClientFactory:
|
|
149
154
|
def data_catalog(self):
|
150
155
|
return self.create_client("data_catalog")
|
151
156
|
|
157
|
+
@property
|
158
|
+
def logging_management(self):
|
159
|
+
return self.create_client("logging_management")
|
160
|
+
|
161
|
+
@property
|
162
|
+
def virtual_network(self):
|
163
|
+
return self.create_client("virtual_network")
|
164
|
+
|
165
|
+
@property
|
166
|
+
def limits(self):
|
167
|
+
return self.create_client("limits")
|
168
|
+
|
152
169
|
@property
|
153
170
|
def marketplace(self):
|
154
171
|
return self.create_client("marketplace")
|
ads/common/oci_logging.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# -*- coding: utf-8; -*-
|
3
3
|
|
4
|
-
# Copyright (c) 2021,
|
4
|
+
# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
7
|
import datetime
|
@@ -384,7 +384,7 @@ class OCILog(OCILoggingModelMixin, oci.logging.models.Log):
|
|
384
384
|
records = []
|
385
385
|
result_too_large = True
|
386
386
|
else:
|
387
|
-
raise
|
387
|
+
raise ex
|
388
388
|
if result_too_large or len(records) >= LIMIT_PER_REQUEST:
|
389
389
|
mid = time_start + (time_end - time_start) / 2
|
390
390
|
# The log search API used RFC3339 time format.
|
ads/common/oci_mixin.py
CHANGED
@@ -798,14 +798,13 @@ class OCIModelMixin(OCISerializableMixin):
|
|
798
798
|
logger.error(
|
799
799
|
"Failed to synchronize the properties of %s due to service error:\n%s",
|
800
800
|
self.__class__,
|
801
|
-
|
801
|
+
traceback.format_exc(),
|
802
802
|
)
|
803
|
-
except Exception
|
803
|
+
except Exception:
|
804
804
|
logger.error(
|
805
|
-
"Failed to synchronize the properties of %s
|
805
|
+
"Failed to synchronize the properties of %s.\n%s",
|
806
806
|
self.__class__,
|
807
|
-
|
808
|
-
str(ex),
|
807
|
+
traceback.format_exc(),
|
809
808
|
)
|
810
809
|
return super().__getattribute__(name)
|
811
810
|
|
ads/common/serializer.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# -*- coding: utf-8; -*-
|
3
3
|
|
4
|
-
# Copyright (c) 2021,
|
4
|
+
# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
7
|
"""
|
@@ -13,6 +13,7 @@ writing serialized objects to and from files.
|
|
13
13
|
import dataclasses
|
14
14
|
import json
|
15
15
|
from abc import ABC, abstractmethod
|
16
|
+
from datetime import datetime
|
16
17
|
from enum import Enum
|
17
18
|
from typing import Dict, Optional, Union
|
18
19
|
from urllib.parse import urlparse
|
@@ -93,6 +94,13 @@ class Serializable(ABC):
|
|
93
94
|
"""
|
94
95
|
pass
|
95
96
|
|
97
|
+
@staticmethod
|
98
|
+
def serialize(obj):
|
99
|
+
"""JSON serializer for objects not serializable by default json code."""
|
100
|
+
if isinstance(obj, datetime):
|
101
|
+
return obj.isoformat()
|
102
|
+
raise TypeError(f"Type {type(obj)} not serializable.")
|
103
|
+
|
96
104
|
@staticmethod
|
97
105
|
def _write_to_file(s: str, uri: str, **kwargs) -> None:
|
98
106
|
"""Write string s into location specified by uri.
|
@@ -153,7 +161,11 @@ class Serializable(ABC):
|
|
153
161
|
return f.read()
|
154
162
|
|
155
163
|
def to_json(
|
156
|
-
self,
|
164
|
+
self,
|
165
|
+
uri: str = None,
|
166
|
+
encoder: callable = json.JSONEncoder,
|
167
|
+
default: callable = None,
|
168
|
+
**kwargs,
|
157
169
|
) -> str:
|
158
170
|
"""Returns object serialized as a JSON string
|
159
171
|
|
@@ -163,6 +175,9 @@ class Serializable(ABC):
|
|
163
175
|
URI location to save the JSON string. Defaults to None.
|
164
176
|
encoder: (callable, optional)
|
165
177
|
Encoder for custom data structures. Defaults to JSONEncoder.
|
178
|
+
default: (callable, optional)
|
179
|
+
A function that gets called for objects that can't otherwise be serialized.
|
180
|
+
It should return JSON-serializable version of the object or original object.
|
166
181
|
|
167
182
|
kwargs
|
168
183
|
------
|
@@ -179,7 +194,9 @@ class Serializable(ABC):
|
|
179
194
|
Serialized version of object.
|
180
195
|
`None` in case when `uri` provided.
|
181
196
|
"""
|
182
|
-
json_string = json.dumps(
|
197
|
+
json_string = json.dumps(
|
198
|
+
self.to_dict(**kwargs), cls=encoder, default=default or self.serialize
|
199
|
+
)
|
183
200
|
if uri:
|
184
201
|
self._write_to_file(s=json_string, uri=uri, **kwargs)
|
185
202
|
return None
|
@@ -337,13 +354,23 @@ class Serializable(ABC):
|
|
337
354
|
def __repr__(self):
|
338
355
|
"""Returns printable version of object.
|
339
356
|
|
340
|
-
|
357
|
+
Returns
|
341
358
|
----------
|
342
359
|
string
|
343
360
|
Serialized version of object as a YAML string
|
344
361
|
"""
|
345
362
|
return self.to_yaml()
|
346
363
|
|
364
|
+
def __str__(self):
|
365
|
+
"""Returns printable version of object.
|
366
|
+
|
367
|
+
Returns
|
368
|
+
----------
|
369
|
+
string
|
370
|
+
Serialized version of object as a YAML string
|
371
|
+
"""
|
372
|
+
return self.to_json()
|
373
|
+
|
347
374
|
|
348
375
|
class DataClassSerializable(Serializable):
|
349
376
|
"""Wrapper class that inherit from Serializable class.
|
@@ -436,7 +463,9 @@ class DataClassSerializable(Serializable):
|
|
436
463
|
"These fields will be ignored."
|
437
464
|
)
|
438
465
|
|
439
|
-
obj = cls(
|
466
|
+
obj = cls(
|
467
|
+
**{key: obj_dict.get(key) for key in allowed_fields if key in obj_dict}
|
468
|
+
)
|
440
469
|
|
441
470
|
for key, value in obj_dict.items():
|
442
471
|
if (
|
ads/common/utils.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# -*- coding: utf-8; -*-
|
3
3
|
|
4
|
-
# Copyright (c) 2020,
|
4
|
+
# Copyright (c) 2020, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
7
|
from __future__ import absolute_import, print_function
|
@@ -33,29 +33,25 @@ import fsspec
|
|
33
33
|
import matplotlib as mpl
|
34
34
|
import numpy as np
|
35
35
|
import pandas as pd
|
36
|
-
from ads.common import logger
|
37
|
-
from ads.common.decorator.deprecate import deprecated
|
38
|
-
from ads.common.word_lists import adjectives, animals
|
39
|
-
from ads.dataset.progress import TqdmProgressBar
|
40
36
|
from cycler import cycler
|
37
|
+
from oci import object_storage
|
41
38
|
from pandas.core.dtypes.common import is_datetime64_dtype, is_numeric_dtype
|
42
39
|
from sklearn.model_selection import train_test_split
|
43
40
|
from tqdm import tqdm
|
44
41
|
|
42
|
+
from ads import config
|
45
43
|
from ads.common import logger
|
46
44
|
from ads.common.decorator.deprecate import deprecated
|
47
45
|
from ads.common.decorator.runtime_dependency import (
|
48
46
|
OptionalDependency,
|
49
47
|
runtime_dependency,
|
50
48
|
)
|
49
|
+
from ads.common.object_storage_details import ObjectStorageDetails
|
50
|
+
from ads.common.oci_client import OCIClientFactory
|
51
51
|
from ads.common.word_lists import adjectives, animals
|
52
|
-
from ads import
|
53
|
-
from ads.dataset.progress import DummyProgressBar, TqdmProgressBar
|
52
|
+
from ads.dataset.progress import TqdmProgressBar
|
54
53
|
|
55
54
|
from . import auth as authutil
|
56
|
-
from oci import object_storage
|
57
|
-
from ads.common.oci_client import OCIClientFactory
|
58
|
-
from ads.common.object_storage_details import ObjectStorageDetails
|
59
55
|
|
60
56
|
# For Model / Model Artifact libraries
|
61
57
|
lib_translator = {"sklearn": "scikit-learn"}
|
@@ -1717,3 +1713,72 @@ def upload_to_os(
|
|
1717
1713
|
)
|
1718
1714
|
|
1719
1715
|
return response
|
1716
|
+
|
1717
|
+
|
1718
|
+
def get_console_link(
|
1719
|
+
resource: str,
|
1720
|
+
ocid: str,
|
1721
|
+
region: str,
|
1722
|
+
) -> str:
|
1723
|
+
"""
|
1724
|
+
This method returns the web console link for the given resource.
|
1725
|
+
Parameters
|
1726
|
+
----------
|
1727
|
+
resource: str
|
1728
|
+
identify the type of OCI resource. {model, model-deployments, notebook-sessions, jobs} is supported.
|
1729
|
+
ocid: str
|
1730
|
+
OCID of the resource
|
1731
|
+
region: str
|
1732
|
+
The Region Identifier that the client should connect to.
|
1733
|
+
|
1734
|
+
Returns
|
1735
|
+
-------
|
1736
|
+
console_link_url: str
|
1737
|
+
a valid link to the console for the given resource
|
1738
|
+
"""
|
1739
|
+
console_link_url = (
|
1740
|
+
f"https://cloud.oracle.com/data-science/{resource}/{ocid}?region={region}"
|
1741
|
+
)
|
1742
|
+
return console_link_url
|
1743
|
+
|
1744
|
+
|
1745
|
+
def get_log_links(
|
1746
|
+
region: str,
|
1747
|
+
log_group_id: str,
|
1748
|
+
compartment_id: str = None,
|
1749
|
+
log_id: str = None,
|
1750
|
+
source_id: str = None,
|
1751
|
+
) -> str:
|
1752
|
+
"""
|
1753
|
+
This method returns the web console link for the given log ids.
|
1754
|
+
|
1755
|
+
Parameters
|
1756
|
+
----------
|
1757
|
+
log_group_id: str, required
|
1758
|
+
OCID of the resource
|
1759
|
+
log_id: str, optional
|
1760
|
+
OCID of the resource
|
1761
|
+
region: str
|
1762
|
+
The Region Identifier that the client should connect to.
|
1763
|
+
compartment_id: str, optional
|
1764
|
+
The compartment OCID of the resource.
|
1765
|
+
source_id: str, optional
|
1766
|
+
The OCID of the resource.
|
1767
|
+
|
1768
|
+
Returns
|
1769
|
+
-------
|
1770
|
+
console_link_url: str
|
1771
|
+
a valid link to the console for the given resource.
|
1772
|
+
"""
|
1773
|
+
console_link_url = ""
|
1774
|
+
if log_group_id and log_id:
|
1775
|
+
# format: https://cloud.oracle.com/logging/search?searchQuery=search "<compartment>/<log_group>/<log>" | source='<source>' | sort by datetime desc®ions=<region>
|
1776
|
+
query_range = f'''search "{compartment_id}/{log_group_id}/{log_id}"'''
|
1777
|
+
query_source = f"source='{source_id}'"
|
1778
|
+
sort_condition = f"sort by datetime desc®ions={region}"
|
1779
|
+
search_query = f"search?searchQuery={query_range} | {query_source} | {sort_condition}"
|
1780
|
+
console_link_url = f"https://cloud.oracle.com/logging/{search_query}"
|
1781
|
+
elif log_group_id:
|
1782
|
+
console_link_url = f"https://cloud.oracle.com/logging/log-groups/{log_group_id}?region={region}"
|
1783
|
+
|
1784
|
+
return console_link_url
|