pyxecm 3.4.6__tar.gz → 3.4.8__tar.gz

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.
Files changed (72) hide show
  1. {pyxecm-3.4.6 → pyxecm-3.4.8}/PKG-INFO +1 -1
  2. {pyxecm-3.4.6 → pyxecm-3.4.8}/pyproject.toml +1 -1
  3. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otcs.py +23 -4
  4. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otds.py +94 -0
  5. {pyxecm-3.4.6 → pyxecm-3.4.8}/.gitignore +0 -0
  6. {pyxecm-3.4.6 → pyxecm-3.4.8}/README.md +0 -0
  7. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/__init__.py +0 -0
  8. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/avts.py +0 -0
  9. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/coreshare.py +0 -0
  10. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/helper/__init__.py +0 -0
  11. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/helper/assoc.py +0 -0
  12. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/helper/data.py +0 -0
  13. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/helper/logadapter.py +0 -0
  14. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/helper/web.py +0 -0
  15. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/helper/xml.py +0 -0
  16. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otac.py +0 -0
  17. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otawp.py +0 -0
  18. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otca.py +0 -0
  19. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otiv.py +0 -0
  20. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otkd.py +0 -0
  21. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otmm.py +0 -0
  22. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/otpd.py +0 -0
  23. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm/py.typed +0 -0
  24. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/__init__.py +0 -0
  25. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/__main__.py +0 -0
  26. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/app.py +0 -0
  27. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/auth/__init__.py +0 -0
  28. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/auth/functions.py +0 -0
  29. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/auth/models.py +0 -0
  30. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/auth/router.py +0 -0
  31. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/common/__init__.py +0 -0
  32. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/common/functions.py +0 -0
  33. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/common/metrics.py +0 -0
  34. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/common/models.py +0 -0
  35. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/common/router.py +0 -0
  36. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/settings.py +0 -0
  37. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/terminal/__init__.py +0 -0
  38. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/terminal/router.py +0 -0
  39. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_maintenance/__init__.py +0 -0
  40. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_maintenance/functions.py +0 -0
  41. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_maintenance/models.py +0 -0
  42. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_maintenance/router.py +0 -0
  43. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_otcs/__init__.py +0 -0
  44. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_otcs/functions.py +0 -0
  45. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_otcs/router.py +0 -0
  46. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_payload/__init__.py +0 -0
  47. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_payload/functions.py +0 -0
  48. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_payload/models.py +0 -0
  49. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_api/v1_payload/router.py +0 -0
  50. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/__init__.py +0 -0
  51. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/__main__.py +0 -0
  52. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/browser_automation.py +0 -0
  53. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/customizer.py +0 -0
  54. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/exceptions.py +0 -0
  55. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/guidewire.py +0 -0
  56. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/k8s.py +0 -0
  57. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/log.py +0 -0
  58. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/m365.py +0 -0
  59. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/payload.py +0 -0
  60. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/payload_list.py +0 -0
  61. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/salesforce.py +0 -0
  62. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/sap.py +0 -0
  63. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/servicenow.py +0 -0
  64. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/settings.py +0 -0
  65. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/successfactors.py +0 -0
  66. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_customizer/translate.py +0 -0
  67. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_maintenance_page/__init__.py +0 -0
  68. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_maintenance_page/__main__.py +0 -0
  69. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_maintenance_page/app.py +0 -0
  70. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_maintenance_page/settings.py +0 -0
  71. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_maintenance_page/static/favicon.avif +0 -0
  72. {pyxecm-3.4.6 → pyxecm-3.4.8}/src/pyxecm_maintenance_page/templates/maintenance.html +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyxecm
3
- Version: 3.4.6
3
+ Version: 3.4.8
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>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyxecm"
3
- version = "3.4.6"
3
+ version = "3.4.8"
4
4
  description = 'A Python library to interact with Opentext Content Management Rest API'
5
5
  keywords = [
6
6
  'opentext',
@@ -1892,7 +1892,13 @@ class OTCS:
1892
1892
 
1893
1893
  # First do some sanity checks:
1894
1894
  if not response:
1895
- self.logger.debug("Empty response - no results found!")
1895
+ self.logger.debug("Empty REST response. Cannot get result value! Returning None.")
1896
+ return None
1897
+ if "error" in response:
1898
+ self.logger.error(
1899
+ "REST response contains an error -> %s. Cannot get result value! Returning None.",
1900
+ str(response["error"]),
1901
+ )
1896
1902
  return None
1897
1903
 
1898
1904
  # To support also iterators that yield from results,
@@ -1903,7 +1909,7 @@ class OTCS:
1903
1909
 
1904
1910
  if "results" not in response:
1905
1911
  if show_error:
1906
- self.logger.error("No 'results' key in REST response - returning None")
1912
+ self.logger.error("No 'results' key in REST response. Cannot get result value! Returning None.")
1907
1913
  return None
1908
1914
 
1909
1915
  results = response["results"]
@@ -2034,10 +2040,16 @@ class OTCS:
2034
2040
 
2035
2041
  # First do some sanity checks:
2036
2042
  if not response:
2037
- self.logger.debug("Empty REST response - returning None")
2043
+ self.logger.debug("Empty REST response. Cannot get result values! Returning None.")
2044
+ return None
2045
+ if "error" in response:
2046
+ self.logger.error(
2047
+ "REST response contains an error -> %s. Cannot get result values! Returning None.",
2048
+ str(response["error"]),
2049
+ )
2038
2050
  return None
2039
2051
  if "results" not in response:
2040
- self.logger.error("No 'results' key in REST response - returning None")
2052
+ self.logger.error("No 'results' key in REST response. Cannot get result values! Returning None.")
2041
2053
  return None
2042
2054
 
2043
2055
  results = response["results"]
@@ -15032,6 +15044,7 @@ class OTCS:
15032
15044
  external_modify_date: str | None = None,
15033
15045
  external_create_date: str | None = None,
15034
15046
  show_error: bool = True,
15047
+ parse_error_response: bool = False,
15035
15048
  ) -> dict | None:
