teradataml 20.0.0.5__py3-none-any.whl → 20.0.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of teradataml might be problematic. Click here for more details.

Files changed (119) hide show
  1. teradataml/LICENSE-3RD-PARTY.pdf +0 -0
  2. teradataml/README.md +306 -0
  3. teradataml/__init__.py +1 -1
  4. teradataml/_version.py +1 -1
  5. teradataml/analytics/analytic_function_executor.py +162 -76
  6. teradataml/analytics/byom/__init__.py +1 -1
  7. teradataml/analytics/json_parser/__init__.py +2 -0
  8. teradataml/analytics/json_parser/analytic_functions_argument.py +95 -2
  9. teradataml/analytics/json_parser/metadata.py +22 -4
  10. teradataml/analytics/sqle/DecisionTreePredict.py +3 -2
  11. teradataml/analytics/sqle/NaiveBayesPredict.py +3 -2
  12. teradataml/analytics/sqle/__init__.py +3 -0
  13. teradataml/analytics/utils.py +59 -11
  14. teradataml/automl/__init__.py +2369 -464
  15. teradataml/automl/autodataprep/__init__.py +15 -0
  16. teradataml/automl/custom_json_utils.py +184 -112
  17. teradataml/automl/data_preparation.py +113 -58
  18. teradataml/automl/data_transformation.py +154 -53
  19. teradataml/automl/feature_engineering.py +113 -53
  20. teradataml/automl/feature_exploration.py +548 -25
  21. teradataml/automl/model_evaluation.py +260 -32
  22. teradataml/automl/model_training.py +399 -206
  23. teradataml/clients/auth_client.py +10 -6
  24. teradataml/clients/keycloak_client.py +165 -0
  25. teradataml/common/aed_utils.py +11 -2
  26. teradataml/common/bulk_exposed_utils.py +4 -2
  27. teradataml/common/constants.py +72 -2
  28. teradataml/common/exceptions.py +32 -0
  29. teradataml/common/garbagecollector.py +50 -21
  30. teradataml/common/messagecodes.py +73 -1
  31. teradataml/common/messages.py +27 -1
  32. teradataml/common/sqlbundle.py +25 -7
  33. teradataml/common/utils.py +210 -22
  34. teradataml/context/aed_context.py +16 -10
  35. teradataml/context/context.py +37 -9
  36. teradataml/data/Employee.csv +5 -0
  37. teradataml/data/Employee_Address.csv +4 -0
  38. teradataml/data/Employee_roles.csv +5 -0
  39. teradataml/data/JulesBelvezeDummyData.csv +100 -0
  40. teradataml/data/byom_example.json +5 -0
  41. teradataml/data/creditcard_data.csv +284618 -0
  42. teradataml/data/docs/byom/docs/ONNXSeq2Seq.py +255 -0
  43. teradataml/data/docs/sqle/docs_17_10/NGramSplitter.py +1 -1
  44. teradataml/data/docs/sqle/docs_17_20/NGramSplitter.py +1 -1
  45. teradataml/data/docs/sqle/docs_17_20/TextParser.py +1 -1
  46. teradataml/data/jsons/byom/ONNXSeq2Seq.json +287 -0
  47. teradataml/data/jsons/byom/onnxembeddings.json +1 -0
  48. teradataml/data/jsons/sqle/20.00/AI_AnalyzeSentiment.json +3 -7
  49. teradataml/data/jsons/sqle/20.00/AI_AskLLM.json +3 -7
  50. teradataml/data/jsons/sqle/20.00/AI_DetectLanguage.json +3 -7
  51. teradataml/data/jsons/sqle/20.00/AI_ExtractKeyPhrases.json +3 -7
  52. teradataml/data/jsons/sqle/20.00/AI_MaskPII.json +3 -7
  53. teradataml/data/jsons/sqle/20.00/AI_RecognizeEntities.json +3 -7
  54. teradataml/data/jsons/sqle/20.00/AI_RecognizePIIEntities.json +3 -7
  55. teradataml/data/jsons/sqle/20.00/AI_TextClassifier.json +3 -7
  56. teradataml/data/jsons/sqle/20.00/AI_TextEmbeddings.json +3 -7
  57. teradataml/data/jsons/sqle/20.00/AI_TextSummarize.json +3 -7
  58. teradataml/data/jsons/sqle/20.00/AI_TextTranslate.json +3 -7
  59. teradataml/data/jsons/sqle/20.00/TD_API_AzureML.json +151 -0
  60. teradataml/data/jsons/sqle/20.00/TD_API_Sagemaker.json +182 -0
  61. teradataml/data/jsons/sqle/20.00/TD_API_VertexAI.json +183 -0
  62. teradataml/data/load_example_data.py +29 -11
  63. teradataml/data/pattern_matching_data.csv +11 -0
  64. teradataml/data/payment_fraud_dataset.csv +10001 -0
  65. teradataml/data/sdk/modelops/modelops_spec.json +101737 -0
  66. teradataml/data/teradataml_example.json +75 -1
  67. teradataml/data/url_data.csv +10 -9
  68. teradataml/dataframe/copy_to.py +715 -55
  69. teradataml/dataframe/dataframe.py +2115 -97
  70. teradataml/dataframe/dataframe_utils.py +66 -28
  71. teradataml/dataframe/functions.py +1130 -2
  72. teradataml/dataframe/setop.py +4 -1
  73. teradataml/dataframe/sql.py +710 -1039
  74. teradataml/dbutils/dbutils.py +470 -35
  75. teradataml/dbutils/filemgr.py +1 -1
  76. teradataml/hyperparameter_tuner/optimizer.py +456 -142
  77. teradataml/hyperparameter_tuner/utils.py +4 -2
  78. teradataml/lib/aed_0_1.dll +0 -0
  79. teradataml/lib/libaed_0_1.dylib +0 -0
  80. teradataml/lib/libaed_0_1.so +0 -0
  81. teradataml/lib/libaed_0_1_aarch64.so +0 -0
  82. teradataml/opensource/_base.py +7 -1
  83. teradataml/options/configure.py +20 -4
  84. teradataml/scriptmgmt/UserEnv.py +247 -36
  85. teradataml/scriptmgmt/lls_utils.py +140 -39
  86. teradataml/sdk/README.md +79 -0
  87. teradataml/sdk/__init__.py +4 -0
  88. teradataml/sdk/_auth_modes.py +422 -0
  89. teradataml/sdk/_func_params.py +487 -0
  90. teradataml/sdk/_json_parser.py +453 -0
  91. teradataml/sdk/_openapi_spec_constants.py +249 -0
  92. teradataml/sdk/_utils.py +236 -0
  93. teradataml/sdk/api_client.py +900 -0
  94. teradataml/sdk/constants.py +62 -0
  95. teradataml/sdk/modelops/__init__.py +98 -0
  96. teradataml/sdk/modelops/_client.py +409 -0
  97. teradataml/sdk/modelops/_constants.py +304 -0
  98. teradataml/sdk/modelops/models.py +2308 -0
  99. teradataml/sdk/spinner.py +107 -0
  100. teradataml/series/series.py +12 -7
  101. teradataml/store/feature_store/constants.py +601 -234
  102. teradataml/store/feature_store/feature_store.py +2886 -616
  103. teradataml/store/feature_store/mind_map.py +639 -0
  104. teradataml/store/feature_store/models.py +5831 -214
  105. teradataml/store/feature_store/utils.py +390 -0
  106. teradataml/table_operators/query_generator.py +4 -21
  107. teradataml/table_operators/table_operator_util.py +1 -1
  108. teradataml/table_operators/templates/dataframe_register.template +6 -2
  109. teradataml/table_operators/templates/dataframe_udf.template +6 -2
  110. teradataml/utils/docstring.py +527 -0
  111. teradataml/utils/dtypes.py +95 -1
  112. teradataml/utils/internal_buffer.py +2 -2
  113. teradataml/utils/utils.py +41 -3
  114. teradataml/utils/validators.py +699 -18
  115. {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/METADATA +312 -2
  116. {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/RECORD +119 -87
  117. {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/WHEEL +0 -0
  118. {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/top_level.txt +0 -0
  119. {teradataml-20.0.0.5.dist-info → teradataml-20.0.0.7.dist-info}/zip-safe +0 -0
@@ -24,27 +24,25 @@ from urllib.parse import urlparse
24
24
  import pandas as pd
25
25
 
26
26
  from teradataml import configure
27
- from teradataml.context.context import _get_user, get_connection
28
- from teradataml.common.constants import HTTPRequest, AsyncStatusColumns, AuthMechs
29
27
  from teradataml.clients.auth_client import _AuthWorkflow
28
+ from teradataml.clients.keycloak_client import _KeycloakManager
30
29
  from teradataml.clients.pkce_client import _DAWorkflow
31
30
  from teradataml.common.constants import (AsyncOpStatus, AsyncStatusColumns,
32
- HTTPRequest)
31
+ AuthMechs, HTTPRequest, TDServices)
33
32
  from teradataml.common.exceptions import TeradataMlException
34
33
  from teradataml.common.messagecodes import MessageCodes
35
34
  from teradataml.common.messages import Messages
36
35
  from teradataml.common.utils import UtilFuncs
37
36
  from teradataml.context.context import _get_user, get_connection
38
37
  from teradataml.scriptmgmt.UserEnv import (UserEnv, _AuthToken,
39
- _get_auth_token, _get_ues_url,
40
- _process_ues_response, _get_ccp_url)
38
+ _get_auth_token, _get_ccp_url,
39
+ _get_ues_url, _process_ues_response)
41
40
  from teradataml.telemetry_utils.queryband import collect_queryband
42
41
  from teradataml.utils.internal_buffer import _InternalBuffer
43
42
  from teradataml.utils.utils import _async_run_id_info
44
43
  from teradataml.utils.validators import _Validators
45
44
 
46
45
 
47
-
48
46
  @collect_queryband(queryband="LstBsEnv")
49
47
  def list_base_envs():
50
48
  """
@@ -269,7 +267,7 @@ def list_user_envs(env_name=None, **kwargs):
269
267
 
270
268
  # Example 8: List all user environments where python 3 environment release version has
271
269
  # odd number. For e.g. python_3.7.x.
272
- >>> list_user_envs(base_env="\.\d*[13579]\.")
270
+ >>> list_user_envs(base_env="\\.\\d*[13579]\\.")
273
271
  env_name env_description base_env_name language
274
272
  1 Customer_Trends Analyse customer trends r_4.1.3 R
275
273
  2 Fraud_Detection Fraud detection through time matching python_3.7.13 Python
@@ -476,29 +474,51 @@ def __create_envs(template):
476
474
  return last_successful_env
477
475
 
478
476
 
479
- def __get_default_base_env():
477
+ def __get_default_base_env(lang="python"):
480
478
  """
481
- Function returns the latest python environment available with
482
- Open Analytics Framework.
479
+ DESCRIPTION:
480
+ Function returns the name of latest environment available with
481
+ Open Analytics Framework for given programming language.
482
+
483
+ PARAMETERS:
484
+ lang:
485
+ Optional Argument.
486
+ Specifies the language for which latest base env is to be retrieved.
487
+ Default value: "python"
488
+ Permitted values: "python", "r", "PYTHON", "R"
489
+ Types: str
490
+
491
+ RETURNS:
492
+ Base environment name.
493
+
494
+ RAISES:
495
+ None.
496
+
497
+ EXAMPLES:
498
+ # Get default R base environment.
499
+ >>> __get_default_base_env(lang="R")
483
500
  """
501
+ lang = lang.lower()
502
+ default_env_key = "default_base_env_{}".format(lang)
484
503
  # Check if the default base environment is already available.
485
- if _InternalBuffer.get('default_base_env') is not None:
486
- return _InternalBuffer.get('default_base_env')
504
+ if _InternalBuffer.get(default_env_key) is not None:
505
+ return _InternalBuffer.get(default_env_key)
487
506
 
488
507
  try:
489
508
  base_envs = list_base_envs()
490
- python_versions = base_envs[base_envs.language == 'Python']['version']
509
+ versions = base_envs[base_envs.language.str.lower() == lang]['version']
491
510
  # Convert version strings to tuples of integers for comparison
492
- version_tuples = [tuple(map(int, version.split('.'))) for version in python_versions]
511
+ version_tuples = [tuple(map(int, version.split('.'))) for version in versions]
493
512
  # Find the latest version tuple using max() function
494
513
  latest_version_tuple = max(version_tuples)
495
514
  # Convert the latest version tuple back to a string
496
515
  latest_version = '.'.join(map(str, latest_version_tuple))
497
- # Get the base environment name for the latest version
498
- _InternalBuffer.add(default_base_env=base_envs[base_envs.version == latest_version]['base_name'].to_list()[0])
499
- return _InternalBuffer.get('default_base_env')
516
+ # Get the base environment name for the latest version and add in internal buffer.
517
+ _InternalBuffer.add(**{default_env_key:
518
+ base_envs[base_envs.version == latest_version]['base_name'].to_list()[0]})
519
+ return _InternalBuffer.get(default_env_key)
500
520
  except Exception as base_env_err:
501
- raise Exception("Failed to obtain default base environment.", str(base_env_err.exception))
521
+ raise Exception("Failed to obtain default base environment.", str(base_env_err))
502
522
 
503
523
 
504
524
  def __install_files(env, directory):
@@ -801,12 +821,14 @@ def create_env(env_name=None, base_env=None, desc=None, template=None, conda_env
801
821
  # the list of base envs. If not available, set base_env to the default python base env.
802
822
  if not base_env or \
803
823
  base_env.lower() not in list_base_envs()['base_name'].str.lower().to_list():
824
+ lang = "python"
804
825
  # Print warning message if base_env provided is not available.
805
826
  if base_env:
806
827
  print(f"Note: The specified base environment '{base_env}' is unavailable. " \
807
828
  "Using the default base environment as specified in the documentation.")
829
+ lang = base_env.split('_')[0].lower() # Extract language for given base_env.
808
830
  # Set base_env to the default
809
- base_env = __get_default_base_env()
831
+ base_env = __get_default_base_env(lang=lang)
810
832
  if not desc:
811
833
  desc = "This env '{}' is created with base env '{}'.".format(env_name, base_env)
812
834
  try:
@@ -1507,7 +1529,7 @@ def _remove_all_envs(env_type, **kwargs):
1507
1529
  claim_id_list.append(future_result)
1508
1530
 
1509
1531
  except (TeradataMlException, RuntimeError, Exception) as emsg:
1510
- # Catching exceptions by remove_env if occured in any thread.
1532
+ # Catching exceptions by remove_env if occurred in any thread.
1511
1533
  failed_envs[env] = emsg
1512
1534
 
1513
1535
  # Negative case - Failed to remove env.
@@ -1778,6 +1800,18 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1778
1800
  Specifies the password for database user to be used for Basic authentication.
1779
1801
  Types: str
1780
1802
 
1803
+ auth_url:
1804
+ Optional Argument.
1805
+ Specifies the endpoint URL for a keycloak server.
1806
+ Types: str
1807
+
1808
+ rest_client:
1809
+ Optional Argument.
1810
+ Specifies the service for which keycloak token is to be generated.
1811
+ Permitted values: "VECTORSTORE"
1812
+ Default value: "VECTORSTORE"
1813
+ Types: str
1814
+
1781
1815
  auth_mech:
1782
1816
  Optional Argument.
1783
1817
  Specifies the mechanism to be used for generating authentication token.
@@ -1787,14 +1821,31 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1787
1821
  * OAuth: Token generation is done through OAuth by using client id
1788
1822
  which can be sepcified by user in "client_id" argument or
1789
1823
  can be derived internally from "base_url".
1790
- * PAT : Token generation is done using "pat_token" and "pem_file".
1824
+ * PAT: Token generation is done using "pat_token" and "pem_file".
1791
1825
  * BASIC: Authentication is done via Basic authentication mechanism
1792
1826
  using user credentials passed in "username" and "password"
1793
1827
  arguments.
1794
- * JWT : Readily available token in "auth_token" argument is used.
1795
- Permitted Values: "OAuth", "PAT", "BASIC", "JWT".
1828
+ * JWT: Readily available token in "auth_token" argument is used.
1829
+ * KEYCLOAK: Token generation is done using keycloak.
1830
+ Permitted Values: "OAuth", "PAT", "BASIC", "JWT", "KEYCLOAK".
1796
1831
  Types: str
1797
1832
 
1833
+ validate_jwt:
1834
+ Optional Argument.
1835
+ Specifies whether to validate generated JWT token or not.
1836
+ Note:
1837
+ * Applicable only when "auth_mech" is "PAT".
1838
+ Default value: True
1839
+ Types: boolean
1840
+
1841
+ valid_from:
1842
+ Optional Argument.
1843
+ Specifies epoch seconds representing time from which JWT token will be valid.
1844
+ Note:
1845
+ * Applicable only when "auth_mech" is "PAT".
1846
+ Default value: 0
1847
+ Types: int
1848
+
1798
1849
  RETURNS:
1799
1850
  True, if the operation is successful.
1800
1851
 
@@ -1861,6 +1912,16 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1861
1912
  Authentication token is generated and set for the session.
1862
1913
  True
1863
1914
 
1915
+ # Example 8: Set the authentication token for by specifying "base_url", "auth_url"
1916
+ # "password" and "rest_client" and generating keycloak token internally.
1917
+ >>> import getpass
1918
+ >>> set_auth_token(base_url=getpass.getpass("base_url : "),
1919
+ ... auth_url=getpass.getpass("auth_url : "),
1920
+ ... password=getpass.getpass("password : "),
1921
+ ... rest_client=getpass.getpass("rest_client : "))
1922
+ Authentication token is generated and set for the session.
1923
+ True
1924
+
1864
1925
  """
1865
1926
 
1866
1927
  # Deriving global connection using get_connection().
@@ -1869,7 +1930,7 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1869
1930
  MessageCodes.INVALID_CONTEXT_CONNECTION)
1870
1931
 
1871
1932
  # Remove keys from _InternalBuffer which are interrelated to base_url and authentication token.
1872
- _InternalBuffer.remove_keys(['list_base_envs', 'default_base_env',
1933
+ _InternalBuffer.remove_keys(['list_base_envs', 'default_base_env_python', 'default_base_env_r',
1873
1934
  'vs_session_id', 'vs_header'])
1874
1935
 
1875
1936
  # ---------------------------------ARGUMENT VALIDATION------------------------------------------------------
@@ -1886,22 +1947,34 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1886
1947
  __arg_info_matrix.append(["ues_url", ues_url, True, (str), True])
1887
1948
 
1888
1949
  username = kwargs.get("username", _get_user())
1889
- __arg_info_matrix.append((["username", username, True, (str), True]))
1950
+ __arg_info_matrix.append(["username", username, True, (str), True])
1890
1951
 
1891
1952
  password = kwargs.get("password", None)
1892
1953
  __arg_info_matrix.append(["password", password, True, (str), True])
1893
1954
 
1894
1955
  auth_token = kwargs.get("auth_token")
1895
- __arg_info_matrix.append((["auth_token", auth_token, True, (str), True]))
1956
+ __arg_info_matrix.append(["auth_token", auth_token, True, (str), True])
1896
1957
 
1897
- expiration_time = kwargs.get("expiration_time", 31536000)
1898
- __arg_info_matrix.append((["expiration_time", expiration_time, True, (int), True]))
1958
+ expiration_time = kwargs.get("expiration_time", 31536000) # 31536000 seconds meaning 365 days.
1959
+ __arg_info_matrix.append(["expiration_time", expiration_time, True, (int), True])
1899
1960
 
1900
1961
  kid = kwargs.get("kid")
1901
- __arg_info_matrix.append((["kid", kid, True, (str), True]))
1962
+ __arg_info_matrix.append(["kid", kid, True, (str), True])
1963
+
1964
+ auth_url = kwargs.get("auth_url", None)
1965
+ __arg_info_matrix.append(["auth_url", auth_url, True, (str), True])
1966
+
1967
+ rest_client = kwargs.get("rest_client", "VECTORSTORE")
1968
+ __arg_info_matrix.append(["rest_client", rest_client, True, (str), True, [svc.name for svc in TDServices]])
1902
1969
 
1903
1970
  auth_mech = kwargs.get("auth_mech", None)
1904
- __arg_info_matrix.append((["auth_mech", auth_mech, True, (str), True, [mech.value for mech in AuthMechs]]))
1971
+ __arg_info_matrix.append(["auth_mech", auth_mech, True, (str), True, [mech.name for mech in AuthMechs]])
1972
+
1973
+ validate_jwt = kwargs.get("validate_jwt", True)
1974
+ __arg_info_matrix.append(["validate_jwt", validate_jwt, True, (bool)])
1975
+
1976
+ valid_from = kwargs.get("valid_from", 0) # This sets iat to UTC beginning.
1977
+ __arg_info_matrix.append(["valid_from", valid_from, True, int])
1905
1978
 
1906
1979
  # Validate arguments.
1907
1980
  _Validators._validate_function_arguments(__arg_info_matrix)
@@ -1919,6 +1992,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1919
1992
 
1920
1993
  # Set the vector_store_base_url. This should only be done if base_url is set.
1921
1994
  # In case ues_url is set, vector_store_base_url should not be set.
1995
+ # Remove trailing forward slash from base_url if present.
1996
+ base_url = base_url[: -1] if base_url.endswith("/") else base_url
1922
1997
  configure._vector_store_base_url = f'{base_url}/data-insights'
1923
1998
 
1924
1999
  if ues_url:
@@ -1950,13 +2025,15 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1950
2025
  if auth_mech:
1951
2026
  auth_mech = auth_mech.lower()
1952
2027
  if auth_mech == 'oauth':
1953
- pat_token = pem_file = password = auth_token = None
2028
+ pat_token = pem_file = password = auth_token = auth_url = None
1954
2029
  elif auth_mech == 'jwt':
1955
- pat_token = pem_file = password = client_id = None
2030
+ pat_token = pem_file = password = client_id = auth_url = None
1956
2031
  elif auth_mech == 'basic':
1957
- pat_token = pem_file = auth_token = client_id = None
2032
+ pat_token = pem_file = auth_token = client_id = auth_url = None
1958
2033
  elif auth_mech == 'pat':
1959
- password = client_id = auth_token = None
2034
+ password = client_id = auth_token = auth_url = None
2035
+ elif auth_mech == 'keycloak':
2036
+ pat_token = pem_file = auth_token = client_id = None
1960
2037
 
1961
2038
  # Validate arguments for mutual exclusiveness.
1962
2039
  all_groups_none = \
@@ -1964,7 +2041,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1964
2041
  {"auth_token": auth_token},
1965
2042
  {"pat_token": pat_token,
1966
2043
  "pem_file": pem_file},
1967
- {"password": password},
2044
+ {"password": password} if not auth_url else
2045
+ {"password": password, "auth_url": auth_url},
1968
2046
  return_all_falsy_status=True)
1969
2047
 
1970
2048
  # Determine authentication mechanism from availability of supportive arguments.
@@ -1973,6 +2051,8 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1973
2051
  auth_mech = 'jwt'
1974
2052
  elif any([pat_token, pem_file]):
1975
2053
  auth_mech = 'pat'
2054
+ elif auth_url:
2055
+ auth_mech = 'keycloak'
1976
2056
  elif password:
1977
2057
  # Authentication is done via Basic authentication mechanism
1978
2058
  # by passing 'basic' field in header.
@@ -1995,7 +2075,6 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
1995
2075
  _InternalBuffer.add(auth_token=_AuthToken(token=auth_token,
1996
2076
  auth_type='bearer'))
1997
2077
  elif auth_mech == 'oauth':
1998
- # TODO: Finalize need to set this flag to False in other scenarios.
1999
2078
  configure._oauth = True
2000
2079
  client_id = "{}-oaf-device".format(org_id) if client_id is None else client_id
2001
2080
  da_wf = _DAWorkflow(parsed_base_url, client_id)
@@ -2028,11 +2107,13 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
2028
2107
  "pem_file": pem_file,
2029
2108
  "username": username,
2030
2109
  "expiration_time": expiration_time,
2031
- "kid": kid})
2110
+ "kid": kid,
2111
+ "valid_from": valid_from})
2032
2112
  token_data = auth_wf._proxy_jwt()
