teradataml 20.0.0.6__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 (96) hide show
  1. teradataml/README.md +210 -0
  2. teradataml/__init__.py +1 -1
  3. teradataml/_version.py +1 -1
  4. teradataml/analytics/analytic_function_executor.py +162 -76
  5. teradataml/analytics/byom/__init__.py +1 -1
  6. teradataml/analytics/json_parser/__init__.py +2 -0
  7. teradataml/analytics/json_parser/analytic_functions_argument.py +95 -2
  8. teradataml/analytics/json_parser/metadata.py +22 -4
  9. teradataml/analytics/sqle/DecisionTreePredict.py +3 -2
  10. teradataml/analytics/sqle/NaiveBayesPredict.py +3 -2
  11. teradataml/analytics/sqle/__init__.py +3 -0
  12. teradataml/analytics/utils.py +4 -1
  13. teradataml/automl/__init__.py +2369 -464
  14. teradataml/automl/autodataprep/__init__.py +15 -0
  15. teradataml/automl/custom_json_utils.py +184 -112
  16. teradataml/automl/data_preparation.py +113 -58
  17. teradataml/automl/data_transformation.py +154 -53
  18. teradataml/automl/feature_engineering.py +113 -53
  19. teradataml/automl/feature_exploration.py +548 -25
  20. teradataml/automl/model_evaluation.py +260 -32
  21. teradataml/automl/model_training.py +399 -206
  22. teradataml/clients/auth_client.py +2 -2
  23. teradataml/common/aed_utils.py +11 -2
  24. teradataml/common/bulk_exposed_utils.py +4 -2
  25. teradataml/common/constants.py +62 -2
  26. teradataml/common/garbagecollector.py +50 -21
  27. teradataml/common/messagecodes.py +47 -2
  28. teradataml/common/messages.py +19 -1
  29. teradataml/common/sqlbundle.py +23 -6
  30. teradataml/common/utils.py +116 -10
  31. teradataml/context/aed_context.py +16 -10
  32. teradataml/data/Employee.csv +5 -0
  33. teradataml/data/Employee_Address.csv +4 -0
  34. teradataml/data/Employee_roles.csv +5 -0
  35. teradataml/data/JulesBelvezeDummyData.csv +100 -0
  36. teradataml/data/byom_example.json +5 -0
  37. teradataml/data/creditcard_data.csv +284618 -0
  38. teradataml/data/docs/byom/docs/ONNXSeq2Seq.py +255 -0
  39. teradataml/data/docs/sqle/docs_17_10/NGramSplitter.py +1 -1
  40. teradataml/data/docs/sqle/docs_17_20/NGramSplitter.py +1 -1
  41. teradataml/data/docs/sqle/docs_17_20/TextParser.py +1 -1
  42. teradataml/data/jsons/byom/ONNXSeq2Seq.json +287 -0
  43. teradataml/data/jsons/sqle/20.00/AI_AnalyzeSentiment.json +3 -7
  44. teradataml/data/jsons/sqle/20.00/AI_AskLLM.json +3 -7
  45. teradataml/data/jsons/sqle/20.00/AI_DetectLanguage.json +3 -7
  46. teradataml/data/jsons/sqle/20.00/AI_ExtractKeyPhrases.json +3 -7
  47. teradataml/data/jsons/sqle/20.00/AI_MaskPII.json +3 -7
  48. teradataml/data/jsons/sqle/20.00/AI_RecognizeEntities.json +3 -7
  49. teradataml/data/jsons/sqle/20.00/AI_RecognizePIIEntities.json +3 -7
  50. teradataml/data/jsons/sqle/20.00/AI_TextClassifier.json +3 -7
  51. teradataml/data/jsons/sqle/20.00/AI_TextEmbeddings.json +3 -7
  52. teradataml/data/jsons/sqle/20.00/AI_TextSummarize.json +3 -7
  53. teradataml/data/jsons/sqle/20.00/AI_TextTranslate.json +3 -7
  54. teradataml/data/jsons/sqle/20.00/TD_API_AzureML.json +151 -0
  55. teradataml/data/jsons/sqle/20.00/TD_API_Sagemaker.json +182 -0
  56. teradataml/data/jsons/sqle/20.00/TD_API_VertexAI.json +183 -0
  57. teradataml/data/load_example_data.py +29 -11
  58. teradataml/data/payment_fraud_dataset.csv +10001 -0
  59. teradataml/data/teradataml_example.json +67 -0
  60. teradataml/dataframe/copy_to.py +714 -54
  61. teradataml/dataframe/dataframe.py +1153 -33
  62. teradataml/dataframe/dataframe_utils.py +8 -3
  63. teradataml/dataframe/functions.py +168 -1
  64. teradataml/dataframe/setop.py +4 -1
  65. teradataml/dataframe/sql.py +141 -9
  66. teradataml/dbutils/dbutils.py +470 -35
  67. teradataml/dbutils/filemgr.py +1 -1
  68. teradataml/hyperparameter_tuner/optimizer.py +456 -142
  69. teradataml/lib/aed_0_1.dll +0 -0
  70. teradataml/lib/libaed_0_1.dylib +0 -0
  71. teradataml/lib/libaed_0_1.so +0 -0
  72. teradataml/lib/libaed_0_1_aarch64.so +0 -0
  73. teradataml/scriptmgmt/UserEnv.py +234 -34
  74. teradataml/scriptmgmt/lls_utils.py +43 -17
  75. teradataml/sdk/_json_parser.py +1 -1
  76. teradataml/sdk/api_client.py +9 -6
  77. teradataml/sdk/modelops/_client.py +3 -0
  78. teradataml/series/series.py +12 -7
  79. teradataml/store/feature_store/constants.py +601 -234
  80. teradataml/store/feature_store/feature_store.py +2886 -616
  81. teradataml/store/feature_store/mind_map.py +639 -0
  82. teradataml/store/feature_store/models.py +5831 -214
  83. teradataml/store/feature_store/utils.py +390 -0
  84. teradataml/table_operators/table_operator_util.py +1 -1
  85. teradataml/table_operators/templates/dataframe_register.template +6 -2
  86. teradataml/table_operators/templates/dataframe_udf.template +6 -2
  87. teradataml/utils/docstring.py +527 -0
  88. teradataml/utils/dtypes.py +93 -0
  89. teradataml/utils/internal_buffer.py +2 -2
  90. teradataml/utils/utils.py +41 -2
  91. teradataml/utils/validators.py +694 -17
  92. {teradataml-20.0.0.6.dist-info → teradataml-20.0.0.7.dist-info}/METADATA +213 -2
  93. {teradataml-20.0.0.6.dist-info → teradataml-20.0.0.7.dist-info}/RECORD +96 -81
  94. {teradataml-20.0.0.6.dist-info → teradataml-20.0.0.7.dist-info}/WHEEL +0 -0
  95. {teradataml-20.0.0.6.dist-info → teradataml-20.0.0.7.dist-info}/top_level.txt +0 -0
  96. {teradataml-20.0.0.6.dist-info → teradataml-20.0.0.7.dist-info}/zip-safe +0 -0
