pyxecm 2.0.0__py3-none-any.whl → 2.0.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 (50) hide show
  1. pyxecm/__init__.py +2 -1
  2. pyxecm/avts.py +79 -33
  3. pyxecm/customizer/api/app.py +45 -796
  4. pyxecm/customizer/api/auth/__init__.py +1 -0
  5. pyxecm/customizer/api/{auth.py → auth/functions.py} +2 -64
  6. pyxecm/customizer/api/auth/router.py +78 -0
  7. pyxecm/customizer/api/common/__init__.py +1 -0
  8. pyxecm/customizer/api/common/functions.py +47 -0
  9. pyxecm/customizer/api/{metrics.py → common/metrics.py} +1 -1
  10. pyxecm/customizer/api/common/models.py +21 -0
  11. pyxecm/customizer/api/{payload_list.py → common/payload_list.py} +6 -1
  12. pyxecm/customizer/api/common/router.py +72 -0
  13. pyxecm/customizer/api/settings.py +25 -0
  14. pyxecm/customizer/api/terminal/__init__.py +1 -0
  15. pyxecm/customizer/api/terminal/router.py +87 -0
  16. pyxecm/customizer/api/v1_csai/__init__.py +1 -0
  17. pyxecm/customizer/api/v1_csai/router.py +87 -0
  18. pyxecm/customizer/api/v1_maintenance/__init__.py +1 -0
  19. pyxecm/customizer/api/v1_maintenance/functions.py +100 -0
  20. pyxecm/customizer/api/v1_maintenance/models.py +12 -0
  21. pyxecm/customizer/api/v1_maintenance/router.py +76 -0
  22. pyxecm/customizer/api/v1_otcs/__init__.py +1 -0
  23. pyxecm/customizer/api/v1_otcs/functions.py +61 -0
  24. pyxecm/customizer/api/v1_otcs/router.py +179 -0
  25. pyxecm/customizer/api/v1_payload/__init__.py +1 -0
  26. pyxecm/customizer/api/v1_payload/functions.py +179 -0
  27. pyxecm/customizer/api/v1_payload/models.py +51 -0
  28. pyxecm/customizer/api/v1_payload/router.py +499 -0
  29. pyxecm/customizer/browser_automation.py +568 -326
  30. pyxecm/customizer/customizer.py +204 -430
  31. pyxecm/customizer/guidewire.py +907 -43
  32. pyxecm/customizer/k8s.py +243 -56
  33. pyxecm/customizer/m365.py +104 -15
  34. pyxecm/customizer/payload.py +1943 -885
  35. pyxecm/customizer/pht.py +19 -2
  36. pyxecm/customizer/servicenow.py +22 -5
  37. pyxecm/customizer/settings.py +9 -6
  38. pyxecm/helper/xml.py +69 -0
  39. pyxecm/otac.py +1 -1
  40. pyxecm/otawp.py +2104 -1535
  41. pyxecm/otca.py +569 -0
  42. pyxecm/otcs.py +201 -37
  43. pyxecm/otds.py +35 -13
  44. {pyxecm-2.0.0.dist-info → pyxecm-2.0.1.dist-info}/METADATA +6 -29
  45. pyxecm-2.0.1.dist-info/RECORD +76 -0
  46. {pyxecm-2.0.0.dist-info → pyxecm-2.0.1.dist-info}/WHEEL +1 -1
  47. pyxecm-2.0.0.dist-info/RECORD +0 -54
  48. /pyxecm/customizer/api/{models.py → auth/models.py} +0 -0
  49. {pyxecm-2.0.0.dist-info → pyxecm-2.0.1.dist-info}/licenses/LICENSE +0 -0
  50. {pyxecm-2.0.0.dist-info → pyxecm-2.0.1.dist-info}/top_level.txt +0 -0
pyxecm/customizer/pht.py CHANGED
@@ -17,21 +17,38 @@ __email__ = "mdiefenb@opentext.com"
17
17
 
18
18
  import json
19
19
  import logging
20
+ import platform
21
+ import sys
20
22
  import time
