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.
- teradataml/LICENSE-3RD-PARTY.pdf +0 -0
- teradataml/README.md +182 -13
- teradataml/__init__.py +2 -1
- teradataml/_version.py +2 -2
- teradataml/analytics/analytic_function_executor.py +8 -13
- teradataml/analytics/json_parser/analytic_functions_argument.py +4 -0
- teradataml/analytics/sqle/__init__.py +16 -1
- teradataml/analytics/utils.py +60 -1
- teradataml/automl/__init__.py +290 -106
- teradataml/automl/autodataprep/__init__.py +471 -0
- teradataml/automl/data_preparation.py +29 -10
- teradataml/automl/data_transformation.py +11 -0
- teradataml/automl/feature_engineering.py +64 -4
- teradataml/automl/feature_exploration.py +639 -25
- teradataml/automl/model_training.py +1 -1
- teradataml/clients/auth_client.py +12 -8
- teradataml/clients/keycloak_client.py +165 -0
- teradataml/common/constants.py +71 -26
- teradataml/common/exceptions.py +32 -0
- teradataml/common/messagecodes.py +28 -0
- teradataml/common/messages.py +13 -4
- teradataml/common/sqlbundle.py +3 -2
- teradataml/common/utils.py +345 -45
- teradataml/context/context.py +259 -93
- teradataml/data/apriori_example.json +22 -0
- teradataml/data/docs/sqle/docs_17_20/Apriori.py +138 -0
- teradataml/data/docs/sqle/docs_17_20/NERExtractor.py +121 -0
- teradataml/data/docs/sqle/docs_17_20/NGramSplitter.py +3 -3
- teradataml/data/docs/sqle/docs_17_20/SMOTE.py +212 -0
- teradataml/data/docs/sqle/docs_17_20/TextMorph.py +119 -0
- teradataml/data/docs/sqle/docs_17_20/TextParser.py +54 -3
- teradataml/data/docs/uaf/docs_17_20/ACF.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/ArimaEstimate.py +2 -2
- teradataml/data/docs/uaf/docs_17_20/ArimaXEstimate.py +2 -2
- teradataml/data/docs/uaf/docs_17_20/DFFT.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/DFFT2.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/DFFT2Conv.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/DFFTConv.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/FilterFactory1d.py +4 -4
- teradataml/data/docs/uaf/docs_17_20/GenseriesSinusoids.py +2 -2
- teradataml/data/docs/uaf/docs_17_20/GoldfeldQuandt.py +2 -2
- teradataml/data/docs/uaf/docs_17_20/HoltWintersForecaster.py +6 -6
- teradataml/data/docs/uaf/docs_17_20/LineSpec.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/LinearRegr.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/Matrix2Image.py +4 -4
- teradataml/data/docs/uaf/docs_17_20/MultivarRegr.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/PACF.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/PowerSpec.py +2 -2
- teradataml/data/docs/uaf/docs_17_20/PowerTransform.py +3 -3
- teradataml/data/docs/uaf/docs_17_20/Resample.py +5 -5
- teradataml/data/docs/uaf/docs_17_20/SAX.py +3 -3
- teradataml/data/docs/uaf/docs_17_20/SignifPeriodicities.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/SimpleExp.py +1 -1
- teradataml/data/docs/uaf/docs_17_20/Smoothma.py +3 -3
- teradataml/data/docs/uaf/docs_17_20/UNDIFF.py +1 -1
- teradataml/data/jsons/byom/onnxembeddings.json +1 -0
- teradataml/data/jsons/sqle/17.20/NGramSplitter.json +6 -6
- teradataml/data/jsons/sqle/17.20/TD_Apriori.json +181 -0
- teradataml/data/jsons/sqle/17.20/TD_NERExtractor.json +145 -0
- teradataml/data/jsons/sqle/17.20/TD_SMOTE.json +267 -0
- teradataml/data/jsons/sqle/17.20/TD_TextMorph.json +134 -0
- teradataml/data/jsons/sqle/17.20/TD_TextParser.json +114 -9
- teradataml/data/jsons/sqle/20.00/AI_AnalyzeSentiment.json +328 -0
- teradataml/data/jsons/sqle/20.00/AI_AskLLM.json +420 -0
- teradataml/data/jsons/sqle/20.00/AI_DetectLanguage.json +343 -0
- teradataml/data/jsons/sqle/20.00/AI_ExtractKeyPhrases.json +328 -0
- teradataml/data/jsons/sqle/20.00/AI_MaskPII.json +328 -0
- teradataml/data/jsons/sqle/20.00/AI_RecognizeEntities.json +328 -0
- teradataml/data/jsons/sqle/20.00/AI_RecognizePIIEntities.json +328 -0
- teradataml/data/jsons/sqle/20.00/AI_TextClassifier.json +359 -0
- teradataml/data/jsons/sqle/20.00/AI_TextEmbeddings.json +360 -0
- teradataml/data/jsons/sqle/20.00/AI_TextSummarize.json +343 -0
- teradataml/data/jsons/sqle/20.00/AI_TextTranslate.json +343 -0
- teradataml/data/jsons/sqle/20.00/TD_SMOTE.json +2 -2
- teradataml/data/jsons/sqle/20.00/TD_VectorDistance.json +1 -1
- teradataml/data/ner_dict.csv +8 -0
- teradataml/data/ner_input_eng.csv +7 -0
- teradataml/data/ner_rule.csv +5 -0
- teradataml/data/pattern_matching_data.csv +11 -0
- teradataml/data/pos_input.csv +40 -0
- teradataml/data/sdk/modelops/modelops_spec.json +101737 -0
- teradataml/data/tdnerextractor_example.json +14 -0
- teradataml/data/teradataml_example.json +21 -1
- teradataml/data/textmorph_example.json +5 -0
- teradataml/data/to_num_data.csv +4 -0
- teradataml/data/tochar_data.csv +5 -0
- teradataml/data/trans_dense.csv +16 -0
- teradataml/data/trans_sparse.csv +55 -0
- teradataml/data/url_data.csv +10 -9
- teradataml/dataframe/copy_to.py +38 -27
- teradataml/dataframe/data_transfer.py +61 -45
- teradataml/dataframe/dataframe.py +1110 -132
- teradataml/dataframe/dataframe_utils.py +73 -27
- teradataml/dataframe/functions.py +1070 -9
- teradataml/dataframe/sql.py +750 -959
- teradataml/dbutils/dbutils.py +33 -13
- teradataml/dbutils/filemgr.py +14 -10
- teradataml/hyperparameter_tuner/utils.py +4 -2
- teradataml/lib/aed_0_1.dll +0 -0
- teradataml/opensource/_base.py +12 -157
- teradataml/options/configure.py +24 -9
- teradataml/scriptmgmt/UserEnv.py +317 -39
- teradataml/scriptmgmt/lls_utils.py +456 -135
- 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/store/__init__.py +1 -1
- teradataml/table_operators/Apply.py +16 -1
- teradataml/table_operators/Script.py +20 -1
- teradataml/table_operators/query_generator.py +4 -21
- teradataml/table_operators/table_operator_util.py +58 -9
- teradataml/utils/dtypes.py +4 -2
- teradataml/utils/internal_buffer.py +22 -2
- teradataml/utils/utils.py +0 -1
- teradataml/utils/validators.py +318 -58
- {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/METADATA +188 -14
- {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/RECORD +131 -84
- {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/WHEEL +0 -0
- {teradataml-20.0.0.4.dist-info → teradataml-20.0.0.6.dist-info}/top_level.txt +0 -0
- {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
|