teradataml 20.0.0.5__py3-none-any.whl → 20.0.0.7__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.
Potentially problematic release.
This version of teradataml might be problematic. Click here for more details.
- teradataml/LICENSE-3RD-PARTY.pdf +0 -0
- teradataml/README.md +306 -0
- teradataml/__init__.py +1 -1
- teradataml/_version.py +1 -1
- teradataml/analytics/analytic_function_executor.py +162 -76
- teradataml/analytics/byom/__init__.py +1 -1
- teradataml/analytics/json_parser/__init__.py +2 -0
- teradataml/analytics/json_parser/analytic_functions_argument.py +95 -2
- teradataml/analytics/json_parser/metadata.py +22 -4
- teradataml/analytics/sqle/DecisionTreePredict.py +3 -2
- teradataml/analytics/sqle/NaiveBayesPredict.py +3 -2
- teradataml/analytics/sqle/__init__.py +3 -0
- teradataml/analytics/utils.py +59 -11
- teradataml/automl/__init__.py +2369 -464
- teradataml/automl/autodataprep/__init__.py +15 -0
- teradataml/automl/custom_json_utils.py +184 -112
- teradataml/automl/data_preparation.py +113 -58
- teradataml/automl/data_transformation.py +154 -53
- teradataml/automl/feature_engineering.py +113 -53
- teradataml/automl/feature_exploration.py +548 -25
- teradataml/automl/model_evaluation.py +260 -32
- teradataml/automl/model_training.py +399 -206
- teradataml/clients/auth_client.py +10 -6
- teradataml/clients/keycloak_client.py +165 -0
- teradataml/common/aed_utils.py +11 -2
- teradataml/common/bulk_exposed_utils.py +4 -2
- teradataml/common/constants.py +72 -2
- teradataml/common/exceptions.py +32 -0
- teradataml/common/garbagecollector.py +50 -21
- teradataml/common/messagecodes.py +73 -1
- teradataml/common/messages.py +27 -1
- teradataml/common/sqlbundle.py +25 -7
- teradataml/common/utils.py +210 -22
- teradataml/context/aed_context.py +16 -10
- teradataml/context/context.py +37 -9
- teradataml/data/Employee.csv +5 -0
- teradataml/data/Employee_Address.csv +4 -0
- teradataml/data/Employee_roles.csv +5 -0
- teradataml/data/JulesBelvezeDummyData.csv +100 -0
- teradataml/data/byom_example.json +5 -0
- teradataml/data/creditcard_data.csv +284618 -0
- teradataml/data/docs/byom/docs/ONNXSeq2Seq.py +255 -0
- teradataml/data/docs/sqle/docs_17_10/NGramSplitter.py +1 -1
- teradataml/data/docs/sqle/docs_17_20/NGramSplitter.py +1 -1
- teradataml/data/docs/sqle/docs_17_20/TextParser.py +1 -1
- teradataml/data/jsons/byom/ONNXSeq2Seq.json +287 -0
- teradataml/data/jsons/byom/onnxembeddings.json +1 -0
- teradataml/data/jsons/sqle/20.00/AI_AnalyzeSentiment.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_AskLLM.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_DetectLanguage.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_ExtractKeyPhrases.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_MaskPII.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_RecognizeEntities.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_RecognizePIIEntities.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_TextClassifier.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_TextEmbeddings.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_TextSummarize.json +3 -7
- teradataml/data/jsons/sqle/20.00/AI_TextTranslate.json +3 -7
- teradataml/data/jsons/sqle/20.00/TD_API_AzureML.json +151 -0
- teradataml/data/jsons/sqle/20.00/TD_API_Sagemaker.json +182 -0
- teradataml/data/jsons/sqle/20.00/TD_API_VertexAI.json +183 -0
- teradataml/data/load_example_data.py +29 -11
- teradataml/data/pattern_matching_data.csv +11 -0
- teradataml/data/payment_fraud_dataset.csv +10001 -0
- teradataml/data/sdk/modelops/modelops_spec.json +101737 -0
- teradataml/data/teradataml_example.json +75 -1
- teradataml/data/url_data.csv +10 -9
- teradataml/dataframe/copy_to.py +715 -55
- teradataml/dataframe/dataframe.py +2115 -97
- teradataml/dataframe/dataframe_utils.py +66 -28
- teradataml/dataframe/functions.py +1130 -2
- teradataml/dataframe/setop.py +4 -1
- teradataml/dataframe/sql.py +710 -1039
- teradataml/dbutils/dbutils.py +470 -35
- teradataml/dbutils/filemgr.py +1 -1
- teradataml/hyperparameter_tuner/optimizer.py +456 -142
- teradataml/hyperparameter_tuner/utils.py +4 -2
- teradataml/lib/aed_0_1.dll +0 -0
- teradataml/lib/libaed_0_1.dylib +0 -0
- teradataml/lib/libaed_0_1.so +0 -0
- teradataml/lib/libaed_0_1_aarch64.so +0 -0
- teradataml/opensource/_base.py +7 -1
- teradataml/options/configure.py +20 -4
- teradataml/scriptmgmt/UserEnv.py +247 -36
- teradataml/scriptmgmt/lls_utils.py +140 -39
- teradataml/sdk/README.md +79 -0
- teradataml/sdk/__init__.py +4 -0
- teradataml/sdk/_auth_modes.py +422 -0
- teradataml/sdk/_func_params.py +487 -0
- teradataml/sdk/_json_parser.py +453 -0
- teradataml/sdk/_openapi_spec_constants.py +249 -0
- teradataml/sdk/_utils.py +236 -0
- teradataml/sdk/api_client.py +900 -0
- teradataml/sdk/constants.py +62 -0
- teradataml/sdk/modelops/__init__.py +98 -0
- teradataml/sdk/modelops/_client.py +409 -0
- teradataml/sdk/modelops/_constants.py +304 -0
- teradataml/sdk/modelops/models.py +2308 -0
- teradataml/sdk/spinner.py +107 -0
- teradataml/series/series.py +12 -7
- teradataml/store/feature_store/constants.py +601 -234
- teradataml/store/feature_store/feature_store.py +2886 -616
- teradataml/store/feature_store/mind_map.py +639 -0
- teradataml/store/feature_store/models.py +5831 -214
- teradataml/store/feature_store/utils.py +390 -0
- teradataml/table_operators/query_generator.py +4 -21
- teradataml/table_operators/table_operator_util.py +1 -1
- teradataml/table_operators/templates/dataframe_register.template +6 -2
- teradataml/table_operators/templates/dataframe_udf.template +6 -2
- teradataml/utils/docstring.py +527 -0
- teradataml/utils/dtypes.py +95 -1
- teradataml/utils/internal_buffer.py +2 -2
- teradataml/utils/utils.py +41 -3
- teradataml/utils/validators.py +699 -18
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/METADATA +312 -2
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/RECORD +119 -87
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/WHEEL +0 -0
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/top_level.txt +0 -0
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/zip-safe +0 -0
|
@@ -24,27 +24,25 @@ from urllib.parse import urlparse
|
|
|
24
24
|
import pandas as pd
|
|
25
25
|
|
|
26
26
|
from teradataml import configure
|
|
27
|
-
from teradataml.context.context import _get_user, get_connection
|
|
28
|
-
from teradataml.common.constants import HTTPRequest, AsyncStatusColumns, AuthMechs
|
|
29
27
|
from teradataml.clients.auth_client import _AuthWorkflow
|
|
28
|
+
from teradataml.clients.keycloak_client import _KeycloakManager
|
|
30
29
|
from teradataml.clients.pkce_client import _DAWorkflow
|
|
31
30
|
from teradataml.common.constants import (AsyncOpStatus, AsyncStatusColumns,
|
|
32
|
-
HTTPRequest)
|
|
31
|
+
AuthMechs, HTTPRequest, TDServices)
|
|
33
32
|
from teradataml.common.exceptions import TeradataMlException
|
|
34
33
|
from teradataml.common.messagecodes import MessageCodes
|
|
35
34
|
from teradataml.common.messages import Messages
|
|
36
35
|
from teradataml.common.utils import UtilFuncs
|
|
37
36
|
from teradataml.context.context import _get_user, get_connection
|
|
38
37
|
from teradataml.scriptmgmt.UserEnv import (UserEnv, _AuthToken,
|
|
39
|
-
_get_auth_token,
|
|
40
|
-
|
|
38
|
+
_get_auth_token, _get_ccp_url,
|
|
39
|
+
_get_ues_url, _process_ues_response)
|
|
41
40
|
from teradataml.telemetry_utils.queryband import collect_queryband
|
|
42
41
|
from teradataml.utils.internal_buffer import _InternalBuffer
|
|
43
42
|
from teradataml.utils.utils import _async_run_id_info
|
|
44
43
|
from teradataml.utils.validators import _Validators
|
|
45
44
|
|
|
46
45
|
|
|
47
|
-
|
|
48
46
|
@collect_queryband(queryband="LstBsEnv")
|
|
49
47
|
def list_base_envs():
|
|
50
48
|
"""
|
|
@@ -269,7 +267,7 @@ def list_user_envs(env_name=None, **kwargs):
|
|
|
269
267
|
|
|
270
268
|
# Example 8: List all user environments where python 3 environment release version has
|
|
271
269
|
# odd number. For e.g. python_3.7.x.
|
|
272
|
-
>>> list_user_envs(base_env="
|
|
270
|
+
>>> list_user_envs(base_env="\\.\\d*[13579]\\.")
|
|
273
271
|
env_name env_description base_env_name language
|
|
274
272
|
1 Customer_Trends Analyse customer trends r_4.1.3 R
|
|
275
273
|
2 Fraud_Detection Fraud detection through time matching python_3.7.13 Python
|
|
@@ -476,29 +474,51 @@ def __create_envs(template):
|
|
|
476
474
|
return last_successful_env
|
|
477
475
|
|
|
478
476
|
|
|
479
|
-
def __get_default_base_env():
|
|
477
|
+
def __get_default_base_env(lang="python"):
|
|
480
478
|
"""
|
|
481
|
-
|
|
482
|
-
|
|
479
|
+
DESCRIPTION:
|
|
480
|
+
Function returns the name of latest environment available with
|
|
481
|
+
Open Analytics Framework for given programming language.
|
|
482
|
+
|
|
483
|
+
PARAMETERS:
|
|
484
|
+
lang:
|
|
485
|
+
Optional Argument.
|
|
486
|
+
Specifies the language for which latest base env is to be retrieved.
|
|
487
|
+
Default value: "python"
|
|
488
|
+
Permitted values: "python", "r", "PYTHON", "R"
|
|
489
|
+
Types: str
|
|
490
|
+
|
|
491
|
+
RETURNS:
|
|
492
|
+
Base environment name.
|
|
493
|
+
|
|
494
|
+
RAISES:
|
|
495
|
+
None.
|
|
496
|
+
|
|
497
|
+
EXAMPLES:
|
|
498
|
+
# Get default R base environment.
|
|
499
|
+
>>> __get_default_base_env(lang="R")
|
|
483
500
|
"""
|
|
501
|
+
lang = lang.lower()
|
|
502
|
+
default_env_key = "default_base_env_{}".format(lang)
|
|
484
503
|
# Check if the default base environment is already available.
|
|
485
|
-
if _InternalBuffer.get(
|
|
486
|
-
return _InternalBuffer.get(
|
|
504
|
+
if _InternalBuffer.get(default_env_key) is not None:
|
|
505
|
+
return _InternalBuffer.get(default_env_key)
|
|
487
506
|
|
|
488
507
|
try:
|
|
489
508
|
base_envs = list_base_envs()
|
|
490
|
-
|
|
509
|
+
versions = base_envs[base_envs.language.str.lower() == lang]['version']
|
|
491
510
|
# Convert version strings to tuples of integers for comparison
|
|
492
|
-
version_tuples = [tuple(map(int, version.split('.'))) for version in
|
|
511
|
+
version_tuples = [tuple(map(int, version.split('.'))) for version in versions]
|
|
493
512
|
# Find the latest version tuple using max() function
|
|
494
513
|
latest_version_tuple = max(version_tuples)
|
|
495
514
|
# Convert the latest version tuple back to a string
|
|
496
515
|
latest_version = '.'.join(map(str, latest_version_tuple))
|
|
497
|
-
# Get the base environment name for the latest version
|
|
498
|
-
_InternalBuffer.add(
|
|
499
|
-
|
|
516
|
+
# Get the base environment name for the latest version and add in internal buffer.
|
|
517
|
+
_InternalBuffer.add(**{default_env_key:
|
|
518
|
+
base_envs[base_envs.version == latest_version]['base_name'].to_list()[0]})
|
|
519
|
+
return _InternalBuffer.get(default_env_key)
|
|
500
520
|
except Exception as base_env_err:
|
|
501
|
-
raise Exception("Failed to obtain default base environment.", str(base_env_err
|
|
521
|
+
raise Exception("Failed to obtain default base environment.", str(base_env_err))
|
|
502
522
|
|
|
503
523
|
|
|
504
524
|
def __install_files(env, directory):
|
|
@@ -801,12 +821,14 @@ def create_env(env_name=None, base_env=None, desc=None, template=None, conda_env
|
|
|
801
821
|
# the list of base envs. If not available, set base_env to the default python base env.
|
|
802
822
|
if not base_env or \
|
|
803
823
|
base_env.lower() not in list_base_envs()['base_name'].str.lower().to_list():
|
|
824
|
+
lang = "python"
|
|
804
825
|
# Print warning message if base_env provided is not available.
|
|
805
826
|
if base_env:
|
|
806
827
|
print(f"Note: The specified base environment '{base_env}' is unavailable. " \
|
|
807
828
|
"Using the default base environment as specified in the documentation.")
|
|
829
|
+
lang = base_env.split('_')[0].lower() # Extract language for given base_env.
|
|
808
830
|
# Set base_env to the default
|
|
809
|
-
base_env = __get_default_base_env()
|
|
831
|
+
base_env = __get_default_base_env(lang=lang)
|
|
810
832
|
if not desc:
|
|
811
833
|
desc = "This env '{}' is created with base env '{}'.".format(env_name, base_env)
|
|
812
834
|
try:
|
|
@@ -1507,7 +1529,7 @@ def _remove_all_envs(env_type, **kwargs):
|
|
|
1507
1529
|
claim_id_list.append(future_result)
|
|
1508
1530
|
|
|
1509
1531
|
except (TeradataMlException, RuntimeError, Exception) as emsg:
|
|
1510
|
-
# Catching exceptions by remove_env if
|
|
1532
|
+
# Catching exceptions by remove_env if occurred in any thread.
|
|
1511
1533
|
failed_envs[env] = emsg
|
|
1512
1534
|
|
|
1513
1535
|
# Negative case - Failed to remove env.
|
|
@@ -1778,6 +1800,18 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1778
1800
|
Specifies the password for database user to be used for Basic authentication.
|
|
1779
1801
|
Types: str
|
|
1780
1802
|
|
|
1803
|
+
auth_url:
|
|
1804
|
+
Optional Argument.
|
|
1805
|
+
Specifies the endpoint URL for a keycloak server.
|
|
1806
|
+
Types: str
|
|
1807
|
+
|
|
1808
|
+
rest_client:
|
|
1809
|
+
Optional Argument.
|
|
1810
|
+
Specifies the service for which keycloak token is to be generated.
|
|
1811
|
+
Permitted values: "VECTORSTORE"
|
|
1812
|
+
Default value: "VECTORSTORE"
|
|
1813
|
+
Types: str
|
|
1814
|
+
|
|
1781
1815
|
auth_mech:
|
|
1782
1816
|
Optional Argument.
|
|
1783
1817
|
Specifies the mechanism to be used for generating authentication token.
|
|
@@ -1787,14 +1821,31 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1787
1821
|
* OAuth: Token generation is done through OAuth by using client id
|
|
1788
1822
|
which can be sepcified by user in "client_id" argument or
|
|
1789
1823
|
can be derived internally from "base_url".
|
|
1790
|
-
* PAT
|
|
1824
|
+
* PAT: Token generation is done using "pat_token" and "pem_file".
|
|
1791
1825
|
* BASIC: Authentication is done via Basic authentication mechanism
|
|
1792
1826
|
using user credentials passed in "username" and "password"
|
|
1793
1827
|
arguments.
|
|
1794
|
-
* JWT
|
|
1795
|
-
|
|
1828
|
+
* JWT: Readily available token in "auth_token" argument is used.
|
|
1829
|
+
* KEYCLOAK: Token generation is done using keycloak.
|
|
1830
|
+
Permitted Values: "OAuth", "PAT", "BASIC", "JWT", "KEYCLOAK".
|
|
1796
1831
|
Types: str
|
|
1797
1832
|
|
|
1833
|
+
validate_jwt:
|
|
1834
|
+
Optional Argument.
|
|
1835
|
+
Specifies whether to validate generated JWT token or not.
|
|
1836
|
+
Note:
|
|
1837
|
+
* Applicable only when "auth_mech" is "PAT".
|
|
1838
|
+
Default value: True
|
|
1839
|
+
Types: boolean
|
|
1840
|
+
|
|
1841
|
+
valid_from:
|
|
1842
|
+
Optional Argument.
|
|
1843
|
+
Specifies epoch seconds representing time from which JWT token will be valid.
|
|
1844
|
+
Note:
|
|
1845
|
+
* Applicable only when "auth_mech" is "PAT".
|
|
1846
|
+
Default value: 0
|
|
1847
|
+
Types: int
|
|
1848
|
+
|
|
1798
1849
|
RETURNS:
|
|
1799
1850
|
True, if the operation is successful.
|
|
1800
1851
|
|
|
@@ -1861,6 +1912,16 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1861
1912
|
Authentication token is generated and set for the session.
|
|
1862
1913
|
True
|
|
1863
1914
|
|
|
1915
|
+
# Example 8: Set the authentication token for by specifying "base_url", "auth_url"
|
|
1916
|
+
# "password" and "rest_client" and generating keycloak token internally.
|
|
1917
|
+
>>> import getpass
|
|
1918
|
+
>>> set_auth_token(base_url=getpass.getpass("base_url : "),
|
|
1919
|
+
... auth_url=getpass.getpass("auth_url : "),
|
|
1920
|
+
... password=getpass.getpass("password : "),
|
|
1921
|
+
... rest_client=getpass.getpass("rest_client : "))
|
|
1922
|
+
Authentication token is generated and set for the session.
|
|
1923
|
+
True
|
|
1924
|
+
|
|
1864
1925
|
"""
|
|
1865
1926
|
|
|
1866
1927
|
# Deriving global connection using get_connection().
|
|
@@ -1869,7 +1930,7 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1869
1930
|
MessageCodes.INVALID_CONTEXT_CONNECTION)
|
|
1870
1931
|
|
|
1871
1932
|
# Remove keys from _InternalBuffer which are interrelated to base_url and authentication token.
|
|
1872
|
-
_InternalBuffer.remove_keys(['list_base_envs', '
|
|
1933
|
+
_InternalBuffer.remove_keys(['list_base_envs', 'default_base_env_python', 'default_base_env_r',
|
|
1873
1934
|
'vs_session_id', 'vs_header'])
|
|
1874
1935
|
|
|
1875
1936
|
# ---------------------------------ARGUMENT VALIDATION------------------------------------------------------
|
|
@@ -1886,22 +1947,34 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1886
1947
|
__arg_info_matrix.append(["ues_url", ues_url, True, (str), True])
|
|
1887
1948
|
|
|
1888
1949
|
username = kwargs.get("username", _get_user())
|
|
1889
|
-
__arg_info_matrix.append(
|
|
1950
|
+
__arg_info_matrix.append(["username", username, True, (str), True])
|
|
1890
1951
|
|
|
1891
1952
|
password = kwargs.get("password", None)
|
|
1892
1953
|
__arg_info_matrix.append(["password", password, True, (str), True])
|
|
1893
1954
|
|
|
1894
1955
|
auth_token = kwargs.get("auth_token")
|
|
1895
|
-
__arg_info_matrix.append(
|
|
1956
|
+
__arg_info_matrix.append(["auth_token", auth_token, True, (str), True])
|
|
1896
1957
|
|
|
1897
|
-
expiration_time = kwargs.get("expiration_time", 31536000)
|
|
1898
|
-
__arg_info_matrix.append(
|
|
1958
|
+
expiration_time = kwargs.get("expiration_time", 31536000) # 31536000 seconds meaning 365 days.
|
|
1959
|
+
__arg_info_matrix.append(["expiration_time", expiration_time, True, (int), True])
|
|
1899
1960
|
|
|
1900
1961
|
kid = kwargs.get("kid")
|
|
1901
|
-
__arg_info_matrix.append(
|
|
1962
|
+
__arg_info_matrix.append(["kid", kid, True, (str), True])
|
|
1963
|
+
|
|
1964
|
+
auth_url = kwargs.get("auth_url", None)
|
|
1965
|
+
__arg_info_matrix.append(["auth_url", auth_url, True, (str), True])
|
|
1966
|
+
|
|
1967
|
+
rest_client = kwargs.get("rest_client", "VECTORSTORE")
|
|
1968
|
+
__arg_info_matrix.append(["rest_client", rest_client, True, (str), True, [svc.name for svc in TDServices]])
|
|
1902
1969
|
|
|
1903
1970
|
auth_mech = kwargs.get("auth_mech", None)
|
|
1904
|
-
__arg_info_matrix.append(
|
|
1971
|
+
__arg_info_matrix.append(["auth_mech", auth_mech, True, (str), True, [mech.name for mech in AuthMechs]])
|
|
1972
|
+
|
|
1973
|
+
validate_jwt = kwargs.get("validate_jwt", True)
|
|
1974
|
+
__arg_info_matrix.append(["validate_jwt", validate_jwt, True, (bool)])
|
|
1975
|
+
|
|
1976
|
+
valid_from = kwargs.get("valid_from", 0) # This sets iat to UTC beginning.
|
|
1977
|
+
__arg_info_matrix.append(["valid_from", valid_from, True, int])
|
|
1905
1978
|
|
|
1906
1979
|
# Validate arguments.
|
|
1907
1980
|
_Validators._validate_function_arguments(__arg_info_matrix)
|
|
@@ -1919,6 +1992,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1919
1992
|
|
|
1920
1993
|
# Set the vector_store_base_url. This should only be done if base_url is set.
|
|
1921
1994
|
# In case ues_url is set, vector_store_base_url should not be set.
|
|
1995
|
+
# Remove trailing forward slash from base_url if present.
|
|
1996
|
+
base_url = base_url[: -1] if base_url.endswith("/") else base_url
|
|
1922
1997
|
configure._vector_store_base_url = f'{base_url}/data-insights'
|
|
1923
1998
|
|
|
1924
1999
|
if ues_url:
|
|
@@ -1950,13 +2025,15 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1950
2025
|
if auth_mech:
|
|
1951
2026
|
auth_mech = auth_mech.lower()
|
|
1952
2027
|
if auth_mech == 'oauth':
|
|
1953
|
-
pat_token = pem_file = password = auth_token = None
|
|
2028
|
+
pat_token = pem_file = password = auth_token = auth_url = None
|
|
1954
2029
|
elif auth_mech == 'jwt':
|
|
1955
|
-
pat_token = pem_file = password = client_id = None
|
|
2030
|
+
pat_token = pem_file = password = client_id = auth_url = None
|
|
1956
2031
|
elif auth_mech == 'basic':
|
|
1957
|
-
pat_token = pem_file = auth_token = client_id = None
|
|
2032
|
+
pat_token = pem_file = auth_token = client_id = auth_url = None
|
|
1958
2033
|
elif auth_mech == 'pat':
|
|
1959
|
-
password = client_id = auth_token = None
|
|
2034
|
+
password = client_id = auth_token = auth_url = None
|
|
2035
|
+
elif auth_mech == 'keycloak':
|
|
2036
|
+
pat_token = pem_file = auth_token = client_id = None
|
|
1960
2037
|
|
|
1961
2038
|
# Validate arguments for mutual exclusiveness.
|
|
1962
2039
|
all_groups_none = \
|
|
@@ -1964,7 +2041,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1964
2041
|
{"auth_token": auth_token},
|
|
1965
2042
|
{"pat_token": pat_token,
|
|
1966
2043
|
"pem_file": pem_file},
|
|
1967
|
-
{"password": password}
|
|
2044
|
+
{"password": password} if not auth_url else
|
|
2045
|
+
{"password": password, "auth_url": auth_url},
|
|
1968
2046
|
return_all_falsy_status=True)
|
|
1969
2047
|
|
|
1970
2048
|
# Determine authentication mechanism from availability of supportive arguments.
|
|
@@ -1973,6 +2051,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1973
2051
|
auth_mech = 'jwt'
|
|
1974
2052
|
elif any([pat_token, pem_file]):
|
|
1975
2053
|
auth_mech = 'pat'
|
|
2054
|
+
elif auth_url:
|
|
2055
|
+
auth_mech = 'keycloak'
|
|
1976
2056
|
elif password:
|
|
1977
2057
|
# Authentication is done via Basic authentication mechanism
|
|
1978
2058
|
# by passing 'basic' field in header.
|
|
@@ -1995,7 +2075,6 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1995
2075
|
_InternalBuffer.add(auth_token=_AuthToken(token=auth_token,
|
|
1996
2076
|
auth_type='bearer'))
|
|
1997
2077
|
elif auth_mech == 'oauth':
|
|
1998
|
-
# TODO: Finalize need to set this flag to False in other scenarios.
|
|
1999
2078
|
configure._oauth = True
|
|
2000
2079
|
client_id = "{}-oaf-device".format(org_id) if client_id is None else client_id
|
|
2001
2080
|
da_wf = _DAWorkflow(parsed_base_url, client_id)
|
|
@@ -2028,11 +2107,13 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
2028
2107
|
"pem_file": pem_file,
|
|
2029
2108
|
"username": username,
|
|
2030
2109
|
"expiration_time": expiration_time,
|
|
2031
|
-
"kid": kid
|
|
2110
|
+
"kid": kid,
|
|
2111
|
+
"valid_from": valid_from})
|
|
2032
2112
|
token_data = auth_wf._proxy_jwt()
|
|
2033
2113
|
|
|
2034
|
-
|
|
2035
|
-
|
|
2114
|
+
if validate_jwt:
|
|
2115
|
+
# Validate generated JWT token.
|
|
2116
|
+
token_validated = _validate_jwt_token(base_url, token_data)
|
|
2036
2117
|
|
|
2037
2118
|
# Store the jwt token in internal class attribute.
|
|
2038
2119
|
_InternalBuffer.add(auth_token=_AuthToken(token=token_data,
|
|
@@ -2047,6 +2128,26 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
2047
2128
|
# Store the header data in internal class attribute.
|
|
2048
2129
|
_InternalBuffer.add(auth_token=_AuthToken(token=encoded_credentials,
|
|
2049
2130
|
auth_type='basic'))
|
|
2131
|
+
elif auth_mech == 'keycloak':
|
|
2132
|
+
_Validators._validate_missing_required_arguments([["password", password, False, (str), True],
|
|
2133
|
+
["auth_url", auth_url, False, (str), True]
|
|
2134
|
+
])
|
|
2135
|
+
token_generator = _KeycloakManager(auth_url=auth_url,
|
|
2136
|
+
client_id=TDServices[rest_client].value)
|
|
2137
|
+
|
|
2138
|
+
# Store manager object in _InternalBuffer in order to generate token after expiry time.
|
|
2139
|
+
_InternalBuffer.add(keycloak_manager=token_generator)
|
|
2140
|
+
try:
|
|
2141
|
+
token_data = token_generator.generate_token(username=username,
|
|
2142
|
+
password=password)
|
|
2143
|
+
except:
|
|
2144
|
+
raise TeradataMlException(Messages.get_message(MessageCodes.FUNC_EXECUTION_FAILED,
|
|
2145
|
+
"set_auth_token",
|
|
2146
|
+
"Failed to generate keycloak token."),
|
|
2147
|
+
MessageCodes.FUNC_EXECUTION_FAILED)
|
|
2148
|
+
|
|
2149
|
+
_InternalBuffer.add(auth_token=_AuthToken(token=token_data,
|
|
2150
|
+
auth_type='keycloak'))
|
|
2050
2151
|
|
|
2051
2152
|
if token_validated:
|
|
2052
2153
|
print("Authentication token is generated, authenticated and set for the session.")
|
teradataml/sdk/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
## How to create Software Development Kit (SDK) using OpenAPI spec
|
|
2
|
+
|
|
3
|
+
All SDKs should be in module `teradataml.sdk`. If a module name `<module_name>` is to be created with OpenAPI JSON file,
|
|
4
|
+
- The json file (say `openapi_spec.json`) should be placed in the directory `teradataml/data/sdk/<module_name>"` after creating required folders to maintain the folder structure.
|
|
5
|
+
- Create a folder `<module_name>` in `teradataml/sdk/` and place `__init__.py` file.
|
|
6
|
+
- Copy and paste the code from `teradataml/sdk/modelops/__init__.py` to newly created `__init__.py` file.
|
|
7
|
+
- Update the constants `SdkNames` and `SdkPackagePaths` in `teradataml/sdk/constants.py` to name the module and locate to appropriate location of OpenAPI JSON spec.
|
|
8
|
+
- Update the values to the constants `SdkNames` and `SdkPackagePaths` in `__init__.py`.
|
|
9
|
+
- Create `teradataml/sdk/<module_name>/_constants.py`.
|
|
10
|
+
- Copy and paste the code from `teradataml/sdk/modelops/_constants.py`. Keep empty dictionaries if no change in class names and function names is required. Fill in the dictionary similar to `teradataml/sdk/modelops/_constants.py` with intended class and function names.
|
|
11
|
+
- If customization is needed in client object, copy and paste the file `teradataml/sdk/modelops/_client.py` to `teradataml/sdk/<module_name>/_client.py` and update corresponding imports (for new client) in `teradataml/sdk/<module_name>/__init__.py`. Otherwise, user can use `BaseClient` from `teradataml/sdk/api_client.py`.
|
|
12
|
+
- Generate Pydantic models for OpenAPI schema using below commands which will create `teradataml/sdk/<module_name>/models.py`. Add unit test cases similar to `teradataml/tests/unit/sdk/test_modelops_schema.py` which import models and use helper class to bulk test the classes.
|
|
13
|
+
```shell
|
|
14
|
+
pip install datamodel-code-generator==0.27.3
|
|
15
|
+
# Run below command from pyTeradata directory.
|
|
16
|
+
datamodel-codegen --input teradataml/data/sdk/<module_name>/openapi_spec.json --input-file-type openapi --output teradataml/sdk/<module_name>/models.py --output-model-type pydantic_v2.BaseModel --use-field-description --keep-model-order --target-python-version=3.8 --use-schema-description --field-constraints --allow-population-by-field-name --strict-types bool int float # From windows use datamodel-codegen.exe
|
|
17
|
+
```
|
|
18
|
+
- If there are not schema in OpenAPI spec, create empty file `teradataml/sdk/<module_name>/models.py`.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## What is created dynamically
|
|
22
|
+
|
|
23
|
+
When the user runs `from teradataml.sdk.<module_name> import *` or `from teradataml.sdk.<module_name> import AnyClass`, it creates classes and class methods dynamically.
|
|
24
|
+
|
|
25
|
+
How are these classes created?
|
|
26
|
+
- Tags from OpenAPI spec are converted to Camel case and used as classes.
|
|
27
|
+
- If any of the API endpoint methods does not have tags associated with them, such functions are kept in class name `DefaultApi`.
|
|
28
|
+
|
|
29
|
+
How are class methods created?
|
|
30
|
+
- All the API endpoint methods form each function of the class.
|
|
31
|
+
- The function names are taken from `OperationId` field of function in OpenAPI JSON spec. The value of `OperationId` is converted to Snake case along with replacing hyphens (`-`) with underscores (`_`). This new value is used as API function name for the user to call by passing parameters.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Example - Vantage ModelOps SDK
|
|
35
|
+
|
|
36
|
+
Couple of the tags in ModelOps OpenAPI spec is `Alert rules`, `Models`. These tags are converted to classes `AlertRules` and `Models` respectively.
|
|
37
|
+
|
|
38
|
+
The API end point `/api/models` contains `get` method with `operationId` as `getCollectionResource-model-get`. The framework creates `get_collection_resource_model_get(...)` function in `Models` class.
|
|
39
|
+
|
|
40
|
+
Similarly, the API end point `/api/models/{id}/alertRules` contains `get` method with `operationId` as `getAlertRules`. The framework creates `get_alert_rules(...)` functions in `AlertRules` class.
|
|
41
|
+
|
|
42
|
+
So, these API endpoints can be accessed through SDK as follows:
|
|
43
|
+
```python
|
|
44
|
+
# Authenticate and connect to client.
|
|
45
|
+
from teradataml.sdk.modelops import ModelOpsClient
|
|
46
|
+
from teradataml.sdk import ClientCredentialsAuth # Three different authentication mechanisms are supported.
|
|
47
|
+
auth_obj = ClientCredentialsAuth(
|
|
48
|
+
auth_client_id="<client_id>",
|
|
49
|
+
auth_client_secret="<client_secret>",
|
|
50
|
+
auth_token_url="https://10.27.117.175/sso/realms/teradata/protocol/openid-connect/token"
|
|
51
|
+
)
|
|
52
|
+
client = ModelOpsCleint(
|
|
53
|
+
base_url="https://10.27.117.175/core",
|
|
54
|
+
auth=auth_obj,
|
|
55
|
+
ssl_verify=False
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Import required classes.
|
|
59
|
+
from teradataml.sdk.modelops import AlertRules, Models
|
|
60
|
+
|
|
61
|
+
# Some APIs are tied with Project ID which needs to be set to the client.
|
|
62
|
+
client.set_project_id("<uuid_project_id>")
|
|
63
|
+
|
|
64
|
+
# Create Models object and get all the models.
|
|
65
|
+
mod = Models(client=client)
|
|
66
|
+
models = mod.get_collection_resource_model_get()
|
|
67
|
+
|
|
68
|
+
# Get alert rules for any one of the model.
|
|
69
|
+
ar = AlertRules(client=client)
|
|
70
|
+
ar.get_alert_rules(id="<uuid_model_id>")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Note:
|
|
74
|
+
- All the argument to the API functions are read as `**kwargs`. So, the user has to pass keyword arguments i.e., positional argument usage is not supported yet.
|
|
75
|
+
- The following validations are done for arguments which accepts basic data types:
|
|
76
|
+
- Missing required arguments.
|
|
77
|
+
- Invalid type passed to arguments.
|
|
78
|
+
- Invalid (non-permitted) value passed to arguments.
|
|
79
|
+
- Validations for dict type objects (like input for `requestBody`) are yet to be added.
|