pyxecm 3.0.1__py3-none-any.whl → 3.1.1__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 pyxecm might be problematic. Click here for more details.

Files changed (52) hide show
  1. pyxecm/avts.py +4 -4
  2. pyxecm/coreshare.py +14 -15
  3. pyxecm/helper/data.py +2 -1
  4. pyxecm/helper/web.py +11 -11
  5. pyxecm/helper/xml.py +41 -10
  6. pyxecm/otac.py +1 -1
  7. pyxecm/otawp.py +19 -19
  8. pyxecm/otca.py +878 -70
  9. pyxecm/otcs.py +1716 -349
  10. pyxecm/otds.py +332 -153
  11. pyxecm/otkd.py +4 -4
  12. pyxecm/otmm.py +1 -1
  13. pyxecm/otpd.py +246 -30
  14. {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/METADATA +2 -1
  15. pyxecm-3.1.1.dist-info/RECORD +82 -0
  16. pyxecm_api/app.py +45 -35
  17. pyxecm_api/auth/functions.py +2 -2
  18. pyxecm_api/auth/router.py +2 -3
  19. pyxecm_api/common/functions.py +67 -12
  20. pyxecm_api/settings.py +0 -8
  21. pyxecm_api/terminal/router.py +1 -1
  22. pyxecm_api/v1_csai/router.py +33 -18
  23. pyxecm_customizer/browser_automation.py +161 -79
  24. pyxecm_customizer/customizer.py +43 -25
  25. pyxecm_customizer/guidewire.py +422 -8
  26. pyxecm_customizer/k8s.py +23 -27
  27. pyxecm_customizer/knowledge_graph.py +498 -20
  28. pyxecm_customizer/m365.py +45 -44
  29. pyxecm_customizer/payload.py +1723 -1188
  30. pyxecm_customizer/payload_list.py +3 -0
  31. pyxecm_customizer/salesforce.py +122 -79
  32. pyxecm_customizer/servicenow.py +27 -7
  33. pyxecm_customizer/settings.py +3 -1
  34. pyxecm_customizer/successfactors.py +2 -2
  35. pyxecm_customizer/translate.py +1 -1
  36. pyxecm-3.0.1.dist-info/RECORD +0 -96
  37. pyxecm_api/agents/__init__.py +0 -7
  38. pyxecm_api/agents/app.py +0 -13
  39. pyxecm_api/agents/functions.py +0 -119
  40. pyxecm_api/agents/models.py +0 -10
  41. pyxecm_api/agents/otcm_knowledgegraph/__init__.py +0 -1
  42. pyxecm_api/agents/otcm_knowledgegraph/functions.py +0 -85
  43. pyxecm_api/agents/otcm_knowledgegraph/models.py +0 -61
  44. pyxecm_api/agents/otcm_knowledgegraph/router.py +0 -74
  45. pyxecm_api/agents/otcm_user_agent/__init__.py +0 -1
  46. pyxecm_api/agents/otcm_user_agent/models.py +0 -20
  47. pyxecm_api/agents/otcm_user_agent/router.py +0 -65
  48. pyxecm_api/agents/otcm_workspace_agent/__init__.py +0 -1
  49. pyxecm_api/agents/otcm_workspace_agent/models.py +0 -40
  50. pyxecm_api/agents/otcm_workspace_agent/router.py +0 -200
  51. {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/WHEEL +0 -0
  52. {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/entry_points.txt +0 -0
pyxecm/avts.py CHANGED
@@ -33,8 +33,8 @@ USER_AGENT = (
33
33
 
34
34
  REQUEST_HEADERS = {"User-Agent": USER_AGENT, "accept": "application/json", "Content-Type": "application/json"}
35
35
 
36
- REQUEST_TIMEOUT = 60
37
- REQUEST_RETRY_DELAY = 20
36
+ REQUEST_TIMEOUT = 60.0
37
+ REQUEST_RETRY_DELAY = 20.0
38
38
  REQUEST_MAX_RETRIES = 2
39
39
 
40
40
  default_logger = logging.getLogger(MODULE_NAME)
@@ -157,7 +157,7 @@ class AVTS:
157
157
  data: dict | list | None = None,
158
158
  json_data: dict | None = None,
159
159
  files: dict | None = None,
160
- timeout: int | None = REQUEST_TIMEOUT,
160
+ timeout: float | None = REQUEST_TIMEOUT,
161
161
  show_error: bool = True,
162
162
  failure_message: str = "",
163
163
  success_message: str = "",
@@ -181,7 +181,7 @@ class AVTS:
181
181
  Dictionary of {"name": file-tuple} for multipart encoding upload.
182
182
  The file-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple
183
183
  ("filename", fileobj, "content_type").
184
- timeout (int | None, optional):
184
+ timeout (float | None, optional):
185
185
  Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
186
186
  show_error (bool, optional):
187
187
  Whether or not an error should be logged in case of a failed REST call.
pyxecm/coreshare.py CHANGED
@@ -53,8 +53,8 @@ REQUEST_LOGIN_HEADERS = {
53
53
  "Accept": "application/json",
54
54
  }
55
55
 
56
- REQUEST_TIMEOUT = 60
57
- REQUEST_RETRY_DELAY = 20
56
+ REQUEST_TIMEOUT = 60.0
57
+ REQUEST_RETRY_DELAY = 20.0
58
58
  REQUEST_MAX_RETRIES = 2
59
59
 
60
60
  CONTENT_MANAGER_ROLE_ID = 5
@@ -303,7 +303,7 @@ class CoreShare:
303
303
  data: dict | None = None,
304
304
  json_data: dict | None = None,
305
305
  files: dict | None = None,
306
- timeout: int | None = REQUEST_TIMEOUT,
306
+ timeout: float | None = REQUEST_TIMEOUT,
307
307
  show_error: bool = True,
308
308
  show_warning: bool = False,
309
309
  warning_message: str = "",
@@ -331,7 +331,7 @@ class CoreShare:
331
331
  files (dict | None, optional):
332
332
  Dictionary of {"name": file-tuple} for multipart encoding upload.
333
333
  The file-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple ("filename", fileobj, "content_type")
334
- timeout (int | None, optional):
334
+ timeout (float | None, optional):
335
335
  Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
336
336
  show_error (bool, optional):
337
337
  Whether or not an error should be logged in case of a failed REST call.
@@ -463,7 +463,7 @@ class CoreShare:
463
463
  time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
464
464
  else:
465
465
  self.logger.error(
466
- "%s; timeout error.",
466
+ "%s; timeout error!",
467
467
  failure_message,
468
468
  )
469
469
  if retry_forever:
@@ -482,7 +482,7 @@ class CoreShare:
482
482
  time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
483
483
  else:
484
484
  self.logger.error(
485
- "%s; connection error.",
485
+ "%s; connection error!",
486
486
  failure_message,
487
487
  )
488
488
  if retry_forever:
@@ -2206,7 +2206,7 @@ class CoreShare:
2206
2206
 
2207
2207
  # Check if the photo file exists
2208
2208
  if not os.path.isfile(photo_path):
2209
- self.logger.error("Photo file -> %s not found!", photo_path)
2209
+ self.logger.error("Photo file -> '%s' not found for Core Share user with ID -> %s!", photo_path, user_id)
2210
2210
  return None
2211
2211
 
2212
2212
  try:
@@ -2216,8 +2216,7 @@ class CoreShare:
2216
2216
  except OSError:
2217
2217
  # Handle any errors that occurred while reading the photo file
2218
2218
  self.logger.error(
2219
- "Error reading photo file -> %s",
2220
- photo_path,
2219
+ "Error reading photo file -> '%s' for Core Share user with ID -> '%s'!", photo_path, user_id
2221
2220
  )
2222
2221
  return None
2223
2222
 
@@ -2238,7 +2237,7 @@ class CoreShare:
2238
2237
  headers=self.request_header_user(content_type=""),
2239
2238
  files=files,
2240
2239
  timeout=REQUEST_TIMEOUT,
2241
- failure_message="Failed to update profile photo of Core Share user with ID -> {}".format(
2240
+ failure_message="Failed to update profile photo of Core Share user with ID -> '{}'".format(
2242
2241
  user_id,
2243
2242
  ),
2244
2243
  user_credentials=True,
@@ -2668,7 +2667,7 @@ class CoreShare:
2668
2667
  response = self.delete_document(item["id"])
2669
2668
  else:
2670
2669
  self.logger.error(
2671
- "Unsupport resource type -> '%s'",
2670
+ "Unsupport resource type -> '%s'!",
2672
2671
  item["resourceType"],
2673
2672
  )
2674
2673
  response = None
@@ -2756,7 +2755,7 @@ class CoreShare:
2756
2755
  )
2757
2756
 
2758
2757
  self.logger.debug(
2759
- "Revoke sharing of folder -> %s with group -> %s; calling -> %s",
2758
+ "Revoke sharing of folder with ID -> '%s' with group with ID -> '%s'; calling -> %s",
2760
2759
  resource_id,
2761
2760
  group_id,
2762
2761
  request_url,
@@ -2767,7 +2766,7 @@ class CoreShare:
2767
2766
  method="DELETE",
2768
2767
  headers=request_header,
2769
2768
  timeout=REQUEST_TIMEOUT,
2770
- failure_message="Failed to revoke sharing Core Share folder with ID -> {} with group with ID -> {}".format(
2769
+ failure_message="Failed to revoke sharing Core Share folder with ID -> '{}' with group with ID -> '{}'!".format(
2771
2770
  resource_id,
2772
2771
  group_id,
2773
2772
  ),
@@ -2794,7 +2793,7 @@ class CoreShare:
2794
2793
  response = self.get_group_shares(group_id=group_id)
2795
2794
 
2796
2795
  if not response or not response["shares"]:
2797
- self.logger.info("Group -> %s has no shares to revoke!", group_id)
2796
+ self.logger.info("Group -> %s has no shares to revoke.", group_id)
2798
2797
  return True
2799
2798
 
2800
2799
  success = True
@@ -2802,7 +2801,7 @@ class CoreShare:
2802
2801
  items = response["shares"]
2803
2802
  for item in items:
2804
2803
  self.logger.info(
2805
- "Revoke sharing of folder -> %s (%s) with group -> %s...",
2804
+ "Revoke sharing of folder -> '%s' (%s) with group -> %s...",
2806
2805
  item["name"],
2807
2806
  item["id"],
2808
2807
  group_id,
pyxecm/helper/data.py CHANGED
@@ -1484,10 +1484,11 @@ class Data:
1484
1484
  remainder = 0
1485
1485
 
1486
1486
  self.logger.info(
1487
- "Data frame has -> %s elements. We split it into -> %s partitions with -> %s rows and remainder -> %s...",
1487
+ "Data frame has -> %s elements. We split it into -> %s partitions with -> %s row%s and remainder -> %s...",
1488
1488
  str(size),
1489
1489
  str(number),
1490
1490
  str(partition_size),
1491
+ "s" if partition_size > 1 else "",
1491
1492
  str(remainder),
1492
1493
  )
1493
1494
 
pyxecm/helper/web.py CHANGED
@@ -36,8 +36,8 @@ REQUEST_FORM_HEADERS = {
36
36
  "User-Agent": USER_AGENT,
37
37
  "Content-Type": "application/x-www-form-urlencoded",
38
38
  }
39
- REQUEST_TIMEOUT = 120
40
- REQUEST_RETRY_DELAY = 20
39
+ REQUEST_TIMEOUT = 120.0
40
+ REQUEST_RETRY_DELAY = 20.0
41
41
  REQUEST_MAX_RETRIES = 2
42
42
 
43
43
  default_logger = logging.getLogger(MODULE_NAME)
@@ -109,9 +109,9 @@ class HTTP:
109
109
  method: str = "POST",
110
110
  payload: dict | None = None,
111
111
  headers: dict | None = None,
112
- timeout: int = REQUEST_TIMEOUT,
112
+ timeout: float | None = REQUEST_TIMEOUT,
113
113
  retries: int = REQUEST_MAX_RETRIES,
114
- wait_time: int = REQUEST_RETRY_DELAY,
114
+ wait_time: float = REQUEST_RETRY_DELAY,
115
115
  wait_on_status: list | None = None,
116
116
  show_error: bool = True,
117
117
  stream: bool = False,
@@ -128,7 +128,7 @@ class HTTP:
128
128
  headers (dict, optional):
129
129
  Request header. Defaults to None. If None then a default
130
130
  value defined in REQUEST_FORM_HEADERS is used.
131
- timeout (int, optional):
131
+ timeout (float | None, optional):
132
132
  The timeout in seconds. Defaults to REQUEST_TIMEOUT.
133
133
  retries (int, optional):
134
134
  The number of retries. If -1 then unlimited retries.
@@ -238,7 +238,7 @@ class HTTP:
238
238
  if retries == 0:
239
239
  return None
240
240
 
241
- if wait_time > 0:
241
+ if wait_time > 0.0:
242
242
  self.logger.warning(
243
243
  "Sleeping %s seconds and then trying once more...",
244
244
  str(wait_time * try_counter),
@@ -255,9 +255,9 @@ class HTTP:
255
255
  self,
256
256
  url: str,
257
257
  filename: str,
258
- timeout: int = REQUEST_TIMEOUT,
259
- retries: int = REQUEST_MAX_RETRIES,
260
- wait_time: int = REQUEST_RETRY_DELAY,
258
+ timeout: float = REQUEST_TIMEOUT,
259
+ retries: int | None = REQUEST_MAX_RETRIES,
260
+ wait_time: float = REQUEST_RETRY_DELAY,
261
261
  wait_on_status: list | None = None,
262
262
  chunk_size: int = 8192,
263
263
  show_error: bool = True,
@@ -269,11 +269,11 @@ class HTTP:
269
269
  The URL to open / load.
270
270
  filename (str):
271
271
  The filename to save the content.
272
- timeout (int, optional):
272
+ timeout (float, optional):
273
273
  The timeout in seconds.
274
274
  retries (int, optional):
275
275
  The number of retries. If -1 then unlimited retries.
276
- wait_time (int, optional):
276
+ wait_time (float, optional):
277
277
  The number of seconds to wait after each try.
278
278
  wait_on_status (list, optional):
279
279
  The list of status codes we want to wait on.
pyxecm/helper/xml.py CHANGED
@@ -55,12 +55,16 @@ class XML:
55
55
  # end method definition
56
56
 
57
57
  @classmethod
58
- def xml_to_dict(cls, xml_string: str) -> dict:
58
+ def xml_to_dict(cls, xml_string: str, encode: bool = False, include_attributes: bool = False) -> dict:
59
59
  """Parse XML string and return a dictionary without namespaces.
60
60
 
61
61
  Args:
62
62
  xml_string (str):
63
63
  The XML string to process.
64
+ encode (bool, optional):
65
+ True if the XML string should be encoded to UTF-8 bytes. Defaults to False.
66
+ include_attributes (bool, optional):
67
+ True if XML attributes should be included in the dictionary. Defaults to False.
64
68
 
65
69
  Returns:
66
70
  dict:
@@ -80,20 +84,47 @@ class XML:
80
84
  Dictionary representing the XML element
81
85
 
82
86
  """
87
+
83
88
  tag = cls.remove_xml_namespace(element.tag)
84
89
  children = list(element)
90
+ node_dict = {}
91
+
92
+ if element.attrib and include_attributes:
93
+ node_dict.update({"@{}".format(k): v for k, v in element.attrib.items()})
94
+
85
95
  if children:
86
- return {
87
- tag: {
88
- cls.remove_xml_namespace(child.tag): xml_element_to_dict(child)[
89
- cls.remove_xml_namespace(child.tag)
90
- ]
91
- for child in children
92
- }
93
- }
96
+ child_dict = {}
97
+ for child in children:
98
+ child_tag = cls.remove_xml_namespace(child.tag)
99
+ child_value = xml_element_to_dict(child)
100
+
101
+ # child_dict is {child_tag: ...}, we want the value inside
102
+ value = child_value[child_tag]
103
+
104
+ # Handle multiple occurrences of the same tag:
105
+ if child_tag in child_dict:
106
+ # If the tag already exists, ensure it becomes a list
107
+ if not isinstance(child_dict[child_tag], list):
108
+ child_dict[child_tag] = [child_dict[child_tag]]
109
+ child_dict[child_tag].append(value)
110
+ else:
111
+ child_dict[child_tag] = value
112
+
113
+ # Merge children into node_dict
114
+ node_dict.update(child_dict)
115
+
116
+ # Add text if present and meaningful
117
+ text = element.text.strip() if element.text and element.text.strip() else None
118
+ if text:
119
+ if node_dict:
120
+ node_dict["#text"] = text
121
+ else:
122
+ return {tag: text}
94
123
 
95
- return {tag: element.text.strip() if element.text else None}
124
+ return {tag: node_dict if node_dict else text}
96
125
 
126
+ if encode:
127
+ xml_string = xml_string.encode("utf-8")
97
128
  root = etree.fromstring(xml_string)
98
129
 
99
130
  return xml_element_to_dict(root)
pyxecm/otac.py CHANGED
@@ -43,7 +43,7 @@ REQUEST_JSON_HEADERS = {
43
43
  "Content-Type": "application/json",
44
44
  }
45
45
 
46
- REQUEST_TIMEOUT = 60
46
+ REQUEST_TIMEOUT = 60.0
47
47
 
48
48
  default_logger = logging.getLogger(MODULE_NAME)
49
49
 
pyxecm/otawp.py CHANGED
@@ -53,10 +53,10 @@ REQUEST_HEADERS_JSON = {
53
53
  "accept": "application/json",
54
54
  }
55
55
 
56
- REQUEST_TIMEOUT = 120
56
+ REQUEST_TIMEOUT = 120.0
57
57
  REQUEST_MAX_RETRIES = 10
58
- REQUEST_RETRY_DELAY = 30
59
- SYNC_PUBLISH_REQUEST_TIMEOUT = 600
58
+ REQUEST_RETRY_DELAY = 30.0
59
+ SYNC_PUBLISH_REQUEST_TIMEOUT = 600.0
60
60
 
61
61
  default_logger = logging.getLogger(MODULE_NAME)
62
62
 
@@ -332,13 +332,13 @@ class OTAWP:
332
332
  The hostname of Extended ECM server to communicate with.
333
333
  port (int):
334
334
  The port number used to talk to the Extended ECM server.
335
- username (str, optional):
335
+ username (str | None, optional):
336
336
  The admin user name of OTAWP. Optional if otawp_ticket is provided.
337
- password (str, optional):
337
+ password (str | None, optional):
338
338
  The admin password of OTAWP. Optional if otawp_ticket is provided.
339
- organization (str, optional):
339
+ organization (str | None, optional):
340
340
  The AppWorks organization. Used in LDAP strings and base URL.
341
- otawp_ticket (str, optional):
341
+ otawp_ticket (str | None, optional):
342
342
  The authentication ticket of OTAWP.
343
343
  config_map_name (str | None, optional):
344
344
  The AppWorks Kubernetes Config Map name. Defaults to None.
@@ -805,8 +805,8 @@ class OTAWP:
805
805
  The key to find.
806
806
 
807
807
  Returns:
808
- str:
809
- The value for the key.
808
+ str | None:
809
+ The value for the key. None in case of an error.
810
810
 
811
811
  """
812
812
 
@@ -859,7 +859,7 @@ class OTAWP:
859
859
  data: dict | None = None,
860
860
  json_data: dict | None = None,
861
861
  files: dict | None = None,
862
- timeout: int | None = REQUEST_TIMEOUT,
862
+ timeout: float | None = REQUEST_TIMEOUT,
863
863
  show_error: bool = True,
864
864
  show_warning: bool = False,
865
865
  warning_message: str = "",
@@ -886,7 +886,7 @@ class OTAWP:
886
886
  files (dict | None, optional):
887
887
  Dictionary of {"name": file-tuple} for multipart encoding upload.
888
888
  The file-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple ("filename", fileobj, "content_type")
889
- timeout (int | None, optional):
889
+ timeout (float | None, optional):
890
890
  Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
891
891
  show_error (bool, optional):
892
892
  Whether or not an error should be logged in case of a failed REST call.
@@ -995,9 +995,9 @@ class OTAWP:
995
995
  Args:
996
996
  response_object (object):
997
997
  This is reponse object delivered by the request call.
998
- additional_error_message (str):
998
+ additional_error_message (str, optional):
999
999
  Print a custom error message.
1000
- show_error (bool):
1000
+ show_error (bool, optional):
1001
1001
  If True log an error, if False log a warning.
1002
1002
 
1003
1003
  Returns:
@@ -1111,7 +1111,7 @@ class OTAWP:
1111
1111
  Whether an error or just a warning should be logged.
1112
1112
 
1113
1113
  Returns:
1114
- str | None:
1114
+ str | int | None:
1115
1115
  Value of the item with the given key, or None if no value is found.
1116
1116
 
1117
1117
  """
@@ -1982,7 +1982,7 @@ class OTAWP:
1982
1982
  The trading name.
1983
1983
 
1984
1984
  Returns:
1985
- dict:
1985
+ dict | None:
1986
1986
  Request response (dictionary) or None if the REST call fails.
1987
1987
 
1988
1988
  """
@@ -2310,7 +2310,7 @@ class OTAWP:
2310
2310
  cookies=self.cookie(),
2311
2311
  json_data=create_category_data,
2312
2312
  timeout=REQUEST_TIMEOUT,
2313
- failure_message="Request to create category -> '{}' failed".format(name),
2313
+ failure_message="Failed to create category -> '{}'".format(name),
2314
2314
  )
2315
2315
 
2316
2316
  # end method definition
@@ -2375,7 +2375,7 @@ class OTAWP:
2375
2375
  headers=REQUEST_HEADERS_JSON,
2376
2376
  cookies=self.cookie(),
2377
2377
  timeout=REQUEST_TIMEOUT,
2378
- failure_message="Request to get categories failed",
2378
+ failure_message="Failed to get categories",
2379
2379
  )
2380
2380
 
2381
2381
  # end method definition
@@ -2480,7 +2480,7 @@ class OTAWP:
2480
2480
  cookies=self.cookie(),
2481
2481
  json_data=create_sub_category_data,
2482
2482
  timeout=REQUEST_TIMEOUT,
2483
- failure_message="Request to create sub-category -> '{}' with parent category ID -> {} failed".format(
2483
+ failure_message="Failed to create sub-category -> '{}' with parent category ID -> {}".format(
2484
2484
  name, parent_id
2485
2485
  ),
2486
2486
  )
@@ -2541,7 +2541,7 @@ class OTAWP:
2541
2541
  headers=REQUEST_HEADERS_JSON,
2542
2542
  cookies=self.cookie(),
2543
2543
  timeout=REQUEST_TIMEOUT,
2544
- failure_message="Request to get sub-categories for parent category with ID -> {} failed".format(parent_id),
2544
+ failure_message="Failed to get sub-categories for parent category with ID -> {}".format(parent_id),
2545
2545
  )
2546
2546
 
2547
2547
  # end method definition