23
+ from importlib.metadata import version
21
24
 
22
25
  import requests
23
26
  from requests.auth import HTTPBasicAuth
24
27
 
25
28
  from pyxecm.helper import Data
26
29
 
27
- default_logger = logging.getLogger("pyxecm.customizer.pht")
30
+ APP_NAME = "pyxecm"
31
+ APP_VERSION = version("pyxecm")
32
+ MODULE_NAME = APP_NAME + ".customizer.pht"
28
33
 
29
- REQUEST_HEADERS = {"Accept": "application/json", "Content-Type": "application/json"}
34
+ PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
35
+ OS_INFO = f"{platform.system()} {platform.release()}"
36
+ ARCH_INFO = platform.machine()
37
+ REQUESTS_VERSION = requests.__version__
38
+
39
+ USER_AGENT = (
40
+ f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
41
+ f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
42
+ )
43
+
44
+ REQUEST_HEADERS = {"User-Agent": USER_AGENT, "accept": "application/json", "Content-Type": "application/json"}
30
45
 
31
46
  REQUEST_TIMEOUT = 60
32
47
  REQUEST_RETRY_DELAY = 20
33
48
  REQUEST_MAX_RETRIES = 2
34
49
 
50
+ default_logger = logging.getLogger(MODULE_NAME)
51
+
35
52
 
36
53
  class PHT:
37
54
  """Class PHT is used to retrieve data from OpenText PHT. It is a pure read-only access."""
@@ -12,12 +12,15 @@ __email__ = "mdiefenb@opentext.com"
12
12
  import json
13
13
  import logging
14
14
  import os
15
+ import platform
16
+ import sys
15
17
  import tempfile
16
18
  import threading
17
19
  import time
18
20
  import urllib.parse
19
21
  from collections.abc import Callable
20
22
  from functools import cache
23
+ from importlib.metadata import version
21
24
  from typing import Any
22
25
 
23
26
  import requests
@@ -26,14 +29,28 @@ from requests.exceptions import HTTPError, RequestException
26
29
 
27
30
  from pyxecm.helper import Data
28
31
 
29
- default_logger = logging.getLogger("pyxecm.customizer.servicenow")
32
+ APP_NAME = "pyxecm"
33
+ APP_VERSION = version("pyxecm")
34
+ MODULE_NAME = APP_NAME + ".customizer.servicenow"
30
35
 
31
- REQUEST_HEADERS = {"Accept": "application/json", "Content-Type": "application/json"}
36
+ PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
37
+ OS_INFO = f"{platform.system()} {platform.release()}"
38
+ ARCH_INFO = platform.machine()
39
+ REQUESTS_VERSION = requests.__version__
40
+
41
+ USER_AGENT = (
42
+ f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
43
+ f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
44
+ )
45
+
46
+ REQUEST_HEADERS = {"User-Agent": USER_AGENT, "Accept": "application/json", "Content-Type": "application/json"}
32
47
 
33
48
  REQUEST_TIMEOUT = 60
34
49
 
35
50
  KNOWLEDGE_BASE_PATH = os.path.join(tempfile.gettempdir(), "attachments")
36
51
 
52
+ default_logger = logging.getLogger(MODULE_NAME)
53
+
37
54
  # ServiceNow database tables. Table names starting with "u_" are custom OpenText tables:
38
55
  SN_TABLE_CATEGORIES = "kb_category"
39
56
  SN_TABLE_KNOWLEDGE_BASES = "kb_knowledge_base"
@@ -78,7 +95,7 @@ class ServiceNow:
78
95
  base_url (str):
79
96
  The base URL of the ServiceNow tenant.
80
97
  auth_type (str):
81
- Athe authorization type, either "oauth" or "basic".
98
+ The authorization type, either "oauth" or "basic".
82
99
  client_id (str):
83
100
  ServiceNow Client ID.
84
101
  client_secret (str):
@@ -168,7 +185,7 @@ class ServiceNow:
168
185
 
169
186
  Returns:
170
187
  dict:
171
- The configuration dictionary.
188
+ The configuration dictionary with all settings.
172
189
 
