Skip to content

Commit

Permalink
Merge pull request #14 from oracle/2.6.x
Browse files Browse the repository at this point in the history
Release version 2.6.6
  • Loading branch information
mrDzurb authored Oct 8, 2022
2 parents e123f56 + 2f117bb commit 3226228
Show file tree
Hide file tree
Showing 236 changed files with 16,927 additions and 2,305 deletions.
16 changes: 8 additions & 8 deletions ads/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@
import os
import logging
import sys
import json

__version__ = ""
with open(
os.path.join(os.path.dirname(os.path.abspath(__file__)), "ads_version.json")
) as version_file:
__version__ = json.load(version_file)["version"]
import oci

import matplotlib.font_manager # causes matplotlib to regenerate its fonts
import json

import ocifs
from ads.common.decorator.deprecate import deprecated
from ads.common.ipython import configure_plotting, _log_traceback
from ads.feature_engineering.accessor.series_accessor import ADSSeriesAccessor
from ads.feature_engineering.accessor.dataframe_accessor import ADSDataFrameAccessor

from ads.common import auth

os.environ["GIT_PYTHON_REFRESH"] = "quiet"

__version__ = ""
with open(
os.path.join(os.path.dirname(os.path.abspath(__file__)), "ads_version.json")
) as version_file:
__version__ = json.load(version_file)["version"]

debug_mode = os.environ.get("DEBUG_MODE", False)
documentation_mode = os.environ.get("DOCUMENTATION_MODE", "False") == "True"
Expand Down Expand Up @@ -64,7 +64,7 @@ def set_auth(
oci_config_path = oci_config_location
else:
logging.warning(
f"{oci_config_location} file not exists, default value oci.config.DEFAULT_LOCATION used instead"
f"{oci_config_location} file does not exist, default value oci.config.DEFAULT_LOCATION used instead"
)
oci_config_path = oci.config.DEFAULT_LOCATION
elif auth == "resource_principal":
Expand Down
2 changes: 1 addition & 1 deletion ads/ads_version.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "2.6.5"
"version": "2.6.6"
}
18 changes: 11 additions & 7 deletions ads/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@

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

import click
import ads.opctl.cli
import ads.jobs.cli
import os
import json

try:
import click
import ads.opctl.cli
import ads.jobs.cli
import os
import json
except:
print(
"Please run `pip install oracle-ads[opctl]` to install the required dependencies for ADS CLI"
)
exit()
with open(
os.path.join(os.path.dirname(os.path.abspath(__file__)), "ads_version.json")
) as version_file:
Expand Down
2 changes: 2 additions & 0 deletions ads/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
import logging

logger = logging.getLogger(__name__)

from ads.common import auth
9 changes: 7 additions & 2 deletions ads/common/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import oci
import os
from ads.common import utils
import ads.telemetry