15036
15049
  """Create a new business workspace.
15037
15050
 
@@ -15076,6 +15089,8 @@ class OTCS:
15076
15089
  If True, log an error if workspace creation fails.
15077
15090
  If False, log a warning instead.
15078
15091
  True is the default.
15092
+ parse_error_response (bool, optional):
15093
+ Whether to parse the request response or not. Defaults to False.
15079
15094
 
15080
15095
  Returns:
15081
15096
  dict | None:
@@ -15202,8 +15217,12 @@ class OTCS:
15202
15217
  ),
15203
15218
  show_error=show_error,
15204
15219
  show_warning=(not show_error),
15220
+ parse_error_response=parse_error_response,
15205
15221
  )
15206
15222
 
15223
+ if "error" in response:
15224
+ return response
15225
+
15207
15226
  node_id = self.get_result_value(response=response, key="id")
15208
15227
  if node_id:
15209
15228
  trace.get_current_span().set_attribute("workspace.id", node_id)
@@ -957,6 +957,100 @@ class OTDS:
957
957
 
958
958
  # end method definition
959
959
 
960
+ @tracer.start_as_current_span(attributes=OTEL_TRACING_ATTRIBUTES, name="authenticate_user_token")
961
+ def authenticate_user_token(
962
+ self,
963
+ username: str,
964
+ password: str,
965
+ scope: str = "otds:roles",
966
+ ) -> str | None:
967
+ """Authenticate a user via the OAuth2 password grant and return a JWT access token.
968
+
969
+ Unlike :meth:`authenticate` with ``grant_type="password"`` (which hits the
970
+ legacy credential endpoint and returns an OTDS SSO ticket), this method posts
971
+ ``grant_type=password`` together with the configured OAuth client credentials to
972
+ the OAuth2 token endpoint (``/otdsws/oauth2/token``). This produces a signed
973
+ JWT access token that can be used as a standard ``Authorization: Bearer`` token.
974
+
975
+ The ``client_id`` and ``client_secret`` must be configured on the OTDS object
976
+ (passed to the constructor) before calling this method.
977
+
978
+ Args:
979
+ username (str):
980
+ The OTDS login name of the user to authenticate.
981
+ password (str):
982
+ The password for the OTDS user.
983
+ scope (str, optional):
984
+ OAuth2 scope string to request. Defaults to ``"otds:roles"``.
985
+
986
+ Returns:
987
+ str | None:
988
+ The JWT access token, or ``None`` if authentication fails.
989
+ The token is also stored in ``self._token``.
990
+
991
+ Example:
992
+ 'eyJraWQiOiJvdGRzLXNpZ25pbmcta2V5IiwiYWxnIjoiUlMyNTYifQ...'
993
+
994
+ """
995
+
996
+ request_url = self.token_url()
997
+
998
+ request_data = {
999
+ "grant_type": "password",
1000
+ "client_id": self.config()["clientId"],
1001
+ "client_secret": self.config()["clientSecret"],
1002
+ "username": username,
1003
+ "password": password,
1004
+ "scope": scope,
1005
+ }
1006
+
1007
+ self.logger.debug(
1008
+ "Requesting OTDS user access token for -> '%s'; calling -> %s",
1009
+ username,
1010
+ request_url,
1011
+ )
1012
+
1013
+ try:
1014
+ response = requests.post(
1015
+ url=request_url,
1016
+ headers=REQUEST_FORM_HEADERS,
1017
+ data=request_data,
1018
+ timeout=REQUEST_TIMEOUT,
1019
+ )
1020
+ except requests.exceptions.RequestException as exception:
1021
+ self.logger.warning(
1022
+ "Unable to connect to OTDS token endpoint -> %s; error -> %s",
1023
+ request_url,
1024
+ str(exception),
1025
+ )
1026
+ return None
1027
+
1028
+ if not response.ok:
1029
+ self.logger.error(
1030
+ "Failed to request user access token for -> '%s'; error -> %s",
1031
+ username,
1032
+ response.text,
1033
+ )
1034
+ return None
1035
+
1036
+ token_dict = self.parse_request_response(response)
1037
+ if not token_dict:
1038
+ return None
1039
+
1040
+ access_token = token_dict.get("access_token")
1041
+ if not access_token:
1042
+ self.logger.error(
1043
+ "OTDS token response for user -> '%s' did not contain an access_token",
1044
+ username,
1045
+ )
1046
+ return None
1047
+
1048
+ self._token = access_token
1049
+ self._cookie = None
1050
+ return self._token
1051
+
1052
+ # end method definition
1053
+
960
1054
  @tracer.start_as_current_span(attributes=OTEL_TRACING_ATTRIBUTES, name="impersonate_user")
961
1055
  def impersonate_user(
962
1056
  self,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes