teradataml 20.0.0.5__py3-none-any.whl → 20.0.0.6__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 +96 -0
- teradataml/_version.py +1 -1
- teradataml/analytics/analytic_function_executor.py +1 -1
- teradataml/analytics/utils.py +56 -11
- teradataml/clients/auth_client.py +10 -6
- teradataml/clients/keycloak_client.py +165 -0
- teradataml/common/constants.py +10 -0
- teradataml/common/exceptions.py +32 -0
- teradataml/common/messagecodes.py +27 -0
- teradataml/common/messages.py +9 -1
- teradataml/common/sqlbundle.py +3 -2
- teradataml/common/utils.py +94 -12
- teradataml/context/context.py +37 -9
- teradataml/data/jsons/byom/onnxembeddings.json +1 -0
- teradataml/data/pattern_matching_data.csv +11 -0
- teradataml/data/sdk/modelops/modelops_spec.json +101737 -0
- teradataml/data/teradataml_example.json +8 -1
- teradataml/data/url_data.csv +10 -9
- teradataml/dataframe/copy_to.py +1 -1
- teradataml/dataframe/dataframe.py +980 -82
- teradataml/dataframe/dataframe_utils.py +58 -25
- teradataml/dataframe/functions.py +962 -1
- teradataml/dataframe/sql.py +570 -1031
- teradataml/hyperparameter_tuner/utils.py +4 -2
- teradataml/lib/aed_0_1.dll +0 -0
- teradataml/opensource/_base.py +7 -1
- teradataml/options/configure.py +20 -4
- teradataml/scriptmgmt/UserEnv.py +13 -2
- teradataml/scriptmgmt/lls_utils.py +99 -24
- 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 +897 -0
- teradataml/sdk/constants.py +62 -0
- teradataml/sdk/modelops/__init__.py +98 -0
- teradataml/sdk/modelops/_client.py +406 -0
- teradataml/sdk/modelops/_constants.py +304 -0
- teradataml/sdk/modelops/models.py +2308 -0
- teradataml/sdk/spinner.py +107 -0
- teradataml/table_operators/query_generator.py +4 -21
- teradataml/utils/dtypes.py +2 -1
- teradataml/utils/utils.py +0 -1
- teradataml/utils/validators.py +5 -1
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.6.dist-info}/METADATA +101 -2
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.6.dist-info}/RECORD +53 -36
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.6.dist-info}/WHEEL +0 -0
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.6.dist-info}/top_level.txt +0 -0
- {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.6.dist-info}/zip-safe +0 -0
|
@@ -276,6 +276,8 @@ class _ProgressBar:
|
|
|
276
276
|
progress_precent=_progress_percent,
|
|
277
277
|
completed_jobs=self.completed_jobs,
|
|
278
278
|
total_jobs=self.total_jobs)
|
|
279
|
+
# Add padding to clear any leftover characters from the previous message.
|
|
280
|
+
padded_msg = _msg.ljust(self.blank_space_len)
|
|
279
281
|
# Display the formatted bar.
|
|
280
|
-
print(
|
|
281
|
-
self.blank_space_len = len(
|
|
282
|
+
print(padded_msg, end='\r', file=self.STDOUT, flush=True)
|
|
283
|
+
self.blank_space_len = len(padded_msg)
|
teradataml/lib/aed_0_1.dll
CHANGED
|
Binary file
|
teradataml/opensource/_base.py
CHANGED
|
@@ -51,6 +51,7 @@ from teradataml.opensource._wrapper_utils import (_generate_new_name,
|
|
|
51
51
|
_validate_df_query_type)
|
|
52
52
|
from teradataml.options.configure import configure
|
|
53
53
|
from teradataml.utils.validators import _Validators
|
|
54
|
+
from teradataml.utils.internal_buffer import _InternalBuffer
|
|
54
55
|
|
|
55
56
|
logger = pylogger.getLogger()
|
|
56
57
|
|
|
@@ -88,9 +89,13 @@ class _GenericObjectWrapper:
|
|
|
88
89
|
self._env = configure.openml_user_env
|
|
89
90
|
else:
|
|
90
91
|
self._env = UtilFuncs._create_or_get_env("open_source_ml.json")
|
|
92
|
+
else:
|
|
93
|
+
set_session_param("searchuifdbpath", self._db_name)
|
|
91
94
|
|
|
92
95
|
# Check if the Python interpreter major versions are consistent between Vantage and local.
|
|
93
|
-
|
|
96
|
+
_check_py_version = _InternalBuffer.get('_check_py_version')
|
|
97
|
+
if _check_py_version:
|
|
98
|
+
UtilFuncs._check_python_version_diff(self._env)
|
|
94
99
|
|
|
95
100
|
# Raise warning when python package versions don't match between Vantage and local.
|
|
96
101
|
# OPENSOURCE_PACKAGE_NAME is set for each opensource package, but not for the base class.
|
|
@@ -1257,6 +1262,7 @@ class _OpenSourceObjectWrapper(_GenericObjectWrapper):
|
|
|
1257
1262
|
|
|
1258
1263
|
class _FunctionWrapper(_GenericObjectWrapper):
|
|
1259
1264
|
def __init__(self, module_name, func_name, file_type, template_file):
|
|
1265
|
+
|
|
1260
1266
|
super().__init__()
|
|
1261
1267
|
self._module_name = module_name
|
|
1262
1268
|
self._func_name = func_name
|
teradataml/options/configure.py
CHANGED
|
@@ -62,6 +62,7 @@ class _Configure(_ConfigureSuper):
|
|
|
62
62
|
stored_procedure_install_location = _create_property('stored_procedure_install_location')
|
|
63
63
|
table_operator = _create_property('table_operator')
|
|
64
64
|
temp_object_type = _create_property('temp_object_type')
|
|
65
|
+
use_short_object_name = _create_property('use_short_object_name')
|
|
65
66
|
|
|
66
67
|
def __init__(self, default_varchar_size=1024, column_casesensitive_handler=False,
|
|
67
68
|
vantage_version="vantage1.1", val_install_location=None,
|
|
@@ -71,7 +72,7 @@ class _Configure(_ConfigureSuper):
|
|
|
71
72
|
cran_repositories=None, inline_plot=True,
|
|
72
73
|
indb_install_location=None,
|
|
73
74
|
openml_user_env=None, local_storage=None, stored_procedure_install_location="SYSLIB",
|
|
74
|
-
table_operator=None, temp_object_type=None):
|
|
75
|
+
table_operator=None, temp_object_type=None, use_short_object_name=False):
|
|
75
76
|
|
|
76
77
|
"""
|
|
77
78
|
PARAMETERS:
|
|
@@ -140,8 +141,8 @@ class _Configure(_ConfigureSuper):
|
|
|
140
141
|
|
|
141
142
|
indb_install_location:
|
|
142
143
|
Specifies the installation location of In-DB Python package.
|
|
143
|
-
Types: string
|
|
144
144
|
Default Value: "/var/opt/teradata/languages/sles12sp3/Python/"
|
|
145
|
+
Types: string
|
|
145
146
|
Example:
|
|
146
147
|
# Set the installation location for older versions.
|
|
147
148
|
teradataml.options.configure.indb_install_location = "/opt/teradata/languages/Python/"
|
|
@@ -182,9 +183,9 @@ class _Configure(_ConfigureSuper):
|
|
|
182
183
|
Specifies the type of temporary database objects created internally by teradataml.
|
|
183
184
|
Permitted Values:
|
|
184
185
|
* "VT" - Volatile tables.
|
|
185
|
-
Types: String
|
|
186
186
|
Default Value: None
|
|
187
|
-
|
|
187
|
+
Types: String
|
|
188
|
+
Notes:
|
|
188
189
|
* If this option is set to "VT" and "persist" argument of analytic functions is
|
|
189
190
|
set to True, then volatile tables are not created as volatile table can't be
|
|
190
191
|
persisted and "persist" argument takes precedence.
|
|
@@ -193,6 +194,16 @@ class _Configure(_ConfigureSuper):
|
|
|
193
194
|
# Set the type of temporary database objects to "VT" to create volatile internal
|
|
194
195
|
# tables.
|
|
195
196
|
teradataml.options.configure.temp_object_type = "VT"
|
|
197
|
+
|
|
198
|
+
use_short_object_name:
|
|
199
|
+
Specifies whether to use shorter names for temporary tables created internally by teradataml.
|
|
200
|
+
When set to True, teradataml generates internal temporary table names with a maximum length
|
|
201
|
+
of 20 characters. Otherwise, there is no restriction on the length of these table names.
|
|
202
|
+
Default Value: False
|
|
203
|
+
Types: bool
|
|
204
|
+
Example:
|
|
205
|
+
# Set the option to use short names for temporary tables.
|
|
206
|
+
teradataml.options.configure.use_short_object_name = True
|
|
196
207
|
"""
|
|
197
208
|
super().__init__()
|
|
198
209
|
super().__setattr__('default_varchar_size', default_varchar_size)
|
|
@@ -213,6 +224,7 @@ class _Configure(_ConfigureSuper):
|
|
|
213
224
|
super().__setattr__('table_operator', table_operator)
|
|
214
225
|
super().__setattr__('_indb_install_location', indb_install_location)
|
|
215
226
|
super().__setattr__('temp_object_type', self.__get_temp_object_type(temp_object_type))
|
|
227
|
+
super().__setattr__('use_short_object_name', use_short_object_name)
|
|
216
228
|
|
|
217
229
|
# internal configurations
|
|
218
230
|
# These configurations are internal and should not be
|
|
@@ -447,6 +459,10 @@ class _Configure(_ConfigureSuper):
|
|
|
447
459
|
|
|
448
460
|
value = self.__get_temp_object_type(value)
|
|
449
461
|
|
|
462
|
+
elif name == 'use_short_object_name':
|
|
463
|
+
if not isinstance(value, bool):
|
|
464
|
+
raise TypeError(Messages.get_message(MessageCodes.UNSUPPORTED_DATATYPE, name, 'bool'))
|
|
465
|
+
|
|
450
466
|
super().__setattr__(name, value)
|
|
451
467
|
else:
|
|
452
468
|
raise AttributeError("'{}' object has no attribute '{}'".format(self.__class__.__name__, name))
|
teradataml/scriptmgmt/UserEnv.py
CHANGED
|
@@ -20,11 +20,10 @@ import time
|
|
|
20
20
|
from concurrent.futures import ThreadPoolExecutor, wait
|
|
21
21
|
from json.decoder import JSONDecodeError
|
|
22
22
|
from urllib.parse import urlparse
|
|
23
|
+
|
|
23
24
|
import pandas as pd
|
|
24
|
-
import requests
|
|
25
25
|
|
|
26
26
|
from teradataml import configure
|
|
27
|
-
from teradataml.clients.auth_client import _AuthWorkflow
|
|
28
27
|
from teradataml.clients.pkce_client import _DAWorkflow
|
|
29
28
|
from teradataml.common.constants import (AsyncOpStatus, CloudProvider,
|
|
30
29
|
HTTPRequest)
|
|
@@ -4046,6 +4045,14 @@ class _AuthToken:
|
|
|
4046
4045
|
def value(self):
|
|
4047
4046
|
return self.__value
|
|
4048
4047
|
|
|
4048
|
+
@value.setter
|
|
4049
|
+
def value(self, token_value):
|
|
4050
|
+
"""
|
|
4051
|
+
DESCRIPTION:
|
|
4052
|
+
Sets value of _AuthToken.
|
|
4053
|
+
"""
|
|
4054
|
+
self.__value = token_value
|
|
4055
|
+
|
|
4049
4056
|
@property
|
|
4050
4057
|
def auth_type(self):
|
|
4051
4058
|
return self.__auth_type
|
|
@@ -4060,3 +4067,7 @@ class _AuthToken:
|
|
|
4060
4067
|
elif self.auth_type.lower() == "bearer":
|
|
4061
4068
|
# Form the Authorization header value by prepending 'Bearer ' to the JWT token.
|
|
4062
4069
|
return {"Authorization": "Bearer {}".format(self.value)}
|
|
4070
|
+
elif self.auth_type.lower() == "keycloak":
|
|
4071
|
+
# Get valid token value for current time.
|
|
4072
|
+
self.value = _InternalBuffer.get("keycloak_manager").get_token()
|
|
4073
|
+
return {"Authorization": "Bearer {}".format(self.value)}
|
|
@@ -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
|
"""
|
|
@@ -1778,6 +1776,18 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1778
1776
|
Specifies the password for database user to be used for Basic authentication.
|
|
1779
1777
|
Types: str
|
|
1780
1778
|
|
|
1779
|
+
auth_url:
|
|
1780
|
+
Optional Argument.
|
|
1781
|
+
Specifies the endpoint URL for a keycloak server.
|
|
1782
|
+
Types: str
|
|
1783
|
+
|
|
1784
|
+
rest_client:
|
|
1785
|
+
Optional Argument.
|
|
1786
|
+
Specifies the service for which keycloak token is to be generated.
|
|
1787
|
+
Permitted values: "VECTORSTORE"
|
|
1788
|
+
Default value: "VECTORSTORE"
|
|
1789
|
+
Types: str
|
|
1790
|
+
|
|
1781
1791
|
auth_mech:
|
|
1782
1792
|
Optional Argument.
|
|
1783
1793
|
Specifies the mechanism to be used for generating authentication token.
|
|
@@ -1787,14 +1797,31 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1787
1797
|
* OAuth: Token generation is done through OAuth by using client id
|
|
1788
1798
|
which can be sepcified by user in "client_id" argument or
|
|
1789
1799
|
can be derived internally from "base_url".
|
|
1790
|
-
* PAT
|
|
1800
|
+
* PAT: Token generation is done using "pat_token" and "pem_file".
|
|
1791
1801
|
* BASIC: Authentication is done via Basic authentication mechanism
|
|
1792
1802
|
using user credentials passed in "username" and "password"
|
|
1793
1803
|
arguments.
|
|
1794
|
-
* JWT
|
|
1795
|
-
|
|
1804
|
+
* JWT: Readily available token in "auth_token" argument is used.
|
|
1805
|
+
* KEYCLOAK: Token generation is done using keycloak.
|
|
1806
|
+
Permitted Values: "OAuth", "PAT", "BASIC", "JWT", "KEYCLOAK".
|
|
1796
1807
|
Types: str
|
|
1797
1808
|
|
|
1809
|
+
validate_jwt:
|
|
1810
|
+
Optional Argument.
|
|
1811
|
+
Specifies whether to validate generated JWT token or not.
|
|
1812
|
+
Note:
|
|
1813
|
+
* Applicable only when "auth_mech" is "PAT".
|
|
1814
|
+
Default value: True
|
|
1815
|
+
Types: boolean
|
|
1816
|
+
|
|
1817
|
+
valid_from:
|
|
1818
|
+
Optional Argument.
|
|
1819
|
+
Specifies epoch seconds representing time from which JWT token will be valid.
|
|
1820
|
+
Note:
|
|
1821
|
+
* Applicable only when "auth_mech" is "PAT".
|
|
1822
|
+
Default value: None
|
|
1823
|
+
Types: int
|
|
1824
|
+
|
|
1798
1825
|
RETURNS:
|
|
1799
1826
|
True, if the operation is successful.
|
|
1800
1827
|
|
|
@@ -1861,6 +1888,16 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1861
1888
|
Authentication token is generated and set for the session.
|
|
1862
1889
|
True
|
|
1863
1890
|
|
|
1891
|
+
# Example 8: Set the authentication token for by specifying "base_url", "auth_url"
|
|
1892
|
+
# "password" and "rest_client" and generating keycloak token internally.
|
|
1893
|
+
>>> import getpass
|
|
1894
|
+
>>> set_auth_token(base_url=getpass.getpass("base_url : "),
|
|
1895
|
+
... auth_url=getpass.getpass("auth_url : "),
|
|
1896
|
+
... password=getpass.getpass("password : "),
|
|
1897
|
+
... rest_client=getpass.getpass("rest_client : "))
|
|
1898
|
+
Authentication token is generated and set for the session.
|
|
1899
|
+
True
|
|
1900
|
+
|
|
1864
1901
|
"""
|
|
1865
1902
|
|
|
1866
1903
|
# Deriving global connection using get_connection().
|
|
@@ -1886,22 +1923,34 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1886
1923
|
__arg_info_matrix.append(["ues_url", ues_url, True, (str), True])
|
|
1887
1924
|
|
|
1888
1925
|
username = kwargs.get("username", _get_user())
|
|
1889
|
-
__arg_info_matrix.append(
|
|
1926
|
+
__arg_info_matrix.append(["username", username, True, (str), True])
|
|
1890
1927
|
|
|
1891
1928
|
password = kwargs.get("password", None)
|
|
1892
1929
|
__arg_info_matrix.append(["password", password, True, (str), True])
|
|
1893
1930
|
|
|
1894
1931
|
auth_token = kwargs.get("auth_token")
|
|
1895
|
-
__arg_info_matrix.append(
|
|
1932
|
+
__arg_info_matrix.append(["auth_token", auth_token, True, (str), True])
|
|
1896
1933
|
|
|
1897
|
-
expiration_time = kwargs.get("expiration_time", 31536000)
|
|
1898
|
-
__arg_info_matrix.append(
|
|
1934
|
+
expiration_time = kwargs.get("expiration_time", 31536000) # 31536000 seconds meaning 365 days.
|
|
1935
|
+
__arg_info_matrix.append(["expiration_time", expiration_time, True, (int), True])
|
|
1899
1936
|
|
|
1900
1937
|
kid = kwargs.get("kid")
|
|
1901
|
-
__arg_info_matrix.append(
|
|
1938
|
+
__arg_info_matrix.append(["kid", kid, True, (str), True])
|
|
1939
|
+
|
|
1940
|
+
auth_url = kwargs.get("auth_url", None)
|
|
1941
|
+
__arg_info_matrix.append(["auth_url", auth_url, True, (str), True])
|
|
1942
|
+
|
|
1943
|
+
rest_client = kwargs.get("rest_client", "VECTORSTORE")
|
|
1944
|
+
__arg_info_matrix.append(["rest_client", rest_client, True, (str), True, [svc.name for svc in TDServices]])
|
|
1902
1945
|
|
|
1903
1946
|
auth_mech = kwargs.get("auth_mech", None)
|
|
1904
|
-
__arg_info_matrix.append(
|
|
1947
|
+
__arg_info_matrix.append(["auth_mech", auth_mech, True, (str), True, [mech.name for mech in AuthMechs]])
|
|
1948
|
+
|
|
1949
|
+
validate_jwt = kwargs.get("validate_jwt", True)
|
|
1950
|
+
__arg_info_matrix.append(["validate_jwt", validate_jwt, True, (bool)])
|
|
1951
|
+
|
|
1952
|
+
valid_from = kwargs.get("valid_from", None)
|
|
1953
|
+
__arg_info_matrix.append(["valid_from", valid_from, True, int])
|
|
1905
1954
|
|
|
1906
1955
|
# Validate arguments.
|
|
1907
1956
|
_Validators._validate_function_arguments(__arg_info_matrix)
|
|
@@ -1950,13 +1999,15 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1950
1999
|
if auth_mech:
|
|
1951
2000
|
auth_mech = auth_mech.lower()
|
|
1952
2001
|
if auth_mech == 'oauth':
|
|
1953
|
-
pat_token = pem_file = password = auth_token = None
|
|
2002
|
+
pat_token = pem_file = password = auth_token = auth_url = None
|
|
1954
2003
|
elif auth_mech == 'jwt':
|
|
1955
|
-
pat_token = pem_file = password = client_id = None
|
|
2004
|
+
pat_token = pem_file = password = client_id = auth_url = None
|
|
1956
2005
|
elif auth_mech == 'basic':
|
|
1957
|
-
pat_token = pem_file = auth_token = client_id = None
|
|
2006
|
+
pat_token = pem_file = auth_token = client_id = auth_url = None
|
|
1958
2007
|
elif auth_mech == 'pat':
|
|
1959
|
-
password = client_id = auth_token = None
|
|
2008
|
+
password = client_id = auth_token = auth_url = None
|
|
2009
|
+
elif auth_mech == 'keycloak':
|
|
2010
|
+
pat_token = pem_file = auth_token = client_id = None
|
|
1960
2011
|
|
|
1961
2012
|
# Validate arguments for mutual exclusiveness.
|
|
1962
2013
|
all_groups_none = \
|
|
@@ -1964,7 +2015,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1964
2015
|
{"auth_token": auth_token},
|
|
1965
2016
|
{"pat_token": pat_token,
|
|
1966
2017
|
"pem_file": pem_file},
|
|
1967
|
-
{"password": password}
|
|
2018
|
+
{"password": password} if not auth_url else
|
|
2019
|
+
{"password": password, "auth_url": auth_url},
|
|
1968
2020
|
return_all_falsy_status=True)
|
|
1969
2021
|
|
|
1970
2022
|
# Determine authentication mechanism from availability of supportive arguments.
|
|
@@ -1973,6 +2025,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1973
2025
|
auth_mech = 'jwt'
|
|
1974
2026
|
elif any([pat_token, pem_file]):
|
|
1975
2027
|
auth_mech = 'pat'
|
|
2028
|
+
elif auth_url:
|
|
2029
|
+
auth_mech = 'keycloak'
|
|
1976
2030
|
elif password:
|
|
1977
2031
|
# Authentication is done via Basic authentication mechanism
|
|
1978
2032
|
# by passing 'basic' field in header.
|
|
@@ -1995,7 +2049,6 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
1995
2049
|
_InternalBuffer.add(auth_token=_AuthToken(token=auth_token,
|
|
1996
2050
|
auth_type='bearer'))
|
|
1997
2051
|
elif auth_mech == 'oauth':
|
|
1998
|
-
# TODO: Finalize need to set this flag to False in other scenarios.
|
|
1999
2052
|
configure._oauth = True
|
|
2000
2053
|
client_id = "{}-oaf-device".format(org_id) if client_id is None else client_id
|
|
2001
2054
|
da_wf = _DAWorkflow(parsed_base_url, client_id)
|
|
@@ -2028,11 +2081,13 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
2028
2081
|
"pem_file": pem_file,
|
|
2029
2082
|
"username": username,
|
|
2030
2083
|
"expiration_time": expiration_time,
|
|
2031
|
-
"kid": kid
|
|
2084
|
+
"kid": kid,
|
|
2085
|
+
"valid_from": valid_from})
|
|
2032
2086
|
token_data = auth_wf._proxy_jwt()
|
|
2033
2087
|
|
|
2034
|
-
|
|
2035
|
-
|
|
2088
|
+
if validate_jwt:
|
|
2089
|
+
# Validate generated JWT token.
|
|
2090
|
+
token_validated = _validate_jwt_token(base_url, token_data)
|
|
2036
2091
|
|
|
2037
2092
|
# Store the jwt token in internal class attribute.
|
|
2038
2093
|
_InternalBuffer.add(auth_token=_AuthToken(token=token_data,
|
|
@@ -2047,6 +2102,26 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
|
|
|
2047
2102
|
# Store the header data in internal class attribute.
|
|
2048
2103
|
_InternalBuffer.add(auth_token=_AuthToken(token=encoded_credentials,
|
|
2049
2104
|
auth_type='basic'))
|
|
2105
|
+
elif auth_mech == 'keycloak':
|
|
2106
|
+
_Validators._validate_missing_required_arguments([["password", password, False, (str), True],
|
|
2107
|
+
["auth_url", auth_url, False, (str), True]
|
|
2108
|
+
])
|
|
2109
|
+
token_generator = _KeycloakManager(auth_url=auth_url,
|
|
2110
|
+
client_id=TDServices[rest_client].value)
|
|
2111
|
+
|
|
2112
|
+
# Store manager object in _InternalBuffer in order to generate token after expiry time.
|
|
2113
|
+
_InternalBuffer.add(keycloak_manager=token_generator)
|
|
2114
|
+
try:
|
|
2115
|
+
token_data = token_generator.generate_token(username=username,
|
|
2116
|
+
password=password)
|
|
2117
|
+
except:
|
|
2118
|
+
raise TeradataMlException(Messages.get_message(MessageCodes.FUNC_EXECUTION_FAILED,
|
|
2119
|
+
"set_auth_token",
|
|
2120
|
+
"Failed to generate keycloak token."),
|
|
2121
|
+
MessageCodes.FUNC_EXECUTION_FAILED)
|
|
2122
|
+
|
|
2123
|
+
_InternalBuffer.add(auth_token=_AuthToken(token=token_data,
|
|
2124
|
+
auth_type='keycloak'))
|
|
2050
2125
|
|
|
2051
2126
|
if token_validated:
|
|
2052
2127
|
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.
|