def api_keys(
Expand Down Expand Up @@ -42,7 +43,9 @@ def api_keys(
>>> auth = authutil.api_keys(oci_config="/home/datascience/.oci/config", profile="TEST", client_kwargs={"timeout": 6000})
>>> oc.OCIClientFactory(**auth).object_storage # Creates Object storage client with timeout set to 6000 using API Key authentication
"""
configuration = oci.config.from_file(oci_config, profile)
configuration = ads.telemetry.update_oci_client_config(
oci.config.from_file(oci_config, profile)
)
return {
"config": configuration,
"signer": oci.signer.Signer(
Expand Down Expand Up @@ -82,8 +85,10 @@ def resource_principal(client_kwargs=None):
>>> oc.OCIClientFactory(**auth).object_storage # Creates Object Storage client with timeout set to 6000 seconds using resource principal authentication
"""

configuration = ads.telemetry.update_oci_client_config()

return {
"config": {},
"config": configuration,
"signer": oci.auth.signers.get_resource_principals_signer(),
"client_kwargs": client_kwargs,
}
Expand Down
18 changes: 14 additions & 4 deletions ads/common/base_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import dataclasses
import json
import os
from typing import Any, Dict, Optional
from typing import Any, Dict, Optional, Union

from ads.common.config import Config, ConfigSection
from ads.common.serializer import Serializable
Expand Down Expand Up @@ -42,11 +42,21 @@ def __setattr__(self, name: str, value: Any):
if value is None:
self.__dict__[name] = value
elif name in self.__annotations__:
if self.__annotations__[name] != type(value):
if hasattr(self.__annotations__[name], "__origin__"):
if self.__annotations__[name].__origin__ is Union and not isinstance(
value, self.__annotations__[name].__args__
):
raise TypeError(
f"Field `{name}` was expected to be of type `{self.__annotations__[name].__args__}` "
f"but type `{type(value)}` was provided."
)

elif self.__annotations__[name] != type(value):
raise TypeError(
f"Field `{name}` was expected to be of type `{self.__annotations__[name].__name__}` "
f"but type `{type(value).__name__}` was provided."
f"Field `{name}` was expected to be of type `{self.__annotations__[name]}` "
f"but type `{type(value)}` was provided."
)

self.__dict__[name] = value

def with_prop(self, name: str, value: Any) -> "BaseProperties":
Expand Down
117 changes: 117 additions & 0 deletions ads/common/data_serializer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python
# -*- coding: utf-8; -*-

# Copyright (c) 2022 Oracle and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/

from __future__ import absolute_import, print_function

import base64
from io import BytesIO
from typing import Dict, List, Union
import requests
import json
import numpy as np
import pandas as pd

DEFAULT_CONTENT_TYPE_JSON = "application/json"
DEFAULT_CONTENT_TYPE_BYTES = "application/octet-stream"


class InputDataSerializer:
"""[An internal class]
Defines the contract for input data
"""

def __init__(
self,
data: Union[
Dict,
str,
List,
np.ndarray,
pd.core.series.Series,
pd.core.frame.DataFrame,
],
data_type=None,
):
"""
Parameters
----------
data: Union[Dict, str, list, numpy.ndarray, pd.core.series.Series,
pd.core.frame.DataFrame]
Data expected by the model deployment predict API.
data_type: Any, defaults to None.
Type of the data. If not provided, it will be checked against data.
"""
if not data_type:
data_type = type(data)
if isinstance(data, np.ndarray):
np_bytes = BytesIO()
np.save(np_bytes, data, allow_pickle=True)
data = base64.b64encode(np_bytes.getvalue()).decode("utf-8")
elif isinstance(data, pd.core.series.Series):
data = data.tolist()
elif isinstance(data, pd.core.frame.DataFrame):
data = data.to_json()
elif (
isinstance(data, dict)
or isinstance(data, str)
or isinstance(data, list)
or isinstance(data, tuple)
or isinstance(data, bytes)
):
pass
else:
raise TypeError(
"The provided data type is not json serializable. "
"The supported data types are Dict, str, list, "
"numpy.ndarray, pd.core.series.Series, "
"pd.core.frame.DataFrame. Please "
"convert to the supported data types first. "
)

self._data = data
self._data_type = str(data_type)

@property
def data(self):
return self._data

@property
def data_type(self):
return self._data_type

def to_dict(self):
return {
"data": self._data,
"data_type": self._data_type,
}

def is_bytes(self):
return "bytes" in self.data_type

def send(self, endpoint: str, dry_run: bool = False, **kwargs):
headers = dict()
if self.is_bytes():
headers["Content-Type"] = (
kwargs.get("content_type") or DEFAULT_CONTENT_TYPE_BYTES
)
request_kwargs = {"data": self.data} # should pass bytes when using data
else:
headers["Content-Type"] = (
kwargs.get("content_type") or DEFAULT_CONTENT_TYPE_JSON
)
request_kwargs = {"json": self.to_dict()}
request_kwargs["headers"] = headers
if dry_run:
request_kwargs["headers"]["Accept"] = "*/*"
req = requests.Request("POST", endpoint, **request_kwargs).prepare()
if self.is_bytes():
return req.body
return json.loads(req.body)
else:
request_kwargs["auth"] = kwargs.get("signer")
return requests.post(endpoint, **request_kwargs).json()
1 change: 1 addition & 0 deletions ads/common/decorator/runtime_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class OptionalDependency:
GEO = "oracle-ads[geo]"
ONNX = "oracle-ads[onnx]"
OPTUNA = "oracle-ads[optuna]"
SPARK = "oracle-ads[spark]"


def runtime_dependency(
Expand Down
48 changes: 36 additions & 12 deletions ads/common/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
runtime_dependency,
OptionalDependency,
)
from ads.common.decorator.deprecate import deprecated
from ads.common.utils import is_notebook
from ads.dataset.pipeline import TransformerPipeline
from distutils import dir_util
from sklearn.pipeline import Pipeline


Expand Down Expand Up @@ -171,14 +171,18 @@ def rename(self, name):
"""
self.name = name

@deprecated(
"2.6.6",
details="Use framework specific Model utility class for saving and deploying model saving and deploying. Check https://accelerated-data-science.readthedocs.io/en/latest/user_guide/model_registration/quick_start.html",
)
def predict(self, X):
"""
Runs the models predict function on some data
Parameters
----------
X: MLData
A MLData object which holds the examples to be predicted on.
X: ADSData
A ADSData object which holds the examples to be predicted on.
Returns
-------
Expand All @@ -202,8 +206,8 @@ def predict_proba(self, X):
Parameters
----------
X: MLData
A MLData object which holds the examples to be predicted on.
X: ADSData
A ADSData object which holds the examples to be predicted on.
Returns
-------
Expand All @@ -218,16 +222,20 @@ def predict_proba(self, X):
else:
return self.est.predict_proba(X)

@deprecated(
"2.6.6",
details="Use framework specific Model utility class for saving and deploying model saving and deploying. Check https://accelerated-data-science.readthedocs.io/en/latest/user_guide/model_registration/quick_start.html",
)
def score(self, X, y_true, score_fn=None):
"""
Scores a model according to a custom score function
Parameters
----------
X: MLData
A MLData object which holds the examples to be predicted on.
y_true: MLData
A MLData object which holds ground truth labels for the examples which are being predicted on.
X: ADSData
A ADSData object which holds the examples to be predicted on.
y_true: ADSData
A ADSData object which holds ground truth labels for the examples which are being predicted on.
score_fn: Scorer (callable)
A callable object that returns a score, usually created with sklearn.metrics.make_scorer().
Expand All @@ -250,6 +258,10 @@ def score(self, X, y_true, score_fn=None):
else:
return self.est.score(X, y_true)

@deprecated(
"2.6.6",
details="Use framework specific Model utility class for saving and deploying model saving and deploying. Check https://accelerated-data-science.readthedocs.io/en/latest/user_guide/model_registration/quick_start.html",
)
def summary(self):
"""
A summary of the ADSModel
Expand All @@ -274,14 +286,18 @@ def __repr__(self):
def __getattr__(self, item):
return getattr(self.est, item)

@deprecated(
"2.6.6",
details="Use framework specific Model utility class for saving and deploying model saving and deploying. Check https://accelerated-data-science.readthedocs.io/en/latest/user_guide/model_registration/quick_start.html",
)
def transform(self, X):
"""
Process some MLData through the selected ADSModel transformers
Process some ADSData through the selected ADSModel transformers
Parameters
----------
X: MLData
A MLData object which holds the examples to be transformed.
X: ADSData
A ADSData object which holds the examples to be transformed.
"""

if hasattr(X, "copy"):
Expand Down Expand Up @@ -310,6 +326,10 @@ def is_classifier(self):
"""
return hasattr(self, "classes_") and self.classes_ is not None

@deprecated(
"2.6.6",
details="Use framework specific Model utility class for saving and deploying model saving and deploying. Check https://accelerated-data-science.readthedocs.io/en/latest/user_guide/model_registration/quick_start.html",
)
def feature_names(self, X=None):
model_type = self._underlying_model
if model_type == "sklearn":
Expand Down Expand Up @@ -367,6 +387,10 @@ def __getstate__(self):
def __setstate__(self, state):
self.__dict__ = state

@deprecated(
"2.6.6",
details="Use framework specific Model utility class for saving and deploying model saving and deploying. Check https://accelerated-data-science.readthedocs.io/en/latest/user_guide/model_registration/quick_start.html",
)
def prepare(
self,
target_dir=None,
Expand Down
Loading

0 comments on commit 3226228

Please sign in to comment.