@@ -0,0 +1,527 @@
1
+ """
2
+ Unpublished work.
3
+ Copyright (c) 2025 by Teradata Corporation. All rights reserved.
4
+ TERADATA CORPORATION CONFIDENTIAL AND TRADE SECRET
5
+
6
+ Primary Owner: Sushant.Mhambrey@Teradata.com
7
+ PankajVinod.Purandare@Teradata.com
8
+
9
+ This file implements the decorator to inherit docstring from parent method,
10
+ override specified sections, append shared parameters, and remove excluded parameters.
11
+ """
12
+
13
+ import inspect
14
+ import re
15
+ import textwrap
16
+ from functools import wraps
17
+ from typing import (
18
+ Any,
19
+ Callable,
20
+ Dict,
21
+ List,
22
+ Optional,
23
+ Sequence,
24
+ Tuple,
25
+ Type,
26
+ Union,
27
+ )
28
+
29
+ # -------------------------------------------------------------------
30
+ # Helpers for emitting structured parameter blocks & notes
31
+ # -------------------------------------------------------------------
32
+
33
+ _LIST_MARKER_RE = re.compile(r"^(\*|\+|\-|\d+\.|[a-zA-Z]\.)\s")
34
+ _SECTION_HEADER_RE = re.compile(r"^\s*([A-Z][A-Z _]+?)\s*:?\s*$", re.MULTILINE)
35
+
36
+
37
+ def _emit_structured_block(
38
+ label: str,
39
+ content: Any,
40
+ description_indent: str,
41
+ ) -> List[str]:
42
+ """
43
+ DESCRIPTION:
44
+ Internal function to build a properly indented block in the docstring
45
+ for any "Label:" section where the content maybe a single value,
46
+ multiline string, or a list of items.
47
+
48
+ PARAMETERS:
49
+ label:
50
+ Required Argument.
51
+ The label for the block (e.g., 'Default Value').
52
+ Types: str
53
+
54
+ content:
55
+ Required Argument.
56
+ The value or list to be formatted as a block.
57
+ Types: Any
58
+
59
+ description_indent:
60
+ Required Argument.
61
+ The indentation to use for the block's description lines.
62
+ Types: str
63
+
64
+ RETURNS:
65
+ List of formatted lines for the docstring block.
66
+ Types: List[str]
67
+
68
+ RAISES:
69
+ None.
70
+
71
+ EXAMPLES:
72
+ lines = _emit_structured_block('Default Value', '512', ' ')
73
+ """
74
+ lines: List[str] = []
75
+ if not content:
76
+ return lines
77
+
78
+ # Normalize into list of lines
79
+ if isinstance(content, (list, tuple, set)):
80
+ raw_lines = [f"* {item}" for item in content]
81
+ else:
82
+ raw_lines = [ln for ln in str(content).splitlines() if ln.strip()]
83
+
84
+ # Single-line simple content
85
+ if len(raw_lines) == 1 and not _LIST_MARKER_RE.match(raw_lines[0]):
86
+ lines.append(f"{description_indent}{label}: {raw_lines[0]}")
87
+ return lines
88
+
89
+ # Multi-line block
90
+ lines.append(f"{description_indent}{label}:")
91
+ block_indent = description_indent + " " * 4
92
+ sub_indent = description_indent + " " * 8
93
+
94
+ # Process each line, indenting bullets and preserving structure
95
+ # for multiline content
96
+ i = 0
97
+ while i < len(raw_lines):
98
+ raw = raw_lines[i].strip()
99
+ is_bullet = bool(_LIST_MARKER_RE.match(raw))
100
+ content = raw[2:].strip() if is_bullet else raw
101
+ if ( not is_bullet and ":" in raw) or content.endswith(":"):
102
+ lines.append(f"{block_indent}{content}") # Group headers at 4 spaces
103
+ i += 1
104
+ elif is_bullet:
105
+ bullet_indent = description_indent + " " * 8 # Keep bullets at 8 spaces
106
+ lines.append(f"{bullet_indent}* {content}")
107
+ i += 1
108
+ else:
109
+ # Not a bullet, just a regular line
110
+ lines.append(f"{sub_indent}{content}")
111
+ i += 1
112
+
113
+ return lines
114
+
115
+ def _emit_notes_block(notes: str, description_indent: str) -> List[str]:
116
+ """
117
+ DESCRIPTION:
118
+ Internal function that emits a free-form notes string into a
119
+ 'Note:' or 'Notes:' section with proper indentation and bullet
120
+ formatting for docstrings.
121
+ Detects whether to use singular or plural header and preserves
122
+ nested paragraphs.
123
+
124
+ PARAMETERS:
125
+ notes:
126
+ Required Argument.
127
+ The notes string to be formatted.
128
+ Types: str
129
+
130
+ description_indent:
131
+ Required Argument.
132
+ The indentation to use for the block's description lines.
133
+ Types: str
134
+
135
+ RETURNS:
136
+ List of formatted lines for the notes block.
137
+ Types: List[str]
138
+
139
+ RAISES:
140
+ None.
141
+
142
+ EXAMPLES:
143
+ lines = _emit_notes_block('Applicable only for file-based stores.', ' ')
144
+ """
145
+ lines: List[str] = []
146
+ in_bullet_section = False
147
+
148
+ # Split and filter out blank lines
149
+ raw = [ln.rstrip() for ln in notes.splitlines() if ln.strip()]
150
+ if not raw:
151
+ return lines
152
+
153
+ # Determine if we need singular or plural header
154
+ bullet_lines = [ln for ln in raw if _LIST_MARKER_RE.match(ln.lstrip())]
155
+ header = "Notes:" if len(bullet_lines) > 1 else "Note:"
156
+
157
+ # Build lines with header
158
+ lines.append(f"{description_indent}{header}")
159
+
160
+ # For each line in raw, indent as bullet
161
+ # or paragraph line under last bullet
162
+ # depending on whether it starts with a bullet marker
163
+ for ln in raw:
164
+ stripped = ln.lstrip()
165
+ if _LIST_MARKER_RE.match(stripped):
166
+ # This is a bullet point or numbered item
167
+ lines.append(f"{description_indent} {stripped}")
168
+ in_bullet_section = True
169
+ else:
170
+ # This is a continuation line or regular text
171
+ # Give extra indent if we're in a bullet section (for continuation)
172
+ extra = " " if in_bullet_section else " "
173
+ lines.append(f"{description_indent}{extra}{stripped}")
174
+
175
+ return lines
176
+ #-------------------------------------------------------------------
177
+ # Section parsing & parameter-removal helpers
178
+ # -------------------------------------------------------------------
179
+
180
+ def _split_sections(docstring: str) -> List[Tuple[str, List[str]]]:
181
+ """
182
+ DESCRIPTION:
183
+ Internal function to split a docstring into named sections based
184
+ on headers like 'DESCRIPTION:', 'PARAMETERS:', etc.
185
+ Leading text before the first recognized header is considered 'BODY'.
186
+
187
+ PARAMETERS:
188
+ docstring:
189
+ Required Argument.
190
+ The docstring to split into sections.
191
+ Types: str
192
+
193
+ RETURNS:
194
+ List of (header, lines) tuples representing docstring sections.
195
+ Types: List[Tuple[str, List[str]]]
196
+
197
+ RAISES:
198
+ None.
199
+
200
+ EXAMPLES:
201
+ sections = _split_sections('''DESCRIPTION:...PARAMETERS:...''')
202
+ """
203
+ if not docstring:
204
+ return []
205
+
206
+ sections: List[Tuple[str, List[str]]] = []
207
+ last_header = "BODY"
208
+ last_index = 0
209
+
210
+ # Find all section headers
211
+ # and split the docstring into blocks
212
+ for match in _SECTION_HEADER_RE.finditer(docstring):
213
+ header = match.group(1).strip().upper()
214
+ block_text = docstring[last_index : match.start()].rstrip("\n")
215
+
216
+ # split into lines and strip out any leading/trailing blank lines
217
+ lines = block_text.splitlines()
218
+ while lines and not lines[0].strip():
219
+ lines.pop(0)
220
+ while lines and not lines[-1].strip():
221
+ lines.pop()
222
+ sections.append((last_header, lines))
223
+
224
+ #sections.append((last_header, block_text.splitlines()))
225
+ # update for next section with last header and last index
226
+ last_header = header
227
+ last_index = match.end()
228
+
229
+ # final block
230
+ final_block = docstring[last_index:].rstrip("\n")
231
+
232
+ lines = final_block.splitlines()
233
+ while lines and not lines[0].strip():
234
+ lines.pop(0)
235
+ while lines and not lines[-1].strip():
236
+ lines.pop()
237
+ sections.append((last_header, lines))
238
+
239
+ # drop the very first BODY if empty
240
+ if sections and not any(line.strip() for line in sections[0][1]):
241
+ sections.pop(0)
242
+
243
+ return sections
244
+
245
+ def _remove_excluded_parameters(
246
+ parameter_lines: List[str],
247
+ excluded_argument_names: set[str],
248
+ ) -> List[str]:
249
+ """
250
+ DESCRIPTION:
251
+ Removes parameter entry blocks from a PARAMETERS section whose name is
252
+ in excluded_argument_names.
253
+
254
+ PARAMETERS:
255
+ parameter_lines:
256
+ Required Argument.
257
+ The lines of the PARAMETERS section to filter.
258
+ Types: List[str]
259
+
260
+ excluded_argument_names:
261
+ Required Argument.
262
+ Set of parameter names to exclude from the PARAMETERS section.
263
+ Types: set[str]
264
+
265
+ RETURNS:
266
+ Filtered list of parameter lines.
267
+ Types: List[str]
268
+
269
+ RAISES:
270
+ None.
271
+
272
+ EXAMPLES:
273
+ param_lines = [
274
+ " chunk_size:",
275
+ " Optional Argument.",
276
+ " nv_ingestor:",
277
+ " Optional Argument."
278
+ ]
279
+ filtered = _remove_excluded_parameters(param_lines , {"nv_ingestor"})
280
+ """
281
+ cleaned_lines: List[str] = []
282
+ skipping = False
283
+ param_indent_level = None
284
+
285
+ # Iterate through all lines under PARAMETERS
286
+ # and remove blocks for excluded parameters
287
+ for line in parameter_lines:
288
+ # Detect start of each param block
289
+ name_match = re.match(r"^(\s*)(\w+):\s*$", line)
290
+ if name_match:
291
+ indent, param_name = name_match.groups()
292
+ if param_name in excluded_argument_names:
293
+ skipping = True
294
+ param_indent_level = len(indent)
295
+ continue
296
+ else:
297
+ skipping = False
298
+
299
+ if skipping:
300
+ # if we encounter a line that's at or above the original param indent,
301
+ # it means the block ended
302
+ current_indent = len(line) - len(line.lstrip())
303
+ if current_indent <= (param_indent_level or 0):
304
+ skipping = False
305
+ else:
306
+ continue
307
+
308
+ else:
309
+ cleaned_lines.append(line)
310
+
311
+ return cleaned_lines
312
+
313
+ # -------------------------------------------------------------------
314
+ # The unified decorator
315
+ # -------------------------------------------------------------------
316
+
317
+ def docstring_handler(
318
+ inherit_from: Optional[Union[Type, Callable]] = None,
319
+ replace_sections: Sequence[str] = ("EXAMPLES",),
320
+ common_params: Optional[Dict[str, Dict[str, Any]]] = None,
321
+ exclude_params: Optional[List[str]] = None,
322
+ ) -> Callable[[Callable], Callable]:
323
+ """
324
+ DESCRIPTION:
325
+ Decorator to inherit parent method's docstring, override specified sections,
326
+ append shared parameters, and remove excluded parameters.
327
+
328
+ PARAMETERS:
329
+ inherit_from:
330
+ Optional Argument.
331
+ Class or function to inherit the parent method's docstring from.
332
+ Types: class or function
333
+
334
+ replace_sections:
335
+ Optional Argument.
336
+ Sequence of section headers the child should override in the docstring.
337
+ Types: sequence of str
338
+
339
+ common_params:
340
+ Optional Argument.
341
+ Mapping of parameter-key to spec-dict to append into PARAMETERS.
342
+ Types: dict
343
+
344
+ exclude_params:
345
+ Optional Argument.
346
+ List of parameter keys (or argument_names) to remove from both inherited PARAMETERS and injected common_params.
347
+ Types: list of str
348
+
349
+ RETURNS:
350
+ Decorated function with updated docstring.
351
+ Types: Callable[[Callable], Callable]
352
+
353
+ RAISES:
354
+ None.
355
+
356
+ EXAMPLES:
357
+ @docstring_handler(inherit_from=BaseClass, common_params=PARAMS)
358
+ def my_func(...):
359
+ ...
360
+ """
361
+ excluded_keys = set(exclude_params or [])
362
+
363
+ if isinstance(replace_sections, str):
364
+ headers_to_replace = {replace_sections.upper()}
365
+ else:
366
+ headers_to_replace = {h.upper() for h in replace_sections}
367
+
368
+ def decorator(method: Callable) -> Callable:
369
+ # 1) Fetch and split parent doc if requested
370
+ parent_sections: List[Tuple[str, List[str]]] = []
371
+ if inherit_from:
372
+ parent_method = getattr(inherit_from, method.__name__)
373
+ raw_parent_doc = inspect.getdoc(parent_method) or ""
374
+ parent_sections = _split_sections(raw_parent_doc)
375
+
376
+ # 2) Split the child’s own doc
377
+ raw_child_doc = inspect.getdoc(method) or ""
378
+ child_sections = dict(_split_sections(raw_child_doc))
379
+
380
+ # 3) Merge sections
381
+ if inherit_from:
382
+ merged_sections: List[Tuple[str, List[str]]] = []
383
+ parent_headers = [hdr for hdr, _ in parent_sections]
384
+
385
+ for header, block_lines in parent_sections:
386
+ if header in headers_to_replace and header in child_sections:
387
+ merged_sections.append((header, child_sections[header]))
388
+ else:
389
+ merged_sections.append((header, block_lines))
390
+
391
+ # Append any child-only sections
392
+ for header, block_lines in _split_sections(raw_child_doc):
393
+ if header not in parent_headers and header != "BODY":
394
+ merged_sections.append((header, block_lines))
395
+
396
+ else:
397
+ # No inheritance: start with child's sections only
398
+ merged_sections = _split_sections(raw_child_doc)
399
+
400
+ # Ensure each section exists
401
+ section_canonical_names = ["DESCRIPTION", "PARAMETERS", "RETURNS", "RAISES", "EXAMPLES"]
402
+ existing = [hdr for hdr, _ in merged_sections ]
403
+ block_indent_auto = " " * 4
404
+
405
+ for section in section_canonical_names:
406
+ if section not in existing:
407
+ # DESCRIPTION gets a default line, others can just say "None"
408
+
409
+ if section == "DESCRIPTION":
410
+ default_block = [f"{block_indent_auto}Auto generated description."]
411
+
412
+ elif section == "PARAMETERS" and common_params:
413
+ default_block = []
414
+ else:
415
+ default_block = [f"{block_indent_auto}None"]
416
+
417
+ # Figure out what to insert next so order stays as section_canonical_names
418
+ insert_at = next(
419
+ (i for i, (hdr, _) in enumerate(merged_sections)
420
+ if hdr in section_canonical_names
421
+ and section_canonical_names.index(hdr) > section_canonical_names.index(section)),
422
+ len(merged_sections),
423
+ )
424
+ merged_sections.insert(insert_at, (section, default_block))
425
+
426
+ # 4) Inject or update PARAMETERS block
427
+ if common_params:
428
+ # find or create PARAMETERS section
429
+ param_index = next(
430
+ (i for i, (hdr, _) in enumerate(merged_sections) if hdr == "PARAMETERS"),
431
+ None,
432
+ )
433
+ header, existing_param_lines = merged_sections[param_index]
434
+
435
+ # remove excluded params
436
+ # also map keys → argument_name for exclusion
437
+ excluded_argument_names = {
438
+ common_params[key].get("argument_name", key)
439
+ for key in excluded_keys
440
+ if key in common_params
441
+ }
442
+ excluded_argument_names |= excluded_keys
443
+
444
+ cleaned_param_lines = _remove_excluded_parameters(
445
+ existing_param_lines,
446
+ excluded_argument_names,
447
+ )
448
+
449
+ # Which args are already present
450
+ existing_param_names = {
451
+ m.group(1)
452
+ for line in cleaned_param_lines
453
+ if (m := re.match(r"^\s*(\w+):\s*$", line))
454
+ }
455
+
456
+ # build new param lines
457
+ base_indent = " " * 4
458
+ description_indent = base_indent + " " * 4
459
+ injected_lines: List[str] = []
460
+ for param_key, spec in common_params.items():
461
+ # Only exclude by excluded keys in the injection loop, not by argument_name.
462
+ if param_key in excluded_keys:
463
+ continue
464
+
465
+ argument_name = spec.get("argument_name", param_key)
466
+
467
+ if argument_name in existing_param_names:
468
+ # If already exists, skip adding it again
469
+ continue
470
+
471
+ # name:
472
+ injected_lines.append(f"{base_indent}{argument_name}:")
473
+ # required
474
+ if spec.get("required"):
475
+ injected_lines.append(f"{description_indent}{spec['required']}")
476
+ # description
477
+ if spec.get("description"):
478
+ for i, desc_line in enumerate(spec["description"].splitlines()):
479
+ indent = description_indent if i else description_indent
480
+ injected_lines.append(f"{indent}{desc_line.strip()}")
481
+ # notes, default, permitted, types
482
+ injected_lines += _emit_notes_block(
483
+ spec.get("notes", ""), description_indent
484
+ )
485
+ injected_lines += _emit_structured_block(
486
+ "Default Value", spec.get("default_values"), description_indent
487
+ )
488
+ injected_lines += _emit_structured_block(
489
+ "Permitted Values", spec.get("permitted_values"), description_indent
490
+ )
491
+ if spec.get("types"):
492
+ injected_lines.append(
493
+ f"{description_indent}Types: {spec['types']}"
494
+ )
495
+ injected_lines.append("") # blank line
496
+
497
+ # merge old + blank separator + new
498
+ if cleaned_param_lines and injected_lines:
499
+ if cleaned_param_lines[-1].strip():
500
+ cleaned_param_lines.append("")
501
+ merged_param_block = cleaned_param_lines + injected_lines
502
+
503
+ # replace in merged_sections
504
+ merged_sections[param_index] = (header, merged_param_block)
505
+
506
+ # 5) Reconstruct final docstring
507
+ final_blocks: List[str] = []
508
+ for header, block_lines in merged_sections:
509
+ if header == "BODY":
510
+ if block_lines:
511
+ final_blocks.append("\n".join(block_lines).rstrip())
512
+ else:
513
+ # final_blocks.append(f"{header}:")
514
+ # if block_lines:
515
+ # final_blocks.append("\n".join(block_lines).rstrip())
516
+ if block_lines:
517
+ block = f"{header}:\n" + "\n".join(block_lines).rstrip()
518
+ else:
519
+ block = f"{header}:"
520
+ final_blocks.append(block)
521
+
522
+ final_doc = "\n\n".join(final_blocks).rstrip() + "\n"
523
+ method.__doc__ = textwrap.dedent(final_doc)
524
+
525
+ return method
526
+
527
+ return decorator
@@ -733,3 +733,96 @@ class _Dtypes:
733
733
  """
734
734
  return _DtypesMappers.DATETIME_PERIOD_TYPES
735
735
 
736
+ @staticmethod
737
+ def _get_normalized_type(td_type):
738
+ """
739
+ DESCRIPTION:
740
+ Get the normalized types for DataFrame Types.
741
+
742
+ PARAMETERS:
743
+ None
744
+
745
+ RETURNS:
746
+ tuple
747
+
748
+ RAISES:
749
+ None
750
+
751
+ EXAMPLES:
752
+ >>> _Dtypes._get_normalized_types()
753
+ """
754
+ # Storing the details of the normalized types.
755
+
756
+ # Decimal type with any precision and scale, normalie it to DECIMAL(38, 19).
757
+ decimal_precision = 38
758
+ decimal_scale = 19
759
+
760
+ # Byte type with any length, normalize it to BYTE(64000).
761
+ byte_length = 64000
762
+
763
+ # Number type with any precision and scale, normalize it to NUMBER(38, 10).
764
+ number_precision = 38
765
+ number_scale = 10
766
+
767
+ # Time and Timestamp with any precision, normalize it to TIME(6) and TIMESTAMP(6).
768
+ time_precision = 6
769
+
770
+ # Interval types with any precision and fractional precision, normalize it
771
+ # to store maximum precision and fractional precision.
772
+ interval_precision = 4
773
+ frac_precision = 6
774
+
775
+ # Character types with any length, normalize it to CHAR(2000) and VARCHAR(2000).
776
+ char_length = 2000
777
+
778
+ type_ = td_type.__class__
779
+
780
+ types_ = {
781
+ INTEGER: BIGINT(),
782
+ SMALLINT: BIGINT(),
783
+ BIGINT: BIGINT(),
784
+ DECIMAL: DECIMAL(precision=decimal_precision, scale=decimal_scale),
785
+ BYTEINT: BYTEINT(),
786
+ BYTE: BYTE(length=byte_length),
787
+ VARBYTE: VARBYTE(length=byte_length),
788
+ FLOAT: FLOAT(),
789
+ NUMBER: NUMBER(precision=number_precision, scale=number_scale),
790
+ DATE: DATE(),
791
+ INTERVAL_YEAR: INTERVAL_YEAR(precision=interval_precision),
792
+ INTERVAL_YEAR_TO_MONTH: INTERVAL_YEAR_TO_MONTH(precision=interval_precision),
793
+ INTERVAL_MONTH: INTERVAL_MONTH(precision=interval_precision),
794
+ INTERVAL_DAY: INTERVAL_DAY(precision=interval_precision),
795
+ INTERVAL_DAY_TO_HOUR: INTERVAL_DAY_TO_HOUR(precision=interval_precision),
796
+ INTERVAL_DAY_TO_MINUTE: INTERVAL_DAY_TO_MINUTE(precision=interval_precision),
797
+ INTERVAL_DAY_TO_SECOND: INTERVAL_DAY_TO_SECOND(
798
+ precision=interval_precision, frac_precision=frac_precision),
799
+ INTERVAL_HOUR: INTERVAL_HOUR(precision=interval_precision),
800
+ INTERVAL_HOUR_TO_MINUTE: INTERVAL_HOUR_TO_MINUTE(precision=interval_precision),
801
+ INTERVAL_HOUR_TO_SECOND: INTERVAL_HOUR_TO_SECOND(
802
+ precision=interval_precision, frac_precision=frac_precision),
803
+ INTERVAL_MINUTE: INTERVAL_MINUTE(precision=interval_precision),
804
+ INTERVAL_MINUTE_TO_SECOND: INTERVAL_MINUTE_TO_SECOND(
805
+ precision=interval_precision, frac_precision=frac_precision),
806
+ INTERVAL_SECOND: INTERVAL_SECOND(
807
+ precision=interval_precision, frac_precision=frac_precision),
808
+ PERIOD_DATE: PERIOD_DATE(),
809
+ DATE: DATE()
810
+ }
811
+
812
+ type_ = types_.get(type_)
813
+ if type_:
814
+ return type_, type_.__class__.__name__
815
+ elif isinstance(td_type, TIME):
816
+ type_ = TIME(precision=time_precision, timezone=td_type.timezone)
817
+ return type_, "TIME_{}".format(type_.timezone)
818
+ elif isinstance(td_type, TIMESTAMP):
819
+ type_ = TIMESTAMP(precision=time_precision, timezone=td_type.timezone)
820
+ return type_, "TIMESTAMP_{}".format(type_.timezone)
821
+ elif isinstance(td_type, (PERIOD_TIME, PERIOD_TIMESTAMP)):
822
+ type_ = td_type.__class__(frac_precision=frac_precision, timezone=td_type.timezone)
823
+ return type_, "{}_{}".format(type_.__class__.__name__, type_.timezone)
824
+ elif isinstance(td_type, (CHAR, VARCHAR)):
825
+ type_ = td_type.__class__(length=char_length, charset=td_type.charset)
826
+ return type_, "{}_{}".format(type_.__class__.__name__, type_.charset)
827
+ else:
828
+ return None, repr(None)
@@ -114,8 +114,8 @@ class _InternalBuffer:
114
114
  None
115
115
 
116
116
  EXAMPLES:
117
- # Remove keys "list_base_envs" and "default_base_env" from _InternalBuffer.
118
- >>> _InternalBuffer.remove_keys(['list_base_envs', 'default_base_env'])
117
+ # Remove keys "list_base_envs" and "default_base_env_python" from _InternalBuffer.
118
+ >>> _InternalBuffer.remove_keys(['list_base_envs', 'default_base_env_python'])
119
119
  """
120
120
  for key in keys:
121
121
  if cls.__data.get(key) is not None: