teradataml 20.0.0.4__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.

Files changed (131) hide show
  1. teradataml/LICENSE-3RD-PARTY.pdf +0 -0
  2. teradataml/README.md +182 -13
  3. teradataml/__init__.py +2 -1
  4. teradataml/_version.py +2 -2
  5. teradataml/analytics/analytic_function_executor.py +8 -13
  6. teradataml/analytics/json_parser/analytic_functions_argument.py +4 -0
  7. teradataml/analytics/sqle/__init__.py +16 -1
  8. teradataml/analytics/utils.py +60 -1
  9. teradataml/automl/__init__.py +290 -106
  10. teradataml/automl/autodataprep/__init__.py +471 -0
  11. teradataml/automl/data_preparation.py +29 -10
  12. teradataml/automl/data_transformation.py +11 -0
  13. teradataml/automl/feature_engineering.py +64 -4
  14. teradataml/automl/feature_exploration.py +639 -25
  15. teradataml/automl/model_training.py +1 -1
  16. teradataml/clients/auth_client.py +12 -8
  17. teradataml/clients/keycloak_client.py +165 -0
  18. teradataml/common/constants.py +71 -26
  19. teradataml/common/exceptions.py +32 -0
  20. teradataml/common/messagecodes.py +28 -0
  21. teradataml/common/messages.py +13 -4
  22. teradataml/common/sqlbundle.py +3 -2
  23. teradataml/common/utils.py +345 -45
  24. teradataml/context/context.py +259 -93
  25. teradataml/data/apriori_example.json +22 -0
  26. teradataml/data/docs/sqle/docs_17_20/Apriori.py +138 -0
  27. teradataml/data/docs/sqle/docs_17_20/NERExtractor.py +121 -0
  28. teradataml/data/docs/sqle/docs_17_20/NGramSplitter.py +3 -3
  29. teradataml/data/docs/sqle/docs_17_20/SMOTE.py +212 -0
  30. teradataml/data/docs/sqle/docs_17_20/TextMorph.py +119 -0
  31. teradataml/data/docs/sqle/docs_17_20/TextParser.py +54 -3
  32. teradataml/data/docs/uaf/docs_17_20/ACF.py +1 -1
  33. teradataml/data/docs/uaf/docs_17_20/ArimaEstimate.py +2 -2
  34. teradataml/data/docs/uaf/docs_17_20/ArimaXEstimate.py +2 -2
  35. teradataml/data/docs/uaf/docs_17_20/DFFT.py +1 -1
  36. teradataml/data/docs/uaf/docs_17_20/DFFT2.py +1 -1
  37. teradataml/data/docs/uaf/docs_17_20/DFFT2Conv.py +1 -1
  38. teradataml/data/docs/uaf/docs_17_20/DFFTConv.py +1 -1
  39. teradataml/data/docs/uaf/docs_17_20/FilterFactory1d.py +4 -4
  40. teradataml/data/docs/uaf/docs_17_20/GenseriesSinusoids.py +2 -2
  41. teradataml/data/docs/uaf/docs_17_20/GoldfeldQuandt.py +2 -2
  42. teradataml/data/docs/uaf/docs_17_20/HoltWintersForecaster.py +6 -6
  43. teradataml/data/docs/uaf/docs_17_20/LineSpec.py +1 -1
  44. teradataml/data/docs/uaf/docs_17_20/LinearRegr.py +1 -1
  45. teradataml/data/docs/uaf/docs_17_20/Matrix2Image.py +4 -4
  46. teradataml/data/docs/uaf/docs_17_20/MultivarRegr.py +1 -1
  47. teradataml/data/docs/uaf/docs_17_20/PACF.py +1 -1
  48. teradataml/data/docs/uaf/docs_17_20/PowerSpec.py +2 -2
  49. teradataml/data/docs/uaf/docs_17_20/PowerTransform.py +3 -3
  50. teradataml/data/docs/uaf/docs_17_20/Resample.py +5 -5
  51. teradataml/data/docs/uaf/docs_17_20/SAX.py +3 -3
  52. teradataml/data/docs/uaf/docs_17_20/SignifPeriodicities.py +1 -1
  53. teradataml/data/docs/uaf/docs_17_20/SimpleExp.py +1 -1
  54. teradataml/data/docs/uaf/docs_17_20/Smoothma.py +3 -3
  55. teradataml/data/docs/uaf/docs_17_20/UNDIFF.py +1 -1
  56. teradataml/data/jsons/byom/onnxembeddings.json +1 -0
  57. teradataml/data/jsons/sqle/17.20/NGramSplitter.json +6 -6
  58. teradataml/data/jsons/sqle/17.20/TD_Apriori.json +181 -0
  59. teradataml/data/jsons/sqle/17.20/TD_NERExtractor.json +145 -0
  60. teradataml/data/jsons/sqle/17.20/TD_SMOTE.json +267 -0
  61. teradataml/data/jsons/sqle/17.20/TD_TextMorph.json +134 -0
  62. teradataml/data/jsons/sqle/17.20/TD_TextParser.json +114 -9
  63. teradataml/data/jsons/sqle/20.00/AI_AnalyzeSentiment.json +328 -0
  64. teradataml/data/jsons/sqle/20.00/AI_AskLLM.json +420 -0
  65. teradataml/data/jsons/sqle/20.00/AI_DetectLanguage.json +343 -0
  66. teradataml/data/jsons/sqle/20.00/AI_ExtractKeyPhrases.json +328 -0
  67. teradataml/data/jsons/sqle/20.00/AI_MaskPII.json +328 -0
  68. teradataml/data/jsons/sqle/20.00/AI_RecognizeEntities.json +328 -0
  69. teradataml/data/jsons/sqle/20.00/AI_RecognizePIIEntities.json +328 -0
  70. teradataml/data/jsons/sqle/20.00/AI_TextClassifier.json +359 -0
  71. teradataml/data/jsons/sqle/20.00/AI_TextEmbeddings.json +360 -0
  72. teradataml/data/jsons/sqle/20.00/AI_TextSummarize.json +343 -0
  73. teradataml/data/jsons/sqle/20.00/AI_TextTranslate.json +343 -0
  74. teradataml/data/jsons/sqle/20.00/TD_SMOTE.json +2 -2
  75. teradataml/data/jsons/sqle/20.00/TD_VectorDistance.json +1 -1
  76. teradataml/data/ner_dict.csv +8 -0
  77. teradataml/data/ner_input_eng.csv +7 -0
  78. teradataml/data/ner_rule.csv +5 -0
  79. teradataml/data/pattern_matching_data.csv +11 -0
  80. teradataml/data/pos_input.csv +40 -0
  81. teradataml/data/sdk/modelops/modelops_spec.json +101737 -0
  82. teradataml/data/tdnerextractor_example.json +14 -0
  83. teradataml/data/teradataml_example.json +21 -1
  84. teradataml/data/textmorph_example.json +5 -0
  85. teradataml/data/to_num_data.csv +4 -0
  86. teradataml/data/tochar_data.csv +5 -0
  87. teradataml/data/trans_dense.csv +16 -0
  88. teradataml/data/trans_sparse.csv +55 -0
  89. teradataml/data/url_data.csv +10 -9
  90. teradataml/dataframe/copy_to.py +38 -27
  91. teradataml/dataframe/data_transfer.py +61 -45
  92. teradataml/dataframe/dataframe.py +1110 -132
  93. teradataml/dataframe/dataframe_utils.py +73 -27
  94. teradataml/dataframe/functions.py +1070 -9
  95. teradataml/dataframe/sql.py +750 -959
  96. teradataml/dbutils/dbutils.py +33 -13
  97. teradataml/dbutils/filemgr.py +14 -10
  98. teradataml/hyperparameter_tuner/utils.py +4 -2
  99. teradataml/lib/aed_0_1.dll +0 -0
  100. teradataml/opensource/_base.py +12 -157
  101. teradataml/options/configure.py +24 -9
  102. teradataml/scriptmgmt/UserEnv.py +317 -39
  103. teradataml/scriptmgmt/lls_utils.py +456 -135
  104. teradataml/sdk/README.md +79 -0
  105. teradataml/sdk/__init__.py +4 -0
  106. teradataml/sdk/_auth_modes.py +422 -0
  107. teradataml/sdk/_func_params.py +487 -0
  108. teradataml/sdk/_json_parser.py +453 -0
  109. teradataml/sdk/_openapi_spec_constants.py +249 -0
  110. teradataml/sdk/_utils.py +236 -0
  111. teradataml/sdk/api_client.py +897 -0
  112. teradataml/sdk/constants.py +62 -0
  113. teradataml/sdk/modelops/__init__.py +98 -0
  114. teradataml/sdk/modelops/_client.py +406 -0
  115. teradataml/sdk/modelops/_constants.py +304 -0
  116. teradataml/sdk/modelops/models.py +2308 -0
  117. teradataml/sdk/spinner.py +107 -0
  118. teradataml/store/__init__.py +1 -1
  119. teradataml/table_operators/Apply.py +16 -1
  120. teradataml/table_operators/Script.py +20 -1
  121. teradataml/table_operators/query_generator.py +4 -21
  122. teradataml/table_operators/table_operator_util.py +58 -9
  123. teradataml/utils/dtypes.py +4 -2
  124. teradataml/utils/internal_buffer.py +22 -2
  125. teradataml/utils/utils.py +0 -1
  126. teradataml/utils/validators.py +318 -58
  127. {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/METADATA +188 -14
  128. {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/RECORD +131 -84
  129. {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/WHEEL +0 -0
  130. {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/top_level.txt +0 -0
  131. {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/zip-safe +0 -0
@@ -0,0 +1,897 @@
1
+ # ################################################################################################
2
+ #
3
+ # Copyright 2025 Teradata. All rights reserved.
4
+ # TERADATA CONFIDENTIAL AND TRADE SECRET
5
+ #
6
+ # Primary Owner: Adithya Avvaru (adithya.avvaru@teradata.com)
7
+ # Secondary Owner: Pankaj Purandare (pankajvinod.purandare@teradata.com)
8
+ #
9
+ # Version: 1.0
10
+ # SDK Version: 1.0
11
+ #
12
+ # This file contains Client class for OpenAPI SDK.
13
+ # NOTE: It is currently taken from AoA SDK and is refactored to use the OpenAPI SDK client object.
14
+ #
15
+ # ################################################################################################
16
+
17
+ from __future__ import absolute_import
18
+
19
+ import json
20
+ import logging
21
+ import os
22
+ import time
23
+ from typing import Dict, List, Optional, Union
24
+
25
+ import requests
26
+ import yaml
27
+ from oauthlib.oauth2.rfc6749.errors import InvalidGrantError, InvalidTokenError
28
+ from requests.exceptions import ConnectionError
29
+
30
+ from teradataml.common.exceptions import (TeradataMlException,
31
+ TeradatamlRestException)
32
+ from teradataml.common.garbagecollector import GarbageCollector
33
+ from teradataml.common.messages import MessageCodes, Messages
34
+ from teradataml.utils.validators import _Validators
35
+
36
+ from ._auth_modes import BearerAuth, ClientCredentialsAuth, DeviceCodeAuth
37
+ from ._utils import _select_header_accept
38
+
39
+ os.system("") # enables ansi escape characters in terminal
40
+
41
+
42
+ class Client(object):
43
+ DEFAULT_CONFIG_DIR = os.path.join(GarbageCollector._get_temp_dir_name(), ".sdk")
44
+ DEFAULT_TOKEN_CACHE_FILE_PATH = os.path.join(DEFAULT_CONFIG_DIR, ".token")
45
+ DEFAULT_CONFIG_FILE_PATH = os.path.join(DEFAULT_CONFIG_DIR, "config.yaml")
46
+ MAX_RETRIES = 3
47
+ SDK_NAME = "BaseSDK"
48
+
49
+ def __init__(self, base_url=None, auth=None, ssl_verify=True, config_file=None):
50
+ """
51
+ DESCRIPTION:
52
+ Initializes the Client object and sets up the configuration for the client.
53
+
54
+ PARAMETERS:
55
+ base_url:
56
+ Optional Argument.
57
+ Specifies the base URL of API endpoint. All requests are made to a relative path to
58
+ this URL. It can be provided directly, or derived from the "BASE_URL" environment
59
+ variable or the YAML configuration variable "base_url". If not provided in any of
60
+ these 3 ways, appropriate Exception is raised.
61
+ Types: str or None
62
+
63
+ auth:
64
+ Optional Argument.
65
+ Specifies the type of authentication to be used. It can be one of the following
66
+ authentication type objects:
67
+ - ClientCredentialsAuth: For client credentials authentication.
68
+ - DeviceCodeAuth: For device code authentication.
69
+ - BearerAuth: For bearer token authentication.
70
+
71
+ Authentication mode is property of the auth object that is passed to this argument.
72
+ If this argument is not provided, authentication mode is derived from the
73
+ "BASE_API_AUTH_MODE" environment variable or the YAML configuration variable
74
+ "auth_mode". If this argument and the above 2 (environment variable and YAML
75
+ configuration variable) are not provided, appropriate Exception is raised.
76
+
77
+ For Authentication modes through environment variables without passing auth
78
+ argument and config file, the following environment variables are used:
79
+ - BASE_URL: Specifies the base URL of API endpoint.
80
+ - BASE_API_AUTH_MODE: Specifies the authentication mode. It can be one of the
81
+ following:
82
+ - "client_credentials": For client credentials authentication.
83
+ - "device_code": For device code authentication.
84
+ - "bearer": For bearer token authentication.
85
+ - BASE_SSL_VERIFY: Similar to 'ssl_verify' argument.
86
+ - BASE_API_AUTH_CLIENT_ID: OAuth2 client ID. Required for "client_credentials" and
87
+ "device_code" authentication modes.
88
+ - BASE_API_AUTH_CLIENT_SECRET: OAuth2 client secret. Required for "client_credentials"
89
+ and "device_code" authentication modes.
90
+ - BASE_API_AUTH_TOKEN_URL: OAuth2 token endpoint. Required for "client_credentials"
91
+ and "device_code" authentication modes.
92
+ - BASE_API_AUTH_DEVICE_AUTH_URL: OAuth2 device code endpoint. Required for
93
+ "device_code" authentication mode.
94
+ - BASE_API_AUTH_BEARER_TOKEN: The raw bearer token. Required for "bearer"
95
+ authentication.
96
+
97
+ Note:
98
+ - For device_code authentication, token is searched in "~/.teradataml/sdk/.token".
99
+ If it is not present, token is created, used for authentication and saved in
100
+ the same location.
101
+
102
+ Types: ClientCredentialsAuth, DeviceCodeAuth, BearerAuth or None
103
+
104
+ ssl_verify:
105
+ Optional Argument.
106
+ Specifies whether to enable or disable TLS Cert validation. If True, TLS cert
107
+ validation is enabled. If False, TLS cert validation is disabled. It can be provided
108
+ directly, or derived from the "BASE_SSL_VERIFY" environment variable or the YAML
109
+ configuration variable "ssl_verify". If ssl_verify is not provided in any of
110
+ these 3 ways, it is set to True by default.
111
+ Default Value: True (Enable TLS cert validation)
112
+ Types: bool or None
113
+
114
+ config_file:
115
+ Optional Argument.
116
+ Specifies the path to the YAML configuration file.
117
+
118
+ Note:
119
+ - At least one of YAML config file or environment variables or above arguments
120
+ must be provided. If not provided, appropriate Exception is raised.
121
+ - If config_file is not provided, the default config file
122
+ ~/.teradataml/sdk/config.yaml is used. If the default config file is not
123
+ found, this function tries to read the configuration from the environment
124
+ variables or other arguments.
125
+
126
+ If YAML file is provided, it should have the following details, depending on the
127
+ what is provided in other arguments:
128
+ - ssl_verify (bool) : Same as ssl_verify argument.
129
+ - base_url (str) : Same as base_url argument.
130
+ - auth_mode (str) : Authentication mode to be used. It can be one of the following:
131
+ - client_credentials: For client credentials authentication.
132
+ - device_code: For device code authentication.
133
+ - bearer: For bearer token authentication.
134
+ - auth_client_id (str) : OAuth2 client ID. Required for client_credentials and
135
+ device_code authentication modes.
136
+ - auth_client_secret (str) : OAuth2 client secret. Required for client_credentials
137
+ and device_code authentication modes.
138
+ - auth_token_url (str) : OAuth2 token endpoint. Required for client_credentials and
139
+ device_code authentication modes.
140
+ - auth_device_auth_url (str) : OAuth2 device code endpoint. Required for device_code
141
+ authentication mode.
142
+ - auth_bearer (str) : The raw bearer token. Required for bearer authentication mode.
143
+
144
+ Types: str or None
145
+
146
+ RETURNS:
147
+ None
148
+
149
+ RAISES:
150
+ - TeradataMlException: If the base_url, auth_mode, or ssl_verify is not provided in
151
+ any of the 3 ways (YAML config file, environment variables, or constructor arguments).
152
+ - ValueError: If the base_url is not provided in any of the 3 ways.
153
+ - FileNotFoundError: If the specified YAML file does not exist.
154
+ - yaml.YAMLError: If there is an error in parsing the YAML file.
155
+
156
+ EXAMPLES:
157
+ >>> from teradataml.sdk import Client, ClientCredentialsAuth, DeviceCodeAuth
158
+ >>> import os
159
+
160
+ # Example 1: Using a custom configuration file for client credentials authentication.
161
+ >>> cc_auth_dict = {"auth_client_id": "your_client_id",
162
+ "auth_client_secret": "your_client_secret",
163
+ "auth_token_url": "https://example.com/token",
164
+ "auth_mode": "client_credentials",
165
+ "base_url": "https://example.com",
166
+ "ssl_verify": False}
167
+
168
+ >>> # Write data to config file.
169
+ >>> cc_config_file = "custom_config.yaml"
170
+ >>> import yaml
171
+ >>> with open(cc_config_file, "w") as f:
172
+ yaml.dump(cc_auth_dict, f, sort_keys=False)
173
+
174
+ >>> # Create client object using config file.
175
+ >>> obj = Client(config_file=cc_config_file)
176
+
177
+ # Example 2: Using environment variables.
178
+ >>> os.environ["BASE_URL"] = "https://example.com"
179
+ >>> os.environ["BASE_API_AUTH_MODE"] = "client_credentials"
180
+ >>> os.environ["BASE_API_AUTH_CLIENT_ID"] = "your_client_id"
181
+ >>> os.environ["BASE_API_AUTH_CLIENT_SECRET"] = "your_client_secret"
182
+ >>> os.environ["BASE_API_AUTH_TOKEN_URL"] = "https://example.com/token"
183
+ >>> os.environ["BASE_SSL_VERIFY"] = "false"
184
+ >>> obj = Client()
185
+
186
+ # Example 3: Using constructor arguments.
187
+ >>> obj = Client(
188
+ base_url="https://example.com",
189
+ auth=DeviceCodeAuth(
190
+ auth_client_id="your_client_id",
191
+ auth_client_secret="your_client_secret",
192
+ auth_token_url="https://example.com/token",
193
+ auth_device_auth_url="https://example.com/device_auth"
194
+ ),
195
+ ssl_verify=True
196
+ )
197
+
198
+ """
199
+ self.logger = logging.getLogger(__name__)
200
+
201
+ os.makedirs(self.DEFAULT_CONFIG_DIR, exist_ok=True)
202
+
203
+
204
+ arg_info_matrix = []
205
+ arg_info_matrix.append(["base_url", base_url, True, (str,)])
206
+ arg_info_matrix.append(["ssl_verify", ssl_verify, True, (bool,)])
207
+ arg_info_matrix.append(["config_file", config_file, True, (str,)])
208
+ arg_info_matrix.append(["auth", auth, True, (ClientCredentialsAuth, DeviceCodeAuth, BearerAuth)])
209
+
210
+ _Validators._validate_function_arguments(arg_info_matrix)
211
+
212
+ # Client config file.
213
+ self.__config_file = config_file
214
+ self.yaml_config = self.__parse_yaml()
215
+
216
+ # Keep all required parameters in the constructor without any default values.
217
+ # They is updated while parsing the config file, environment variables and constructor arguments.
218
+
219
+ ## Step 1: Process SSL Verify.
220
+ self.__process_ssl_verify(ssl_verify=ssl_verify)
221
+
222
+ ## Step 2: Process Endpoint URL.
223
+ # Raise error if base_url is not provided in config file or environment variable or constructor.
224
+ self.__process_endpoint_url(base_url=base_url)
225
+
226
+ ## Step 3: Process Auth Mode.
227
+ # Raise error if auth_mode is not provided in config file or environment variable or
228
+ # through constructor argument "auth".
229
+ self.__process_auth_mode(auth=auth)
230
+
231
+ ## Step 3: Process Auth and create auth object if "auth" argument is not provided.
232
+ auth = self.__process_auth(auth=auth)
233
+
234
+ # Set required parameters for auth objects before calling authenticate method.
235
+ # These parameters are used in the authenticate method of the auth object.
236
+ auth._ssl_verify = self.ssl_verify
237
+ auth._base_url = self.base_url
238
+
239
+
240
+ if self.auth_mode == DeviceCodeAuth.AUTH_MODE.value:
241
+ try:
242
+ self.session = auth.authenticate(token_cache_file_path=self.DEFAULT_TOKEN_CACHE_FILE_PATH)
243
+ except InvalidGrantError as ge:
244
+ if ge.description in ["Token is not active", "Session not active"]:
245
+ logging.warning(ge.description + "\nRetrying one more time\n")
246
+
247
+ self.__remove_cached_token()
248
+
249
+ self.session = auth.authenticate(token_cache_file_path=self.DEFAULT_TOKEN_CACHE_FILE_PATH)
250
+ else:
251
+ raise ge
252
+ except InvalidTokenError as ge:
253
+ logging.warning(ge.description + "\nRetrying one more time\n")
254
+
255
+ self.__remove_cached_token()
256
+
257
+ self.__create_oauth_session_device_code()
258
+ else:
259
+ self.session = auth.authenticate()
260
+
261
+ logging.info(f"Connected to {self.base_url}")
262
+
263
+ def __raise_exception_for_args(self, auth_mode, missing_value):
264
+ raise TeradataMlException(Messages.get_message(MessageCodes.REST_AUTH_MISSING_ARG,
265
+ auth_mode,
266
+ missing_value),
267
+ MessageCodes.REST_AUTH_MISSING_ARG)
268
+
269
+ def __parse_yaml(self):
270
+ """
271
+ DESCRIPTION:
272
+ Parses a YAML configuration file to extract and load configuration settings.
273
+
274
+ PARAMETERS:
275
+ - None
276
+
277
+ RETURNS:
278
+ None
279
+
280
+ RAISES:
281
+ - FileNotFoundError: If the specified YAML file does not exist.
282
+ - yaml.YAMLError: If there is an error in parsing the YAML file.
283
+
284
+ EXAMPLES:
285
+ # Example 1: Using a custom configuration file
286
+ obj = Client(config_file="custom_config.yaml")
287
+ obj.__parse_yaml()
288
+
289
+ # Example 2: Using the default configuration file
290
+ obj = Client()
291
+ obj.__parse_yaml()
292
+ """
293
+
294
+ yaml_file_path = None
295
+ if self.__config_file is not None:
296
+ yaml_file_path = self.__config_file
297
+ elif os.path.isfile(self.DEFAULT_CONFIG_FILE_PATH):
298
+ yaml_file_path = self.DEFAULT_CONFIG_FILE_PATH
299
+ if yaml_file_path:
300
+ with open(yaml_file_path, "r") as handle:
301
+ conf = yaml.safe_load(handle)
302
+ return conf
303
+ return {}
304
+
305
+ def __process_ssl_verify(self, ssl_verify):
306
+ """
307
+ DESCRIPTION:
308
+ Processes the SSL verification configuration by determining its value based on the
309
+ provided argument, environment variables, and YAML configuration. If no value is set,
310
+ it defaults to True.
311
+
312
+
313
+ PARAMETERS:
314
+ - ssl_verify: Optional Argument
315
+ Specifies whether SSL verification is enabled. Can be provided directly,
316
+ or derived from the "BASE_SSL_VERIFY" environment variable or
317
+ the YAML configuration variable "ssl_verify".
318
+ Type: bool or None
319
+
320
+ RETURNS:
321
+ None
322
+
323
+ RAISES:
324
+ None
325
+
326
+ EXAMPLES:
327
+ # Create client object.
328
+ obj = Client(....)
329
+
330
+ # Example 1: Directly passing the ssl_verify argument
331
+ obj.__process_ssl_veify(ssl_verify=True)
332
+
333
+ # Example 2: Using environment variable "BASE_SSL_VERIFY"
334
+ os.environ["BASE_SSL_VERIFY"] = "false"
335
+ obj.__process_ssl_veify(ssl_verify=None)
336
+
337
+ # Example 3: Using YAML configuration
338
+ obj.yaml_config = {"ssl_verify": False}
339
+ obj.__process_ssl_veify(ssl_verify=None)
340
+ """
341
+
342
+ self.ssl_verify = ssl_verify or \
343
+ os.environ.get("BASE_SSL_VERIFY", str(ssl_verify)).lower() == "true" or \
344
+ self.yaml_config.get("ssl_verify", False)
345
+
346
+ if self.ssl_verify is None:
347
+ # Set default SSL Verify to True if not set in config file or environment variable
348
+ # or constructor.
349
+ self.ssl_verify = True
350
+
351
+ def __process_endpoint_url(self, base_url: Optional[str]=None):
352
+ """
353
+ DESCRIPTION:
354
+ Processes the base URL configuration by determining its value based on the
355
+ provided argument, environment variables, and YAML configuration. If no value is set,
356
+ it raises an Exception.
357
+
358
+ PARAMETERS:
359
+ - base_url: Optional Argument
360
+ Specifies the base URL. Can be provided directly,
361
+ or derived from the "BASE_URL" environment variable or
362
+ the YAML configuration variable "base_url".
363
+ Type: str or None
364
+
365
+ RETURNS:
366
+ None
367
+
368
+ RAISES:
369
+ TeradataMlException: If no endpoint URL is provided.
370
+
371
+ EXAMPLES:
372
+ # Create client object.
373
+ obj = Client(....)
374
+
375
+ # Example 1: Directly passing the base_url argument
376
+ obj.__process_endpoint_url(base_url="https://example.com")
377
+
378
+ # Example 2: Using environment variable "BASE_URL"
379
+ os.environ["BASE_URL"] = "https://example.com"
380
+ obj.__process_endpoint_url(base_url=None)
381
+
382
+ # Example 3: Using YAML configuration
383
+ obj.yaml_config = {"base_url": "https://example.com"}
384
+ obj.__process_endpoint_url(base_url=None)
385
+ """
386
+ self.base_url = base_url or \
387
+ os.environ.get("BASE_URL", None) or \
388
+ self.yaml_config.get("base_url", "")
389
+
390
+ if not self.base_url:
391
+ raise TeradataMlException(Messages.get_message(MessageCodes.REST_NOT_CONFIGURED,
392
+ "base_url",
393
+ self.SDK_NAME,
394
+ self.SDK_NAME),
395
+ MessageCodes.REST_NOT_CONFIGURED)
396
+
397
+ def __process_auth_mode(self, auth: Union[DeviceCodeAuth, ClientCredentialsAuth, BearerAuth]):
398
+ """
399
+ DESCRIPTION:
400
+ Processes the authentication mode configuration by determining its value based on the
401
+ provided argument "auth", environment variables, and YAML configuration.
402
+
403
+ PARAMETERS:
404
+ - auth: Optional Argument
405
+ Specifies the authentication mode. Can be provided directly,
406
+ or derived from the "BASE_API_AUTH_MODE" environment variable or
407
+ the YAML configuration variable "auth_mode".
408
+ Type: str or None
409
+
410
+ RETURNS:
411
+ None
412
+
413
+ RAISES:
414
+ TeradataMlException: If no authentication mode is provided.
415
+
416
+ EXAMPLES:
417
+ # Create client object.
418
+ obj = Client(....)
419
+
420
+ # Example 1: Directly passing the auth argument
421
+ obj.__process_auth_mode(auth="client_credentials")
422
+
423
+ # Example 2: Using environment variable "BASE_API_AUTH_MODE"
424
+ os.environ["BASE_API_AUTH_MODE"] = "bearer"
425
+ obj.__process_auth_mode(auth=None)
426
+
427
+ # Example 3: Using YAML configuration
428
+ obj.yaml_config = {"auth_mode": "device_code"}
429
+ obj.__process_auth_mode(auth=None)
430
+ """
431
+ self.auth_mode = (auth.AUTH_MODE.value if auth else None) or \
432
+ os.environ.get("BASE_API_AUTH_MODE", None) or \
433
+ self.yaml_config.get("auth_mode", None)
434
+
435
+ if not self.auth_mode:
436
+ raise TeradataMlException(Messages.get_message(MessageCodes.REST_NOT_CONFIGURED,
437
+ "auth",
438
+ self.SDK_NAME,
439
+ self.SDK_NAME),
440
+ MessageCodes.REST_NOT_CONFIGURED)
441
+
442
+ self.__update_legacy_auth_mode()
443
+
444
+ def __process_auth(self, auth):
445
+ """
446
+ DESCRIPTION:
447
+ Processes the authentication configuration by determining its value based on the
448
+ provided argument "auth", environment variables, and YAML configuration.
449
+
450
+ PARAMETERS:
451
+ - auth: Optional Argument
452
+ Specifies the authentication mode. Can be provided directly,
453
+ or derived from the "BASE_API_AUTH_MODE" environment variable or
454
+ the YAML configuration variable "auth_mode".
455
+ Type: str or None
456
+
457
+ RETURNS:
458
+ None
459
+
460
+ RAISES:
461
+ TeradataMlException: If no authentication mode is provided.
462
+
463
+ EXAMPLES:
464
+ # Create client object.
465
+ obj = Client(....)
466
+
467
+ # Example 1: Directly passing the auth argument
468
+ obj.__process_auth(auth="client_credentials")
469
+
470
+ # Example 2: Using environment variable "BASE_API_AUTH_MODE"
471
+ os.environ["BASE_API_AUTH_MODE"] = "bearer"
472
+ obj.__process_auth(auth=None)
473
+
474
+ # Example 3: Using YAML configuration
475
+ obj.yaml_config = {"auth_mode": "device_code"}
476
+ obj.__process_auth(auth=None)
477
+ """
478
+ if auth is None:
479
+ if self.auth_mode == BearerAuth.AUTH_MODE.value:
480
+ # Create Bearer auth object.
481
+ self.__bearer_token = os.environ.get("BASE_API_AUTH_BEARER_TOKEN", None) or \
482
+ self.yaml_config.get("auth_bearer")
483
+ self.__raise_exception_for_args(self.auth_mode, "Bearer token") if not self.__bearer_token \
484
+ else None
485
+ auth = BearerAuth(auth_bearer=self.__bearer_token)
486
+
487
+ else:
488
+ # Create ClientCredentials or DeviceCode auth object.
489
+ self.__client_id = os.environ.get("BASE_API_AUTH_CLIENT_ID", None) or \
490
+ self.yaml_config.get("auth_client_id")
491
+ self.__raise_exception_for_args(self.auth_mode, "Client ID") if not self.__client_id \
492
+ else None
493
+
494
+ self.__client_secret = os.environ.get("BASE_API_AUTH_CLIENT_SECRET", None) or \
495
+ self.yaml_config.get("auth_client_secret")
496
+ if self.auth_mode == ClientCredentialsAuth.AUTH_MODE.value:
497
+ # Client Secret is required for client_credentials authentication.
498
+ # It can be empty for device_code authentication.
499
+ # Raise error if client_secret is not provided for client_credentials authentication.
500
+ self.__raise_exception_for_args(self.auth_mode, "Client Secret") if not self.__client_secret \
501
+ else None
502
+
503
+ self.__token_url = os.environ.get("BASE_API_AUTH_TOKEN_URL", None) or \
504
+ self.yaml_config.get("auth_token_url")
505
+ self.__raise_exception_for_args(self.auth_mode, "Token URL") if not self.__token_url \
506
+ else None
507
+
508
+ if self.auth_mode == ClientCredentialsAuth.AUTH_MODE.value:
509
+ # Create ClientCredentials auth object.
510
+ auth = ClientCredentialsAuth(
511
+ auth_client_id=self.__client_id,
512
+ auth_client_secret=self.__client_secret,
513
+ auth_token_url=self.__token_url,
514
+ )
515
+
516
+ elif self.auth_mode == DeviceCodeAuth.AUTH_MODE.value:
517
+ # Create DeviceCode auth object.
518
+ self.__device_auth_url = os.environ.get("BASE_API_AUTH_DEVICE_AUTH_URL", None) \
519
+ or self.yaml_config.get("auth_device_auth_url")
520
+ self.__raise_exception_for_args(self.auth_mode, "Device Auth URL") \
521
+ if not self.__device_auth_url else None
522
+
523
+ auth = DeviceCodeAuth(
524
+ auth_client_id=self.__client_id,
525
+ auth_client_secret=self.__client_secret,
526
+ auth_token_url=self.__token_url,
527
+ auth_device_auth_url=self.__device_auth_url,
528
+ )
529
+ else:
530
+ raise ValueError(
531
+ "Invalid auth mode. Please use either "
532
+ "'client_credentials' [ClientCredentialsAuth() in 'auth' argument] or "\
533
+ "'device_code' [DeviceCodeAuth() in 'auth' argument] or "\
534
+ "'bearer' [BearerAuth() in 'auth' argument]."
535
+ )
536
+ return auth
537
+
538
+ def __update_legacy_auth_mode(self):
539
+ if self.auth_mode == "oauth-cc":
540
+ self.auth_mode = "client_credentials"
541
+ elif self.auth_mode == "oauth":
542
+ self.auth_mode = "device_code"
543
+
544
+ def get_request(self, path, header_params: Dict[str, str], query_params: Dict[str, str]):
545
+ """
546
+ DESCRIPTION:
547
+ Sends a GET request to the specified API endpoint using the provided parameters.
548
+
549
+ PARAMETERS:
550
+ path:
551
+ Required Argument.
552
+ Specifies the URL path for the API endpoint along with path parameters.
553
+ Note:
554
+ It should be a relative path to the base URL.
555
+ Types: str
556
+
557
+ header_params:
558
+ Required Argument.
559
+ Specifies the header parameters to be included in the request.
560
+ Types: dict
561
+
562
+ query_params:
563
+ Required Argument.
564
+ Specifies the query parameters to be included in the request.
565
+ Types: dict
566
+
567
+ RETURNS:
568
+ dict for resources if the request is successful, None if resource is not found (404), or str for errors.
569
+
570
+ RAISES:
571
+ TeradatamlRestException: If a network or HTTP error occurs.
572
+ HTTPError: If the response contains an HTTP error status code.
573
+
574
+ EXAMPLES:
575
+ >>> client = Client(...)
576
+ >>> client.get_request("/api/projects", header_params, query_params)
577
+ """
578
+ retry = 0
579
+
580
+ while retry < self.MAX_RETRIES:
581
+ try:
582
+ resp = self.session.get(
583
+ url=self.__strip_url(self.base_url) + path,
584
+ headers=header_params,
585
+ params=query_params,
586
+ )
587
+
588
+ if resp.status_code == 404:
589
+ return None
590
+
591
+ return self.__validate_and_extract_body(resp)
592
+
593
+ except ConnectionError:
594
+ retry += 1
595
+ time.sleep(5)
596
+
597
+ except Exception as e:
598
+ raise TeradatamlRestException(
599
+ Messages.get_message(MessageCodes.REST_HTTP_ERROR, e),
600
+ MessageCodes.REST_HTTP_ERROR,
601
+ str(e))
602
+
603
+ if retry == self.MAX_RETRIES:
604
+ logging.error("Max retries reached. Please check your network connection.")
605
+ return None
606
+
607
+ def post_request(
608
+ self,
609
+ path,
610
+ header_params: Dict[str, str],
611
+ query_params: Dict[str, str],
612
+ body: Dict[str, str],
613
+ ):
614
+ """
615
+ DESCRIPTION:
616
+ Sends a POST request to the specified API endpoint with the provided body and parameters.
617
+
618
+ PARAMETERS:
619
+ path:
620
+ Required Argument.
621
+ Specifies the URL path for the API endpoint along with path parameters.
622
+ Note:
623
+ It should be a relative path to the base URL.
624
+ Types: str
625
+
626
+ header_params:
627
+ Required Argument.
628
+ Specifies the header parameters to be included in the request.
629
+ Types: dict
630
+
631
+ query_params:
632
+ Required Argument.
633
+ Specifies the query parameters to be included in the request.
634
+ Types: dict
635
+
636
+ body:
637
+ Required Argument.
638
+ Specifies the request body to be sent in the POST request.
639
+ Types: dict
640
+
641
+ RETURNS:
642
+ dict for resources if the request is successful, or str for errors.
643
+
644
+ RAISES:
645
+ HTTPError: If the response contains an HTTP error status code.
646
+
647
+ EXAMPLES:
648
+ >>> client = Client(...)
649
+ >>> client.post_request("/api/projects", header_params, query_params, body)
650
+ """
651
+
652
+ resp = self.session.post(
653
+ url=self.__strip_url(self.base_url) + path,
654
+ headers=header_params,
655
+ params=query_params,
656
+ data=json.dumps(body),
657
+ )
658
+
659
+ return self.__validate_and_extract_body(resp)
660
+
661
+ def put_request(
662
+ self,
663
+ path,
664
+ header_params: Dict[str, str],
665
+ query_params: Dict[str, str],
666
+ body: Dict[str, str],
667
+ ):
668
+ """
669
+ DESCRIPTION:
670
+ Sends a PUT request to the specified API endpoint with the provided body and parameters.
671
+
672
+ PARAMETERS:
673
+ path:
674
+ Required Argument.
675
+ Specifies the URL path for the API endpoint along with path parameters.
676
+ Note:
677
+ It should be a relative path to the base URL.
678
+ Types: str
679
+
680
+ header_params:
681
+ Required Argument.
682
+ Specifies the header parameters to be included in the request.
683
+ Types: dict
684
+
685
+ query_params:
686
+ Required Argument.
687
+ Specifies the query parameters to be included in the request.
688
+ Types: dict
689
+
690
+ body:
691
+ Required Argument.
692
+ Specifies the request body to be sent in the PUT request.
693
+ Types: dict
694
+
695
+ RETURNS:
696
+ dict for resources if the request is successful, or str for errors.
697
+
698
+ RAISES:
699
+ HTTPError: If the response contains an HTTP error status code.
700
+
701
+ EXAMPLES:
702
+ >>> client = Client(...)
703
+ >>> client.put_request("/api/projects/123", header_params, query_params, body)
704
+ """
705
+
706
+ resp = self.session.put(
707
+ url=self.__strip_url(self.base_url) + path,
708
+ headers=header_params,
709
+ params=query_params,
710
+ data=json.dumps(body),
711
+ )
712
+
713
+ return self.__validate_and_extract_body(resp)
714
+
715
+ def patch_request(self,
716
+ path,
717
+ header_params: Dict[str, str],
718
+ query_params: Dict[str, str],
719
+ body: Dict[str, str]
720
+ ):
721
+ """
722
+ DESCRIPTION:
723
+ Sends a PATCH request to the specified API endpoint with the provided body and parameters.
724
+
725
+ PARAMETERS:
726
+ path:
727
+ Required Argument.
728
+ Specifies the URL path for the API endpoint along with path parameters.
729
+ Note:
730
+ It should be a relative path to the base URL.
731
+ Types: str
732
+
733
+ header_params:
734
+ Required Argument.
735
+ Specifies the header parameters to be included in the request.
736
+ Types: dict
737
+
738
+ query_params:
739
+ Required Argument.
740
+ Specifies the query parameters to be included in the request.
741
+ Types: dict
742
+
743
+ body:
744
+ Required Argument.
745
+ Specifies the request body to be sent in the PATCH request.
746
+ Types: dict
747
+
748
+ RETURNS:
749
+ dict for resources if the request is successful, or str for errors.
750
+
751
+ RAISES:
752
+ HTTPError: If the response contains an HTTP error status code.
753
+
754
+ EXAMPLES:
755
+ >>> client = Client(...)
756
+ >>> client.patch_request("/api/projects/123", header_params, query_params, body)
757
+ """
758
+
759
+ resp = self.session.patch(
760
+ url=self.__strip_url(self.base_url) + path,
761
+ headers=header_params,
762
+ params=query_params,
763
+ data=json.dumps(body),
764
+ )
765
+
766
+ return self.__validate_and_extract_body(resp)
767
+
768
+ def delete_request(
769
+ self,
770
+ path,
771
+ header_params: Dict[str, str],
772
+ query_params: Dict[str, str],
773
+ body: Dict[str, str],
774
+ ):
775
+ """
776
+ DESCRIPTION:
777
+ Sends a DELETE request to the specified API endpoint with the provided body and parameters.
778
+
779
+ PARAMETERS:
780
+ path:
781
+ Required Argument.
782
+ Specifies the URL path for the API endpoint along with path parameters.
783
+ Note:
784
+ It should be a relative path to the base URL.
785
+ Types: str
786
+
787
+ header_params:
788
+ Required Argument.
789
+ Specifies the header parameters to be included in the request.
790
+ Types: dict
791
+
792
+ query_params:
793
+ Required Argument.
794
+ Specifies the query parameters to be included in the request.
795
+ Types: dict
796
+
797
+ body:
798
+ Required Argument.
799
+ Specifies the request body to be sent in the DELETE request.
800
+ Types: dict
801
+
802
+ RETURNS:
803
+ dict for resources if the request is successful, or str for errors.
804
+
805
+ RAISES:
806
+ HTTPError: If the response contains an HTTP error status code.
807
+
808
+ EXAMPLES:
809
+ >>> client = Client(...)
810
+ >>> client.delete_request("/api/projects/123", header_params, query_params, body)
811
+ """
812
+
813
+ resp = self.session.delete(
814
+ url=self.__strip_url(self.base_url) + path,
815
+ headers=header_params,
816
+ params=query_params,
817
+ data=json.dumps(body),
818
+ )
819
+
820
+ return self.__validate_and_extract_body(resp)
821
+
822
+ def __validate_and_extract_body(self, resp):
823
+ if resp.status_code == 401:
824
+ self.__remove_cached_token()
825
+ self.logger.warning(
826
+ "Clearing the token cache. Please re-run cmd and login again."
827
+ )
828
+
829
+ try:
830
+ resp.raise_for_status()
831
+ except requests.exceptions.HTTPError as err:
832
+ if resp.text:
833
+ raise requests.exceptions.HTTPError(f"Error message: {resp.text}")
834
+ else:
835
+ raise err
836
+
837
+ try:
838
+ return resp.json()
839
+ except ValueError:
840
+ return resp.text
841
+
842
+ def __strip_url(self, url):
843
+ return url.rstrip("/")
844
+
845
+ def __remove_cached_token(self):
846
+ if os.path.exists(self.__class__.DEFAULT_TOKEN_CACHE_FILE_PATH):
847
+ os.remove(self.__class__.DEFAULT_TOKEN_CACHE_FILE_PATH)
848
+
849
+ def _prepare_header_dict(self, content_type: Optional[Union[str, List[str]]] = "application/json",
850
+ accept: Optional[Union[str, List[str]]] = "application/json",
851
+ additional_headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
852
+ """
853
+ DESCRIPTION:
854
+ Prepares a header dictionary for API requests.
855
+
856
+ PARAMETERS:
857
+ content_type:
858
+ Optional Argument.
859
+ Specifies the Content-Type header value(s) to be included in the request.
860
+ Default Value: "application/json"
861
+ Types: List[str]
862
+
863
+ accept:
864
+ Optional Argument.
865
+ Specifies the Accept header value(s) to be included in the request.
866
+ Default Value: "application/json"
867
+ Types: List[str]
868
+
869
+ additional_headers:
870
+ Optional Argument.
871
+ Specifies any additional headers to be included in the request.
872
+ Types: Dict[str, str]
873
+
874
+ RETURNS:
875
+ A dictionary containing the prepared headers.
876
+
877
+ RAISES:
878
+ None
879
+
880
+ EXAMPLES:
881
+ >>> client = Client(...)
882
+ >>> headers = client._prepare_header_dict(content_type=["application/json"], accept=["application/json"])
883
+ """
884
+ headers = {}
885
+
886
+ if isinstance(content_type, str):
887
+ content_type = [content_type]
888
+ headers["Content-Type"] = _select_header_accept(content_type) if content_type else "application/json"
889
+
890
+ if isinstance(accept, str):
891
+ accept = [accept]
892
+ headers["Accept"] = _select_header_accept(accept) if accept else "application/json"
893
+
894
+ if additional_headers:
895
+ headers.update(additional_headers)
896
+
897
+ return headers