173
190
  """
174
191
 
@@ -387,7 +404,7 @@ class ServiceNow:
387
404
 
388
405
  return token
389
406
  else:
390
- self.logger.error("Unsupported authentication type")
407
+ self.logger.error("Unsupported authentication type -> %s!", auth_type)
391
408
  return None
392
409
 
393
410
  # end method definition
@@ -19,7 +19,7 @@ class CustomizerSettingsOTDS(BaseModel):
19
19
  username: str = Field(default="admin", description="Username for the OTDS admin user")
20
20
  password: SecretStr = Field(default=None, description="Password for the OTDS admin user")
21
21
  ticket: str | None = Field(None, description="Ticket for the OTDS admin user")
22
- admin_partition: str = Field(default="otds.admin", description="Name of the default Partition in OTDS")
22
+ admin_partition: str = Field(default="otds.admin", description="Name of the admin partition in OTDS")
23
23
  enable_audit: bool = Field(default=True, description="Enable the OTDS Audit")
24
24
  disable_password_policy: bool = Field(
25
25
  default=True,
@@ -68,6 +68,7 @@ class CustomizerSettingsOTCS(BaseModel):
68
68
  username: str = Field(default="admin", description="Username for the OTCS admin user")
69
69
  password: SecretStr = Field(default=None, description="Password for the OTCS admin user")
70
70
  base_path: str = Field(default="/cs/cs", description="Base path of the OTCS installation")
71
+ support_path: str = Field(default="/cssupport", description="Support path of the OTCS installation")
71
72
  url: HttpUrl | None = Field(default=None, description="URL of the OTCS service")
72
73
  url_frontend: HttpUrl | None = Field(
73
74
  default=None,
@@ -91,7 +92,7 @@ class CustomizerSettingsOTCS(BaseModel):
91
92
  description="temporary download directory for payload processing",
92
93
  )
93
94
 
94
- # FEME endpoint for additional indexing supporting Content Aviator:
95
+ # FEME endpoint for additional embedding supporting Content Aviator:
95
96
  feme_uri: str = Field(default="ws://feme:4242", description="URL of the FEME endpoint")
96
97
 
97
98
  # Add configuration options for Customizer behaviour
@@ -266,7 +267,7 @@ class CustomizerSettingsK8S(BaseModel):
266
267
  sts_otcs_admin_replicas: int = Field(default=None)
267
268
  ingress_otxecm: str = Field(default="otxecm-ingress", description="Name of the otxecm ingress")
268
269
 
269
- maintenance_service_name: str = Field(default="otxecm-customizer")
270
+ maintenance_service_name: str = Field(default="customizer")
270
271
  maintenance_service_port: int = Field(default=5555)
271
272
 
272
273
 
@@ -279,6 +280,7 @@ class CustomizerSettingsOTAWP(BaseModel):
279
280
  description="Username of the OTAWP Admin user",
280
281
  )
281
282
  password: SecretStr = Field(default=None, description="Password of the OTAWP Admin user")
283
+ organization: str = Field(default="system", description="The name of the organization (kind of tenant in AppWorks)")
282
284
  license_file: str = Field(default="/payload/otawp-license.lic", description="Path to the OTAWP license file.")
283
285
  product_name: str = Field(default="APPWORKS_PLATFORM", description="Name of the Product for the license")
284
286
  product_description: str = Field(
@@ -351,7 +353,6 @@ class CustomizerSettingsAVTS(BaseModel):
351
353
  enabled: bool = Field(default=False, description="Enable Aviator Search configuration")
352
354
  username: str = Field(default="", description="Admin username for Aviator Search")
353
355
  password: str = Field(default="", description="Admin password for Aviator Search")
354
- otds_url: HttpUrl | None = Field(default=None, description="URL of the OTDS")
355
356
  client_id: str = Field(default="", description="OTDS Client ID for Aviator Search")
356
357
  client_secret: str = Field(default="", description="OTDS Client Secret for Aviator Search")
357
358
  base_url: HttpUrl | None = Field(
@@ -399,13 +400,15 @@ class Settings(BaseSettings):
399
400
 
400
401
  profiling: bool = Field(
401
402
  default=False,
402
- description=" Profiling can only be enabled when using the CustomizerAPI. Switch to enable python profiling using pyinstrument. Result is a html file showing the execution of payload broken down into functions and their duration. The files are located in the logdir. Profiling is disabled by default.",
403
+ description="Profiling can only be enabled when using the CustomizerAPI. Switch to enable python profiling using pyinstrument. Result is a html file showing the execution of payload broken down into functions and their duration. The files are located in the logdir. Profiling is disabled by default.",
403
404
  )
404
405
  cprofiling: bool = Field(
405
406
  default=False,
406
- description=" Profiling can only be enabled when using the CustomizerAPI. Switch to enable python profiling using cProfile. Result is a log file with the cProfile results, as well as a dump of the profiling session. The files are located in the logdir. The files are located in the logdir. Profilig is disabled by default.",
407
+ description="Profiling can only be enabled when using the CustomizerAPI. Switch to enable python profiling using cProfile. Result is a log file with the cProfile results, as well as a dump of the profiling session. The files are located in the logdir. The files are located in the logdir. Profilig is disabled by default.",
407
408
  )
408
409
 
410
+ headless_browser: bool = Field(default=True, description="Headless Browser for the BrowserAutomation")
411
+
409
412
  otds: CustomizerSettingsOTDS = CustomizerSettingsOTDS()
410
413
  otcs: CustomizerSettingsOTCS = CustomizerSettingsOTCS()
411
414
  otac: CustomizerSettingsOTAC = CustomizerSettingsOTAC()
pyxecm/helper/xml.py CHANGED
@@ -31,6 +31,75 @@ class XML:
31
31
 
32
32
  logger: logging.Logger = default_logger
33
33
 
34
+ @classmethod
35
+ def remove_xml_namespace(cls, tag: str) -> str:
36
+ """Remove namespace from XML tag.
37
+
38
+ Args:
39
+ tag (str):
40
+ The XML tag with namespace.
41
+
42
+ Returns:
43
+ str:
44
+ The tag without namespace.
45
+
46
+ """
47
+
48
+ # In Python's ElementTree, the tag namespace
49
+ # is put into curly braces like "{namespace}element"
50
+ # that's why this method splits after the closing curly brace
51
+ # and takes the last item (-1):
52
+
53
+ return tag.split("}", 1)[-1]
54
+
55
+ # end method definition
56
+
57
+ @classmethod
58
+ def xml_to_dict(cls, xml_string: str) -> dict:
59
+ """Parse XML string and return a dictionary without namespaces.
60
+
61
+ Args:
62
+ xml_string (str):
63
+ The XML string to process.
64
+
65
+ Returns:
66
+ dict:
67
+ The XML structure converted to a dictionary.
68
+
69
+ """
70
+
71
+ def xml_element_to_dict(element: Element) -> dict:
72
+ """Convert XML element to dictionary.
73
+
74
+ Args:
75
+ element (Element):
76
+ The XML element.
77
+
78
+ Returns:
79
+ dict:
80
+ Dictionary representing the XML element
81
+
82
+ """
83
+ tag = cls.remove_xml_namespace(element.tag)
84
+ children = list(element)
85
+ 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
+ }
94
+
95
+ return {tag: element.text.strip() if element.text else None}
96
+
97
+ root = etree.fromstring(xml_string)
98
+
99
+ return xml_element_to_dict(root)
100
+
101
+ # end method definition
102
+
34
103
  @classmethod
35
104
  def load_xml_file(
36
105
  cls,
pyxecm/otac.py CHANGED
@@ -387,7 +387,7 @@ class OTAC:
387
387
  # Check if previous authentication was not successful.
388
388
  # Then we do the normal username + password authentication:
389
389
  self.logger.debug(
390
- "Requesting OTAC ticket with User/Password; calling -> %s",
390
+ "Requesting OTAC ticket with username and password; calling -> %s",
391
391
  request_url,
392
392
  )
393
393