Skip to content

Commit b450ef1

Browse files
committed
Merge commit '16bb56d887c8b95ccb5f2e281aecb1ac7b392572'
2 parents 9e62306 + 16bb56d commit b450ef1

File tree

204 files changed

+15491
-726
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

204 files changed

+15491
-726
lines changed

.github/workflows/run-unittests-py38-cov-report.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ jobs:
6161
name: "Test env setup"
6262
timeout-minutes: 20
6363

64+
# Installing forecast deps for python3.8 test setup only, it will not work with python3.9/3.10, because
65+
# automlx do not support py3.9 and some versions of py3.10. This step omitted in -py39-py30.yml workflow
66+
- name: "Install Forecasting dependencies"
67+
run: |
68+
pip install -e ".[forecast]"
69+
6470
- name: "Run unitary tests folder with maximum ADS dependencies"
6571
timeout-minutes: 60
6672
shell: bash

.github/workflows/run-unittests-py39-py310.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
test-path: ["tests/unitary/with_extras tests/unitary/default_setup", "tests/unitary/with_extras/model"]
3737
include:
3838
- test-path: "tests/unitary/with_extras tests/unitary/default_setup"
39-
ignore-path: "--ignore tests/unitary/with_extras/model --ignore tests/unitary/with_extras/feature_store"
39+
ignore-path: "--ignore tests/unitary/with_extras/model --ignore tests/unitary/with_extras/feature_store --ignore tests/unitary/with_extras/operator/forecast"
4040
name: "unitary"
4141
- test-path: "tests/unitary/with_extras/model"
4242
name: "model"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,6 @@ logs/
160160

161161
# vim
162162
*.swp
163+
164+
# Python Wheel
165+
*.whl

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@ exclude build/lib/notebooks/**
2424
exclude benchmark/**
2525
include ads/ads
2626
include ads/model/common/*.*
27+
include ads/operator/**/*.md
28+
include ads/operator/**/*.yaml
29+
include ads/operator/**/*.whl
30+
include ads/operator/**/MLoperator

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ You have various options when installing ADS.
2727
python3 -m pip install oracle-ads
2828
```
2929

30+
### Installing OCI AI Operators
31+
32+
To use the AI Forecast Operator, install the "forecast" dependencies using the following command:
33+
34+
```bash
35+
python3 -m pip install 'oracle_ads[forecast]==2.9.0'
36+
```
37+
3038
### Installing extras libraries
3139

3240
To work with gradient boosting models, install the `boosted` module. This module includes XGBoost and LightGBM model classes.

ads/cli.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
import ads.opctl.cli
1515
import ads.jobs.cli
1616
import ads.pipeline.cli
17-
import os
18-
import json
17+
import ads.opctl.operator.cli
1918
except Exception as ex:
2019
print(
2120
"Please run `pip install oracle-ads[opctl]` to install "
22-
"the required dependencies for ADS CLI."
21+
"the required dependencies for ADS CLI. \n"
22+
f"{str(ex)}"
2323
)
2424
logger.debug(ex)
2525
logger.debug(traceback.format_exc())
@@ -44,6 +44,7 @@ def cli():
4444
cli.add_command(ads.opctl.cli.commands)
4545
cli.add_command(ads.jobs.cli.commands)
4646
cli.add_command(ads.pipeline.cli.commands)
47+
cli.add_command(ads.opctl.operator.cli.commands)
4748

4849

4950
if __name__ == "__main__":

ads/common/auth.py

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -629,8 +629,8 @@ def create_signer(self) -> Dict:
629629
user=configuration["user"],
630630
fingerprint=configuration["fingerprint"],
631631
private_key_file_location=configuration.get("key_file"),
632-
pass_phrase= configuration.get("pass_phrase"),
633-
private_key_content=configuration.get("key_content")
632+
pass_phrase=configuration.get("pass_phrase"),
633+
private_key_content=configuration.get("key_content"),
634634
),
635635
"client_kwargs": self.client_kwargs,
636636
}
@@ -750,21 +750,10 @@ class SecurityToken(AuthSignerGenerator):
750750
a given user - it requires that user's private key and security token.
751751
It prepares extra arguments necessary for creating clients for variety of OCI services.
752752
"""
753-
SECURITY_TOKEN_GENERIC_HEADERS = [
754-
"date",
755-
"(request-target)",
756-
"host"
757-
]
758-
SECURITY_TOKEN_BODY_HEADERS = [
759-
"content-length",
760-
"content-type",
761-
"x-content-sha256"
762-
]
763-
SECURITY_TOKEN_REQUIRED = [
764-
"security_token_file",
765-
"key_file",
766-
"region"
767-
]
753+
754+
SECURITY_TOKEN_GENERIC_HEADERS = ["date", "(request-target)", "host"]
755+
SECURITY_TOKEN_BODY_HEADERS = ["content-length", "content-type", "x-content-sha256"]
756+
SECURITY_TOKEN_REQUIRED = ["security_token_file", "key_file", "region"]
768757

769758
def __init__(self, args: Optional[Dict] = None):
770759
"""
@@ -831,12 +820,18 @@ def create_signer(self) -> Dict:
831820
return {
832821
"config": configuration,
833822
"signer": oci.auth.signers.SecurityTokenSigner(
834-
token=self._read_security_token_file(configuration.get("security_token_file")),
823+
token=self._read_security_token_file(
824+
configuration.get("security_token_file")
825+
),
835826
private_key=oci.signer.load_private_key_from_file(
836827
configuration.get("key_file"), configuration.get("pass_phrase")
837828
),
838-
generic_headers=configuration.get("generic_headers", self.SECURITY_TOKEN_GENERIC_HEADERS),
839-
body_headers=configuration.get("body_headers", self.SECURITY_TOKEN_BODY_HEADERS)
829+
generic_headers=configuration.get(
830+
"generic_headers", self.SECURITY_TOKEN_GENERIC_HEADERS
831+
),
832+
body_headers=configuration.get(
833+
"body_headers", self.SECURITY_TOKEN_BODY_HEADERS
834+
),
840835
),
841836
"client_kwargs": self.client_kwargs,
842837
}
@@ -849,30 +844,37 @@ def _validate_and_refresh_token(self, configuration: Dict[str, Any]):
849844
configuration: Dict
850845
Security token configuration.
851846
"""
852-
security_token = self._read_security_token_file(configuration.get("security_token_file"))
853-
security_token_container = oci.auth.security_token_container.SecurityTokenContainer(
854-
session_key_supplier=None,
855-
security_token=security_token
847+
security_token = self._read_security_token_file(
848+
configuration.get("security_token_file")
849+
)
850+
security_token_container = (
851+
oci.auth.security_token_container.SecurityTokenContainer(
852+
session_key_supplier=None, security_token=security_token
853+
)
856854
)
857855

858856
if not security_token_container.valid():
859857
raise SecurityTokenError(
860858
"Security token has expired. Call `oci session authenticate` to generate new session."
861859
)
862-
860+
863861
time_now = int(time.time())
864862
time_expired = security_token_container.get_jwt()["exp"]
865863
if time_expired - time_now < SECURITY_TOKEN_LEFT_TIME:
866864
if not self.oci_config_location:
867-
logger.warning("Can not auto-refresh token. Specify parameter `oci_config_location` through ads.set_auth() or ads.auth.create_signer().")
865+
logger.warning(
866+
"Can not auto-refresh token. Specify parameter `oci_config_location` through ads.set_auth() or ads.auth.create_signer()."
867+
)
868868
else:
869-
result = os.system(f"oci session refresh --config-file {self.oci_config_location} --profile {self.oci_key_profile}")
869+
result = os.system(
870+
f"oci session refresh --config-file {self.oci_config_location} --profile {self.oci_key_profile}"
871+
)
870872
if result == 1:
871873
logger.warning(
872874
"Some error happened during auto-refreshing the token. Continue using the current one that's expiring in less than {SECURITY_TOKEN_LEFT_TIME} seconds."
873875
"Please follow steps in https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clitoken.htm to renew token."
874876
)
875-
877+
876878
date_time = datetime.fromtimestamp(time_expired).strftime("%Y-%m-%d %H:%M:%S")
877879
logger.info(f"Session is valid until {date_time}.")
878880

@@ -894,7 +896,7 @@ def _read_security_token_file(self, security_token_file: str) -> str:
894896
raise ValueError("Invalid `security_token_file`. Specify a valid path.")
895897
try:
896898
token = None
897-
with open(expanded_path, 'r') as f:
899+
with open(expanded_path, "r") as f:
898900
token = f.read()
899901
return token
900902
except:
@@ -903,7 +905,7 @@ def _read_security_token_file(self, security_token_file: str) -> str:
903905

904906
class AuthFactory:
905907
"""
906-
AuthFactory class which contains list of registered signers and alllows to register new signers.
908+
AuthFactory class which contains list of registered signers and allows to register new signers.
907909
Check documentation for more signers: https://docs.oracle.com/en-us/iaas/tools/python/latest/api/signing.html.
908910
909911
Current signers:

ads/common/decorator/runtime_dependency.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class OptionalDependency:
6464
OPTUNA = "oracle-ads[optuna]"
6565
SPARK = "oracle-ads[spark]"
6666
HUGGINGFACE = "oracle-ads[huggingface]"
67+
FORECAST = "oracle-ads[forecast]"
68+
PII = "oracle-ads[pii]"
6769
FEATURE_STORE = "oracle-ads[feature-store]"
6870
GRAPHVIZ = "oracle-ads[graphviz]"
6971
MLM_INSIGHTS = "oracle-ads[mlm_insights]"

ads/common/object_storage_details.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*--
33

4-
# Copyright (c) 2021, 2022 Oracle and/or its affiliates.
4+
# Copyright (c) 2021, 2023 Oracle and/or its affiliates.
55
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
66

77
import json
@@ -15,7 +15,7 @@
1515
from ads.common import oci_client
1616

1717

18-
class InvalidObjectStoragePath(Exception): # pragma: no cover
18+
class InvalidObjectStoragePath(Exception): # pragma: no cover
1919
"""Invalid Object Storage Path."""
2020

2121
pass
@@ -137,4 +137,4 @@ def is_oci_path(uri: str = None) -> bool:
137137
"""
138138
if not uri:
139139
return False
140-
return uri.startswith("oci://")
140+
return uri.lower().startswith("oci://")

0 commit comments

Comments
 (0)