2033
2113
 
2034
- # Validate generated JWT token.
2035
- token_validated = _validate_jwt_token(base_url, token_data)
2114
+ if validate_jwt:
2115
+ # Validate generated JWT token.
2116
+ token_validated = _validate_jwt_token(base_url, token_data)
2036
2117
 
2037
2118
  # Store the jwt token in internal class attribute.
2038
2119
  _InternalBuffer.add(auth_token=_AuthToken(token=token_data,
@@ -2047,6 +2128,26 @@ def set_auth_token(base_url=None, client_id=None, pat_token=None, pem_file=None,
2047
2128
  # Store the header data in internal class attribute.
2048
2129
  _InternalBuffer.add(auth_token=_AuthToken(token=encoded_credentials,
2049
2130
  auth_type='basic'))
2131
+ elif auth_mech == 'keycloak':
2132
+ _Validators._validate_missing_required_arguments([["password", password, False, (str), True],
2133
+ ["auth_url", auth_url, False, (str), True]
2134
+ ])
2135
+ token_generator = _KeycloakManager(auth_url=auth_url,
2136
+ client_id=TDServices[rest_client].value)
2137
+
2138
+ # Store manager object in _InternalBuffer in order to generate token after expiry time.
2139
+ _InternalBuffer.add(keycloak_manager=token_generator)
2140
+ try:
2141
+ token_data = token_generator.generate_token(username=username,
2142
+ password=password)
2143
+ except:
2144
+ raise TeradataMlException(Messages.get_message(MessageCodes.FUNC_EXECUTION_FAILED,
2145
+ "set_auth_token",
2146
+ "Failed to generate keycloak token."),
2147
+ MessageCodes.FUNC_EXECUTION_FAILED)
2148
+
2149
+ _InternalBuffer.add(auth_token=_AuthToken(token=token_data,
2150
+ auth_type='keycloak'))
2050
2151
 
2051
2152
  if token_validated:
2052
2153
  print("Authentication token is generated, authenticated and set for the session.")
@@ -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.
@@ -0,0 +1,4 @@
1
+ from teradataml.sdk._auth_modes import (BearerAuth, ClientCredentialsAuth,
2
+ DeviceCodeAuth)
3
+ from teradataml.sdk.api_client import Client
4
+ from teradataml.sdk.constants import SdkPackagePaths