pyxecm 3.0.1__py3-none-any.whl → 3.1.0__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.
- pyxecm/avts.py +4 -4
- pyxecm/coreshare.py +14 -15
- pyxecm/helper/data.py +2 -1
- pyxecm/helper/web.py +11 -11
- pyxecm/helper/xml.py +41 -10
- pyxecm/otac.py +1 -1
- pyxecm/otawp.py +19 -19
- pyxecm/otca.py +870 -67
- pyxecm/otcs.py +1567 -280
- pyxecm/otds.py +332 -153
- pyxecm/otkd.py +4 -4
- pyxecm/otmm.py +1 -1
- pyxecm/otpd.py +246 -30
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.0.dist-info}/METADATA +2 -1
- pyxecm-3.1.0.dist-info/RECORD +82 -0
- pyxecm_api/app.py +45 -35
- pyxecm_api/auth/functions.py +2 -2
- pyxecm_api/auth/router.py +2 -3
- pyxecm_api/common/functions.py +164 -12
- pyxecm_api/settings.py +0 -8
- pyxecm_api/terminal/router.py +1 -1
- pyxecm_api/v1_csai/router.py +33 -18
- pyxecm_customizer/browser_automation.py +98 -48
- pyxecm_customizer/customizer.py +43 -25
- pyxecm_customizer/guidewire.py +422 -8
- pyxecm_customizer/k8s.py +23 -27
- pyxecm_customizer/knowledge_graph.py +501 -20
- pyxecm_customizer/m365.py +45 -44
- pyxecm_customizer/payload.py +1684 -1159
- pyxecm_customizer/payload_list.py +3 -0
- pyxecm_customizer/salesforce.py +122 -79
- pyxecm_customizer/servicenow.py +27 -7
- pyxecm_customizer/settings.py +3 -1
- pyxecm_customizer/successfactors.py +2 -2
- pyxecm_customizer/translate.py +1 -1
- pyxecm-3.0.1.dist-info/RECORD +0 -96
- pyxecm_api/agents/__init__.py +0 -7
- pyxecm_api/agents/app.py +0 -13
- pyxecm_api/agents/functions.py +0 -119
- pyxecm_api/agents/models.py +0 -10
- pyxecm_api/agents/otcm_knowledgegraph/__init__.py +0 -1
- pyxecm_api/agents/otcm_knowledgegraph/functions.py +0 -85
- pyxecm_api/agents/otcm_knowledgegraph/models.py +0 -61
- pyxecm_api/agents/otcm_knowledgegraph/router.py +0 -74
- pyxecm_api/agents/otcm_user_agent/__init__.py +0 -1
- pyxecm_api/agents/otcm_user_agent/models.py +0 -20
- pyxecm_api/agents/otcm_user_agent/router.py +0 -65
- pyxecm_api/agents/otcm_workspace_agent/__init__.py +0 -1
- pyxecm_api/agents/otcm_workspace_agent/models.py +0 -40
- pyxecm_api/agents/otcm_workspace_agent/router.py +0 -200
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.0.dist-info}/WHEEL +0 -0
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.0.dist-info}/entry_points.txt +0 -0
pyxecm/otkd.py
CHANGED
|
@@ -50,8 +50,8 @@ REQUEST_UPLOAD_HEADERS = {
|
|
|
50
50
|
# DO NOT set "Content-Type" manually
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
REQUEST_TIMEOUT = 60
|
|
54
|
-
REQUEST_RETRY_DELAY = 20
|
|
53
|
+
REQUEST_TIMEOUT = 60.0
|
|
54
|
+
REQUEST_RETRY_DELAY = 20.0
|
|
55
55
|
REQUEST_MAX_RETRIES = 2
|
|
56
56
|
|
|
57
57
|
default_logger = logging.getLogger(MODULE_NAME)
|
|
@@ -301,7 +301,7 @@ class OTKD:
|
|
|
301
301
|
data: dict | None = None,
|
|
302
302
|
json_data: dict | None = None,
|
|
303
303
|
files: dict | None = None,
|
|
304
|
-
timeout:
|
|
304
|
+
timeout: float | None = REQUEST_TIMEOUT,
|
|
305
305
|
show_error: bool = True,
|
|
306
306
|
show_warning: bool = False,
|
|
307
307
|
warning_message: str = "",
|
|
@@ -327,7 +327,7 @@ class OTKD:
|
|
|
327
327
|
files (dict | None, optional):
|
|
328
328
|
Dictionary of {"name": file-tuple} for multipart encoding upload.
|
|
329
329
|
File-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple ("filename", fileobj, "content_type")
|
|
330
|
-
timeout (
|
|
330
|
+
timeout (float | None, optional):
|
|
331
331
|
The timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
|
|
332
332
|
show_error (bool, optional):
|
|
333
333
|
Whether or not an error should be logged in case of a failed REST call.
|
pyxecm/otmm.py
CHANGED
pyxecm/otpd.py
CHANGED
|
@@ -9,11 +9,46 @@ __email__ = "mdiefenb@opentext.com"
|
|
|
9
9
|
import json
|
|
10
10
|
import logging
|
|
11
11
|
import os
|
|
12
|
+
import platform
|
|
13
|
+
import sys
|
|
14
|
+
import time
|
|
15
|
+
from http import HTTPStatus
|
|
16
|
+
from importlib.metadata import version
|
|
12
17
|
|
|
13
18
|
import requests
|
|
14
19
|
from requests.auth import HTTPBasicAuth
|
|
15
20
|
from requests_toolbelt.multipart.encoder import MultipartEncoder
|
|
16
21
|
|
|
22
|
+
APP_NAME = "pyxecm"
|
|
23
|
+
APP_VERSION = version("pyxecm")
|
|
24
|
+
MODULE_NAME = APP_NAME + ".otpd"
|
|
25
|
+
|
|
26
|
+
PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
27
|
+
OS_INFO = f"{platform.system()} {platform.release()}"
|
|
28
|
+
ARCH_INFO = platform.machine()
|
|
29
|
+
REQUESTS_VERSION = requests.__version__
|
|
30
|
+
|
|
31
|
+
USER_AGENT = (
|
|
32
|
+
f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
|
|
33
|
+
f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
REQUEST_HEADERS = {
|
|
37
|
+
"User-Agent": USER_AGENT,
|
|
38
|
+
"accept": "application/json;charset=utf-8",
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
REQUEST_FORM_HEADERS = {
|
|
43
|
+
"User-Agent": USER_AGENT,
|
|
44
|
+
"accept": "application/json;charset=utf-8",
|
|
45
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
REQUEST_TIMEOUT = 60.0
|
|
49
|
+
REQUEST_RETRY_DELAY = 20.0
|
|
50
|
+
REQUEST_MAX_RETRIES = 2
|
|
51
|
+
|
|
17
52
|
default_logger = logging.getLogger("pyxecm.otpd")
|
|
18
53
|
|
|
19
54
|
request_headers = {
|
|
@@ -93,15 +128,17 @@ class OTPD:
|
|
|
93
128
|
otpd_base_url = protocol + "://" + otpd_config["hostname"]
|
|
94
129
|
if str(port) not in ["80", "443"]:
|
|
95
130
|
otpd_base_url += ":{}".format(port)
|
|
96
|
-
otpd_base_url += "/ServerManager"
|
|
97
131
|
otpd_config["baseUrl"] = otpd_base_url
|
|
98
132
|
|
|
99
|
-
|
|
133
|
+
otpd_servermanager_url = otpd_base_url + "/ServerManager"
|
|
134
|
+
otpd_config["serverManagerUrl"] = otpd_servermanager_url
|
|
135
|
+
|
|
136
|
+
otpd_rest_url = otpd_servermanager_url + "/api"
|
|
100
137
|
otpd_config["restUrl"] = otpd_rest_url
|
|
101
138
|
|
|
102
139
|
otpd_config["settingsUrl"] = otpd_rest_url + "/v1/settings"
|
|
103
140
|
|
|
104
|
-
otpd_config["importDatabaseUrl"] =
|
|
141
|
+
otpd_config["importDatabaseUrl"] = otpd_servermanager_url + "/servlet/import"
|
|
105
142
|
|
|
106
143
|
self._config = otpd_config
|
|
107
144
|
|
|
@@ -174,32 +211,6 @@ class OTPD:
|
|
|
174
211
|
|
|
175
212
|
# end method definition
|
|
176
213
|
|
|
177
|
-
def base_url(self) -> str:
|
|
178
|
-
"""Return the base URL of PowerDocs.
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
string:
|
|
182
|
-
The base URL.
|
|
183
|
-
|
|
184
|
-
"""
|
|
185
|
-
|
|
186
|
-
return self.config()["baseUrl"]
|
|
187
|
-
|
|
188
|
-
# end method definition
|
|
189
|
-
|
|
190
|
-
def rest_url(self) -> str:
|
|
191
|
-
"""Return the REST URL of PowerDocs.
|
|
192
|
-
|
|
193
|
-
Returns:
|
|
194
|
-
string:
|
|
195
|
-
The REST URL.
|
|
196
|
-
|
|
197
|
-
"""
|
|
198
|
-
|
|
199
|
-
return self.config()["restUrl"]
|
|
200
|
-
|
|
201
|
-
# end method definition
|
|
202
|
-
|
|
203
214
|
def parse_request_response(
|
|
204
215
|
self,
|
|
205
216
|
response_object: object,
|
|
@@ -270,7 +281,7 @@ class OTPD:
|
|
|
270
281
|
return self._jsessionid
|
|
271
282
|
|
|
272
283
|
auth_url = (
|
|
273
|
-
self.
|
|
284
|
+
self.config()["serverManagerUrl"]
|
|
274
285
|
+ "/j_security_check?j_username="
|
|
275
286
|
+ self.config()["username"]
|
|
276
287
|
+ "&j_password="
|
|
@@ -482,3 +493,208 @@ class OTPD:
|
|
|
482
493
|
return None
|
|
483
494
|
|
|
484
495
|
# end method definition
|
|
496
|
+
|
|
497
|
+
def do_request(
|
|
498
|
+
self,
|
|
499
|
+
url: str,
|
|
500
|
+
method: str = "GET",
|
|
501
|
+
headers: dict | None = None,
|
|
502
|
+
data: dict | None = None,
|
|
503
|
+
json_data: dict | None = None,
|
|
504
|
+
files: dict | None = None,
|
|
505
|
+
timeout: float | None = REQUEST_TIMEOUT,
|
|
506
|
+
show_error: bool = True,
|
|
507
|
+
show_warning: bool = False,
|
|
508
|
+
warning_message: str = "",
|
|
509
|
+
failure_message: str = "",
|
|
510
|
+
success_message: str = "",
|
|
511
|
+
max_retries: int = REQUEST_MAX_RETRIES,
|
|
512
|
+
retry_forever: bool = False,
|
|
513
|
+
parse_request_response: bool = True,
|
|
514
|
+
) -> dict | None:
|
|
515
|
+
"""Call an OTDS REST API in a safe way.
|
|
516
|
+
|
|
517
|
+
Args:
|
|
518
|
+
url (str):
|
|
519
|
+
The URL to send the request to.
|
|
520
|
+
method (str, optional):
|
|
521
|
+
The HTTP method (GET, POST, etc.). Defaults to "GET".
|
|
522
|
+
headers (dict | None, optional):
|
|
523
|
+
The request headers. Defaults to None.
|
|
524
|
+
data (dict | None, optional):
|
|
525
|
+
Request payload. Defaults to None
|
|
526
|
+
json_data (dict | None, optional):
|
|
527
|
+
Request payload for the JSON parameter. Defaults to None.
|
|
528
|
+
files (dict | None, optional):
|
|
529
|
+
Dictionary of {"name": file-tuple} for multipart encoding upload.
|
|
530
|
+
File-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple ("filename", fileobj, "content_type")
|
|
531
|
+
timeout (int | None, optional):
|
|
532
|
+
The timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
|
|
533
|
+
show_error (bool, optional):
|
|
534
|
+
Whether or not an error should be logged in case of a failed REST call.
|
|
535
|
+
If False, then only a warning is logged. Defaults to True.
|
|
536
|
+
show_warning (bool, optional):
|
|
537
|
+
Whether or not an warning should be logged in case of a
|
|
538
|
+
failed REST call.
|
|
539
|
+
If False, then only a warning is logged. Defaults to True.
|
|
540
|
+
warning_message (str, optional):
|
|
541
|
+
Specific warning message. Defaults to "". If not given the error_message will be used.
|
|
542
|
+
failure_message (str, optional):
|
|
543
|
+
Specific error message. Defaults to "".
|
|
544
|
+
success_message (str, optional):
|
|
545
|
+
Specific success message. Defaults to "".
|
|
546
|
+
max_retries (int, optional):
|
|
547
|
+
How many retries on Connection errors? Default is REQUEST_MAX_RETRIES.
|
|
548
|
+
retry_forever (bool, optional):
|
|
549
|
+
Eventually wait forever - without timeout. Defaults to False.
|
|
550
|
+
parse_request_response (bool, optional):
|
|
551
|
+
Defines if the response.text should be interpreted as json and loaded into a dictionary.
|
|
552
|
+
True is the default.
|
|
553
|
+
|
|
554
|
+
Returns:
|
|
555
|
+
dict | None:
|
|
556
|
+
Response of OTDS REST API or None in case of an error.
|
|
557
|
+
|
|
558
|
+
"""
|
|
559
|
+
|
|
560
|
+
if headers is None:
|
|
561
|
+
headers = REQUEST_HEADERS
|
|
562
|
+
|
|
563
|
+
# In case of an expired session we reauthenticate and
|
|
564
|
+
# try 1 more time. Session expiration should not happen
|
|
565
|
+
# twice in a row:
|
|
566
|
+
retries = 0
|
|
567
|
+
|
|
568
|
+
while True:
|
|
569
|
+
try:
|
|
570
|
+
response = requests.request(
|
|
571
|
+
method=method,
|
|
572
|
+
url=url,
|
|
573
|
+
data=data,
|
|
574
|
+
json=json_data,
|
|
575
|
+
files=files,
|
|
576
|
+
headers=headers,
|
|
577
|
+
timeout=timeout,
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
if response.ok:
|
|
581
|
+
if success_message:
|
|
582
|
+
self.logger.info(success_message)
|
|
583
|
+
if parse_request_response:
|
|
584
|
+
return self.parse_request_response(response)
|
|
585
|
+
else:
|
|
586
|
+
return response
|
|
587
|
+
else:
|
|
588
|
+
# Handle plain HTML responses to not pollute the logs
|
|
589
|
+
content_type = response.headers.get("content-type", None)
|
|
590
|
+
response_text = (
|
|
591
|
+
"HTML content (only printed in debug log)" if content_type == "text/html" else response.text
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
if show_error:
|
|
595
|
+
self.logger.error(
|
|
596
|
+
"%s; status -> %s/%s; error -> %s",
|
|
597
|
+
failure_message,
|
|
598
|
+
response.status_code,
|
|
599
|
+
HTTPStatus(response.status_code).phrase,
|
|
600
|
+
response_text,
|
|
601
|
+
)
|
|
602
|
+
elif show_warning:
|
|
603
|
+
self.logger.warning(
|
|
604
|
+
"%s; status -> %s/%s; warning -> %s",
|
|
605
|
+
warning_message if warning_message else failure_message,
|
|
606
|
+
response.status_code,
|
|
607
|
+
HTTPStatus(response.status_code).phrase,
|
|
608
|
+
response_text,
|
|
609
|
+
)
|
|
610
|
+
if content_type == "text/html":
|
|
611
|
+
self.logger.debug(
|
|
612
|
+
"%s; status -> %s/%s; warning -> %s",
|
|
613
|
+
failure_message,
|
|
614
|
+
response.status_code,
|
|
615
|
+
HTTPStatus(response.status_code).phrase,
|
|
616
|
+
response.text,
|
|
617
|
+
)
|
|
618
|
+
return None
|
|
619
|
+
except requests.exceptions.Timeout:
|
|
620
|
+
if retries <= max_retries:
|
|
621
|
+
self.logger.warning(
|
|
622
|
+
"Request timed out. Retrying in %s seconds...",
|
|
623
|
+
str(REQUEST_RETRY_DELAY),
|
|
624
|
+
)
|
|
625
|
+
retries += 1
|
|
626
|
+
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
627
|
+
else:
|
|
628
|
+
self.logger.error(
|
|
629
|
+
"%s; timeout error.",
|
|
630
|
+
failure_message,
|
|
631
|
+
)
|
|
632
|
+
if retry_forever:
|
|
633
|
+
# If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
|
|
634
|
+
self.logger.warning("Turn timeouts off and wait forever...")
|
|
635
|
+
timeout = None
|
|
636
|
+
else:
|
|
637
|
+
return None
|
|
638
|
+
except requests.exceptions.ConnectionError:
|
|
639
|
+
if retries <= max_retries:
|
|
640
|
+
self.logger.warning(
|
|
641
|
+
"Connection error. Retrying in %s seconds...",
|
|
642
|
+
str(REQUEST_RETRY_DELAY),
|
|
643
|
+
)
|
|
644
|
+
retries += 1
|
|
645
|
+
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
646
|
+
else:
|
|
647
|
+
self.logger.error(
|
|
648
|
+
"%s; connection error.",
|
|
649
|
+
failure_message,
|
|
650
|
+
)
|
|
651
|
+
if retry_forever:
|
|
652
|
+
# If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
|
|
653
|
+
self.logger.warning("Turn timeouts off and wait forever...")
|
|
654
|
+
timeout = None
|
|
655
|
+
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
656
|
+
else:
|
|
657
|
+
return None
|
|
658
|
+
# end try
|
|
659
|
+
self.logger.info(
|
|
660
|
+
"Retrying REST API %s call -> %s... (retry = %s",
|
|
661
|
+
method,
|
|
662
|
+
url,
|
|
663
|
+
str(retries),
|
|
664
|
+
)
|
|
665
|
+
# end while True
|
|
666
|
+
|
|
667
|
+
# end method definition
|
|
668
|
+
|
|
669
|
+
def generate_document(self, payload: str) -> dict | None:
|
|
670
|
+
"""Generate a PowerDocs document based on the provided XML payload.
|
|
671
|
+
|
|
672
|
+
Args:
|
|
673
|
+
payload (str):
|
|
674
|
+
The XML payload to generate the document.
|
|
675
|
+
|
|
676
|
+
Returns:
|
|
677
|
+
dict | None:
|
|
678
|
+
The request response or None in case of an error.
|
|
679
|
+
|
|
680
|
+
"""
|
|
681
|
+
|
|
682
|
+
if not payload:
|
|
683
|
+
self.logger.error("Cannot generate PowerDocs document from empty payload!")
|
|
684
|
+
return None
|
|
685
|
+
|
|
686
|
+
url = self.config()["baseUrl"] + "/c4ApplicationServer/rest/document"
|
|
687
|
+
|
|
688
|
+
body = {"documentgeneration": payload}
|
|
689
|
+
|
|
690
|
+
response = self.do_request(
|
|
691
|
+
url=url,
|
|
692
|
+
method="POST",
|
|
693
|
+
headers=REQUEST_FORM_HEADERS,
|
|
694
|
+
data=body,
|
|
695
|
+
show_error=True,
|
|
696
|
+
failure_message="Failed to generate PowerDocs document",
|
|
697
|
+
parse_request_response=False,
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
return response
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyxecm
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: A Python library to interact with Opentext Content Management Rest API
|
|
5
5
|
Project-URL: Homepage, https://github.com/opentext/pyxecm
|
|
6
6
|
Author-email: Kai Gatzweiler <kgatzweiler@opentext.com>, "Dr. Marc Diefenbruch" <mdiefenb@opentext.com>
|
|
@@ -37,6 +37,7 @@ Requires-Dist: python-multipart>=0.0.20; extra == 'api'
|
|
|
37
37
|
Requires-Dist: uvicorn>=0.35.0; extra == 'api'
|
|
38
38
|
Provides-Extra: customizer
|
|
39
39
|
Requires-Dist: kubernetes>=33.1.0; extra == 'customizer'
|
|
40
|
+
Requires-Dist: openpyxl>=3.1.5; extra == 'customizer'
|
|
40
41
|
Requires-Dist: playwright>=1.53.0; extra == 'customizer'
|
|
41
42
|
Requires-Dist: pydantic>=2.11.7; extra == 'customizer'
|
|
42
43
|
Requires-Dist: python-hcl2>=7.2.1; extra == 'customizer'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
pyxecm/__init__.py,sha256=KNvTFbDVHylf8Ub28osm5Dw0W-ck-94y27lIBuE32RE,441
|
|
2
|
+
pyxecm/avts.py,sha256=NEd1JdJCVmNohp_A-ZxAIMQZX5NCJFMhyKV6cdLFgTw,56960
|
|
3
|
+
pyxecm/coreshare.py,sha256=oz5SASlOC_e4-OIazFUrIA7gB6DfpC7RY4Ck7AHKcvQ,95999
|
|
4
|
+
pyxecm/otac.py,sha256=itsxIkIhIHdAiRCLRegmxCejE3kqpWxgwaJvAGNqzzg,22849
|
|
5
|
+
pyxecm/otawp.py,sha256=9kQghTIrnHP5I_GOmnAlvPhJk433b0dcdVzQHx0fSAM,112962
|
|
6
|
+
pyxecm/otca.py,sha256=8rBAnLGNcEK9UAdRz6bSzDqe5Smvvp0lLl8oaV7yQbE,99352
|
|
7
|
+
pyxecm/otcs.py,sha256=GIXA1BIV8oTZEO3-30MG0eG0TQLNtuvjAzpNmBa2JCE,815063
|
|
8
|
+
pyxecm/otds.py,sha256=gTyHwCSFVJbEia3h-xcPY0UL1fS58VxuI0l9uA3lC6c,191581
|
|
9
|
+
pyxecm/otiv.py,sha256=I5lt4sz7TN3W7BCstCKQY2WQnei-t0tXdM4QjRQRmWI,2358
|
|
10
|
+
pyxecm/otkd.py,sha256=3c37FwQ-KDBN48O1wZVxX46BiQDRtb2-KrXZ7HG54Fg,47488
|
|
11
|
+
pyxecm/otmm.py,sha256=MC4roK8SNG3RPj7Nb-iwn8siH9CLLmhwTmw-84i6zm4,80733
|
|
12
|
+
pyxecm/otpd.py,sha256=MXtgaRMEgVXBbc6hPm9tXq--NpzYAkSMnaL_p2H4b7E,23875
|
|
13
|
+
pyxecm/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
pyxecm/helper/__init__.py,sha256=B35HdIZC9wZ1m_sx4NOPggyFFJoXmFuA1T2tuPDU1W8,246
|
|
15
|
+
pyxecm/helper/assoc.py,sha256=yOh4GFZEkTfIaVVrHBr4bhMtIv-E76oDVWGqaUdVqyA,7321
|
|
16
|
+
pyxecm/helper/data.py,sha256=L92y9dagzJLwdfZW-ISUemkJEuGFo8kGz3r18c01GPc,123363
|
|
17
|
+
pyxecm/helper/logadapter.py,sha256=ExrIKpA2JKegkTIky0wDDTgPYSvVmwQLrDh5jko_6hQ,724
|
|
18
|
+
pyxecm/helper/otel_config.py,sha256=nMzNi3Jv2_kmYG4thzDpN95bqjy6MbRfV6nlpIZ6SjQ,907
|
|
19
|
+
pyxecm/helper/web.py,sha256=YqR72jWSeg3dOEdhN6b09s-kSnHbTjDIl56QC5NvNtE,13386
|
|
20
|
+
pyxecm/helper/xml.py,sha256=6FJ-ApiJmBBo6IwtnWj93DVB016ZTSlQIMXQNvFumOI,47091
|
|
21
|
+
pyxecm_api/__init__.py,sha256=8oXxEEFSu2afpyQURpxMA2qTZAB3MUdbBrndogDn5Oc,92
|
|
22
|
+
pyxecm_api/__main__.py,sha256=Q2tcaoSExPMUwGVBrE4AHT8DNvB4XIgwoN4EPDx5Rt8,117
|
|
23
|
+
pyxecm_api/app.py,sha256=OkBipbCPeDM8KO-LvehYKdSyXcXvVHSwz4vXx8CZdZY,7256
|
|
24
|
+
pyxecm_api/settings.py,sha256=Zu4LnBsCUm9bi7riE_uP2JynWkSmUjJtGrLmSZQXpRg,5535
|
|
25
|
+
pyxecm_api/auth/__init__.py,sha256=ranS8DEliiC4Mlo-bVva9Maj5q08I0I6NJflUFIvOvw,19
|
|
26
|
+
pyxecm_api/auth/functions.py,sha256=hdu4XPS975r8LsbH_3OKNQOEMvnbD40zhRh1nO1hIyQ,3331
|
|
27
|
+
pyxecm_api/auth/models.py,sha256=lKebaIHbALZ10quCCKQ3wf7w8V6k84tFXcPV1zbQsS0,271
|
|
28
|
+
pyxecm_api/auth/router.py,sha256=H58owZMM9lcskUITWSJPZYQr6IM66MyV7h9G36HPpQM,2140
|
|
29
|
+
pyxecm_api/common/__init__.py,sha256=ranS8DEliiC4Mlo-bVva9Maj5q08I0I6NJflUFIvOvw,19
|
|
30
|
+
pyxecm_api/common/functions.py,sha256=-WpWLKkiHzv2WmR3zIBrF2Z1ADcDlC5ifJWLyG7cu-s,8963
|
|
31
|
+
pyxecm_api/common/metrics.py,sha256=kOJ1DZveZJ7xFd1pB12Zbkq6Z-evaTivpgO_ujVbsxM,2707
|
|
32
|
+
pyxecm_api/common/models.py,sha256=c76ysWUt40A875DirsFMXttxwjHvBYvjuOVEXePSZ9k,456
|
|
33
|
+
pyxecm_api/common/router.py,sha256=BXi3SMvkswCIftoVkJIP_Wx8gd3WKJsE3rq6Pult50I,3482
|
|
34
|
+
pyxecm_api/terminal/__init__.py,sha256=RHlTzdGeOY0_dvvNZS_wq6uJcY1OatIUHwCxAUwklaE,43
|
|
35
|
+
pyxecm_api/terminal/router.py,sha256=cYL93inAB9qux-IFg-TpZjdRHWF_OSkbABlXyG69ukc,3582
|
|
36
|
+
pyxecm_api/v1_csai/__init__.py,sha256=ranS8DEliiC4Mlo-bVva9Maj5q08I0I6NJflUFIvOvw,19
|
|
37
|
+
pyxecm_api/v1_csai/models.py,sha256=c0VEJP09jsTW83dpHtZnooNvg3SZNuyMHEBCgWQDJ1s,489
|
|
38
|
+
pyxecm_api/v1_csai/router.py,sha256=5MuzlVzUTEjgBTE2yGtvplt2jekxS4zcl_lqUcz3LVU,5198
|
|
39
|
+
pyxecm_api/v1_csai/statics/bindings/utils.js,sha256=MRPHMxfDDJnqr7x4KRYWDOfSMYOhSGFdoElmQ-lWDLA,6311
|
|
40
|
+
pyxecm_api/v1_csai/statics/tom-select/tom-select.complete.min.js,sha256=f2dQEyWhXp7M5o3MsmgS6zJ_Gq4pXFxSxSTsYrPxPc0,44776
|
|
41
|
+
pyxecm_api/v1_csai/statics/tom-select/tom-select.css,sha256=JgqUGftl29aF9fEJ-ObePYuXmhVAUK-Tp2GiLTTt54Q,9328
|
|
42
|
+
pyxecm_api/v1_csai/statics/vis-9.1.2/vis-network.css,sha256=LoLURa1YeOqIFlJHDOYyYB-PVfG5nm6-zf-GFGAObQ4,220163
|
|
43
|
+
pyxecm_api/v1_csai/statics/vis-9.1.2/vis-network.min.js,sha256=HyDwc28yy5vt-PY4OyXP6i-Dnhq-gNboBAtNW-o3jGk,468813
|
|
44
|
+
pyxecm_api/v1_maintenance/__init__.py,sha256=ranS8DEliiC4Mlo-bVva9Maj5q08I0I6NJflUFIvOvw,19
|
|
45
|
+
pyxecm_api/v1_maintenance/functions.py,sha256=NDU08aHzPi7KXxKMA4KPHwc-LkpiqqwZU7Wif8yjaJk,3001
|
|
46
|
+
pyxecm_api/v1_maintenance/models.py,sha256=HcrhBg9hhRZg4Y6xuus9T8SCNIsL8ZxX1uuaRrBnFBw,271
|
|
47
|
+
pyxecm_api/v1_maintenance/router.py,sha256=gL_f_-9Slq7yzzOO1uS1aB8N3GduKnm1__7b6cSH7VI,2238
|
|
48
|
+
pyxecm_api/v1_otcs/__init__.py,sha256=ranS8DEliiC4Mlo-bVva9Maj5q08I0I6NJflUFIvOvw,19
|
|
49
|
+
pyxecm_api/v1_otcs/functions.py,sha256=YKC4b6nVtlnBGcu2WqSRLmS3faXagkAokrBMXUblkJE,2012
|
|
50
|
+
pyxecm_api/v1_otcs/router.py,sha256=VCtGmObA2TVJREwx4mA047SzSpsJlfxhRXA6DdlppZw,7055
|
|
51
|
+
pyxecm_api/v1_payload/__init__.py,sha256=ranS8DEliiC4Mlo-bVva9Maj5q08I0I6NJflUFIvOvw,19
|
|
52
|
+
pyxecm_api/v1_payload/functions.py,sha256=xA06ACS4NWUut0FXfrw6Ww-R94y43PVSESyEiZEhKAA,6295
|
|
53
|
+
pyxecm_api/v1_payload/models.py,sha256=eD9A2K23L_cGhBDTO1FGVGJMQ1COaYWmcr-ELE66tOA,1006
|
|
54
|
+
pyxecm_api/v1_payload/router.py,sha256=2twiLBeNNDGIEQ6SCZwLFgd8oYOzgbskS-Q3OL-lKe4,15441
|
|
55
|
+
pyxecm_customizer/__init__.py,sha256=x2NhDlNcubRC-jXzqT02j9kQGXBo36QAehjmcQuSbXw,721
|
|
56
|
+
pyxecm_customizer/__main__.py,sha256=QGQlJJAdLmJccArwPT8XEhBOMSJ-Z8gwLrtHPNfL8Ps,1407
|
|
57
|
+
pyxecm_customizer/browser_automation.py,sha256=q1305oZ3a_JI8fLpc0u0T5D_8YSFW0C8-LQpOY0pwXc,69540
|
|
58
|
+
pyxecm_customizer/customizer.py,sha256=Nzz3wndPp9r5GVpOzLtdNUOuIsCZ2GYdIS1HhWdboBM,84938
|
|
59
|
+
pyxecm_customizer/exceptions.py,sha256=YXX0in-UGXfJb6Fei01JQetOtAHqUiITb49OTSaZRkE,909
|
|
60
|
+
pyxecm_customizer/guidewire.py,sha256=1smNNDW-9FdrpqVu0r74KqgEqtq9M7LgpopUJvRSLrE,67049
|
|
61
|
+
pyxecm_customizer/k8s.py,sha256=DcxLKKuvV3S4DYqP4jUygn32aeGtD0c1FOXumZzqqdY,55837
|
|
62
|
+
pyxecm_customizer/knowledge_graph.py,sha256=9Yu-Y7Co7A54qEayRT9e0SKYHlMfDmDVAH12k5gSf3A,46469
|
|
63
|
+
pyxecm_customizer/log.py,sha256=2DmGF3b-ZIOAJCPSmZmxGD7BNxY4-mZm0H_X0HeJedE,916
|
|
64
|
+
pyxecm_customizer/m365.py,sha256=xQGdY9ti44e93c5tPbgCHjvrM-SjQr2F1iApJMb0-Pk,213957
|
|
65
|
+
pyxecm_customizer/payload.py,sha256=JKye3d-ac-Z6IFInFPh50AnI47mREGHZhYdLeyQH8qM,1365927
|
|
66
|
+
pyxecm_customizer/payload_list.py,sha256=MCpCzarmQ-5u7FSW7djNOMSjv373Ltx-9rEDIuhEboI,28266
|
|
67
|
+
pyxecm_customizer/salesforce.py,sha256=lGkQcEYg5YIWc7SF2TELT6yfgrn4pnbCrf8wXGk-PMc,64557
|
|
68
|
+
pyxecm_customizer/sap.py,sha256=lD_riOZhYjbZ0_pUZyqhxP6guzBM__TcUjZhSgDowoE,6506
|
|
69
|
+
pyxecm_customizer/servicenow.py,sha256=K26DQiXd-SMMyft9CLCKtw_vb3oKf6VGdTEzm7XMqYI,66292
|
|
70
|
+
pyxecm_customizer/settings.py,sha256=SPm6sBFiMMuFquNwKBnkUcqPZLtVBQ5K6CGjsLJNaOc,21409
|
|
71
|
+
pyxecm_customizer/successfactors.py,sha256=CcWGXwYcqp4jJ805XQZfY50iXcCEiJg6uVUq5AjRqXs,38661
|
|
72
|
+
pyxecm_customizer/translate.py,sha256=TViU9Erp4lXzZi2jQSmBpjVWS0kIW-I_Y5C0z25z-tQ,4960
|
|
73
|
+
pyxecm_maintenance_page/__init__.py,sha256=09to4a8rygOIN6Z1SCN9tLtW1qPUC78Z-scDbpt0E-Q,136
|
|
74
|
+
pyxecm_maintenance_page/__main__.py,sha256=N_0tw2upUPQZhTYCaIr75LogyaEsp-mlZCon-lIyaxM,158
|
|
75
|
+
pyxecm_maintenance_page/app.py,sha256=pTOeZfgPPq6BT7P8naUjW-ZT9dXqwX6DWazIVL-9Fkc,1997
|
|
76
|
+
pyxecm_maintenance_page/settings.py,sha256=VRReZeNdza7i7lgnQ3wVojzoPDGXZnzr5rsMJY1EnHk,955
|
|
77
|
+
pyxecm_maintenance_page/static/favicon.avif,sha256=POuuPXKbjHVP3BjNLpFIx8MfkQg5z2LZA7sK6lejARg,1543
|
|
78
|
+
pyxecm_maintenance_page/templates/maintenance.html,sha256=0OAinv7jmj3Aa7GNCIoBLDGEMW1-_HdJfwWmkmb6Cs4,5581
|
|
79
|
+
pyxecm-3.1.0.dist-info/METADATA,sha256=C6gl_je1-QeK7NROKoR0Sm_hk4pQXPuXabc6is81GYA,4566
|
|
80
|
+
pyxecm-3.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
81
|
+
pyxecm-3.1.0.dist-info/entry_points.txt,sha256=prc1mDdpd3bQk98VRBozI363mDUgSwDibDKXGNqKqgI,151
|
|
82
|
+
pyxecm-3.1.0.dist-info/RECORD,,
|
pyxecm_api/app.py
CHANGED
|
@@ -8,7 +8,6 @@ __email__ = "mdiefenb@opentext.com"
|
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
10
|
import os
|
|
11
|
-
import threading
|
|
12
11
|
from collections.abc import AsyncGenerator
|
|
13
12
|
from contextlib import asynccontextmanager
|
|
14
13
|
from datetime import UTC, datetime
|
|
@@ -23,9 +22,6 @@ from prometheus_fastapi_instrumentator import Instrumentator
|
|
|
23
22
|
from pyxecm.helper.otel_config import tracer
|
|
24
23
|
from pyxecm_maintenance_page import run_maintenance_page
|
|
25
24
|
|
|
26
|
-
from .agents.app import agent_routers
|
|
27
|
-
from .agents.functions import register_all
|
|
28
|
-
from .agents.otcm_knowledgegraph.functions import build_graph
|
|
29
25
|
from .auth.router import router as auth_router
|
|
30
26
|
from .common.functions import PAYLOAD_LIST
|
|
31
27
|
from .common.metrics import payload_logs_by_payload, payload_logs_total
|
|
@@ -50,31 +46,20 @@ if os.path.isfile(os.path.join(api_settings.logfolder, api_settings.logfile)):
|
|
|
50
46
|
elif not os.path.exists(api_settings.logfolder):
|
|
51
47
|
os.makedirs(api_settings.logfolder)
|
|
52
48
|
|
|
53
|
-
handlers = [logging.FileHandler(os.path.join(api_settings.logfolder, api_settings.logfile))]
|
|
54
|
-
if api_settings.log_payload_processing:
|
|
55
|
-
handlers.append(logging.StreamHandler())
|
|
56
|
-
|
|
57
|
-
logging.basicConfig(
|
|
58
|
-
format="%(asctime)s %(levelname)s [%(name)s] [%(threadName)s] %(message)s",
|
|
59
|
-
datefmt="%d-%b-%Y %H:%M:%S",
|
|
60
|
-
level=api_settings.loglevel,
|
|
61
|
-
handlers=handlers,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
49
|
|
|
65
50
|
@asynccontextmanager
|
|
66
51
|
async def lifespan(
|
|
67
52
|
app: FastAPI, # noqa: ARG001
|
|
68
53
|
) -> AsyncGenerator:
|
|
69
|
-
"""Lifespan
|
|
54
|
+
"""Lifespan function for FASTAPI to handle the startup and shutdown process.
|
|
70
55
|
|
|
71
56
|
Args:
|
|
72
57
|
app (FastAPI):
|
|
73
|
-
The application.
|
|
58
|
+
The FastAPI application.
|
|
74
59
|
|
|
75
60
|
"""
|
|
76
61
|
|
|
77
|
-
logger.debug("
|
|
62
|
+
logger.debug("API settings -> %s", api_settings)
|
|
78
63
|
|
|
79
64
|
with tracer.start_as_current_span("import_payloads"):
|
|
80
65
|
if api_settings.import_payload:
|
|
@@ -89,20 +74,18 @@ async def lifespan(
|
|
|
89
74
|
# Optional Payload
|
|
90
75
|
import_payload(payload_dir=api_settings.payload_dir_optional)
|
|
91
76
|
|
|
92
|
-
logger.info("Starting
|
|
77
|
+
logger.info("Starting maintenance page thread...")
|
|
93
78
|
if api_settings.maintenance_page:
|
|
94
79
|
run_maintenance_page()
|
|
95
80
|
|
|
96
|
-
if api_settings.csai_studio_integration:
|
|
97
|
-
logger.info("Registering Content Aviator tools...")
|
|
98
|
-
register_all()
|
|
99
|
-
threading.Thread(name="KnowledgeGraph", target=build_graph).start()
|
|
100
|
-
|
|
101
81
|
yield
|
|
82
|
+
|
|
102
83
|
logger.info("Shutdown")
|
|
103
84
|
PAYLOAD_LIST.stop_payload_processing()
|
|
104
85
|
|
|
105
86
|
|
|
87
|
+
# end function lifespan
|
|
88
|
+
|
|
106
89
|
app = FastAPI(
|
|
107
90
|
docs_url="/api",
|
|
108
91
|
title=api_settings.title,
|
|
@@ -114,7 +97,7 @@ app = FastAPI(
|
|
|
114
97
|
openapi_tags=[
|
|
115
98
|
{
|
|
116
99
|
"name": "auth",
|
|
117
|
-
"description": "Authentication Endpoint - Users are authenticated against
|
|
100
|
+
"description": "Authentication Endpoint - Users are authenticated against OpenText Directory Services",
|
|
118
101
|
},
|
|
119
102
|
{
|
|
120
103
|
"name": "payload",
|
|
@@ -156,8 +139,6 @@ if api_settings.csai:
|
|
|
156
139
|
)
|
|
157
140
|
|
|
158
141
|
app.include_router(router=v1_csai_router)
|
|
159
|
-
for agent_router in agent_routers:
|
|
160
|
-
app.include_router(prefix="/agents", router=agent_router)
|
|
161
142
|
|
|
162
143
|
|
|
163
144
|
## Add Prometheus Instrumentator for /metrics,
|
|
@@ -170,7 +151,7 @@ if api_settings.metrics:
|
|
|
170
151
|
|
|
171
152
|
## Start the API Server
|
|
172
153
|
def run_api() -> None:
|
|
173
|
-
"""Start the
|
|
154
|
+
"""Start the FastAPI Webserver."""
|
|
174
155
|
|
|
175
156
|
# Check if Temp and Log dir exists
|
|
176
157
|
if not os.path.exists(api_settings.temp_dir):
|
|
@@ -183,27 +164,56 @@ def run_api() -> None:
|
|
|
183
164
|
customizer_start_time = datetime.now(UTC).strftime(
|
|
184
165
|
"%Y-%m-%d_%H-%M",
|
|
185
166
|
)
|
|
186
|
-
api_settings.logfile =
|
|
167
|
+
api_settings.logfile = "customizer_{}.log".format(customizer_start_time)
|
|
187
168
|
|
|
188
169
|
# Configure Logging for uvicorn
|
|
189
170
|
log_config = uvicorn.config.LOGGING_CONFIG
|
|
190
171
|
|
|
191
172
|
# Stdout
|
|
192
|
-
log_config["formatters"]["
|
|
173
|
+
log_config["formatters"]["standard"] = {
|
|
193
174
|
"()": "uvicorn.logging.DefaultFormatter",
|
|
194
175
|
"fmt": "%(levelprefix)s [%(name)s] [%(threadName)s] %(message)s",
|
|
195
176
|
"use_colors": True,
|
|
196
177
|
}
|
|
197
|
-
|
|
198
|
-
|
|
178
|
+
|
|
179
|
+
log_config["formatters"]["logfile"] = {
|
|
180
|
+
"()": "uvicorn.logging.DefaultFormatter",
|
|
181
|
+
"fmt": "%(asctime)s %(levelname)s [%(name)s] [%(threadName)s] %(message)s",
|
|
182
|
+
"datefmt": "%d-%b-%Y %H:%M:%S",
|
|
183
|
+
"use_colors": True,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
log_config["formatters"]["accesslog"] = {
|
|
187
|
+
"()": "uvicorn.logging.AccessFormatter",
|
|
188
|
+
"fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',
|
|
189
|
+
"use_colors": False,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
log_config["handlers"]["console"] = {
|
|
193
|
+
"formatter": "standard",
|
|
199
194
|
"class": "logging.StreamHandler",
|
|
200
195
|
"stream": "ext://sys.stdout",
|
|
201
196
|
}
|
|
202
197
|
|
|
203
|
-
log_config["
|
|
204
|
-
"
|
|
198
|
+
log_config["handlers"]["file"] = {
|
|
199
|
+
"formatter": "logfile",
|
|
200
|
+
"class": "logging.FileHandler",
|
|
201
|
+
"filename": os.path.join(api_settings.logfolder, api_settings.logfile),
|
|
202
|
+
"mode": "a",
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
log_config["handlers"]["accesslog"] = {
|
|
206
|
+
"formatter": "accesslog",
|
|
207
|
+
"class": "logging.FileHandler",
|
|
208
|
+
"filename": os.path.join(api_settings.logfolder, "access.log"),
|
|
209
|
+
"mode": "a",
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
log_config["loggers"]["uvicorn.access"]["handlers"] = ["access", "accesslog"]
|
|
213
|
+
|
|
214
|
+
log_config["loggers"]["root"] = {
|
|
205
215
|
"level": api_settings.loglevel,
|
|
206
|
-
"
|
|
216
|
+
"handlers": ["console", "file"],
|
|
207
217
|
}
|
|
208
218
|
|
|
209
219
|
logger.info("Starting processing thread...")
|
pyxecm_api/auth/functions.py
CHANGED
|
@@ -27,8 +27,8 @@ def get_groups(response: dict, token: str) -> list:
|
|
|
27
27
|
"""Get the groups of the user.
|
|
28
28
|
|
|
29
29
|
Args:
|
|
30
|
-
response (
|
|
31
|
-
token (
|
|
30
|
+
response (dict): _description_
|
|
31
|
+
token (str): _description_
|
|
32
32
|
|
|
33
33
|
Returns:
|
|
34
34
|
list: _description_
|
pyxecm_api/auth/router.py
CHANGED
|
@@ -64,9 +64,8 @@ async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]) -> J
|
|
|
64
64
|
async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]) -> JSONResponse:
|
|
65
65
|
"""Get the current user.
|
|
66
66
|
|
|
67
|
-
current_user:
|
|
68
|
-
|
|
69
|
-
description: The current user.
|
|
67
|
+
current_user (User):
|
|
68
|
+
The current user.
|
|
70
69
|
|
|
71
70
|
"""
|
|
72
71
|
|