pyxecm 3.8.2__tar.gz → 3.9.0__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 (88) hide show
  1. {pyxecm-3.8.2 → pyxecm-3.9.0}/PKG-INFO +4 -1
  2. {pyxecm-3.8.2 → pyxecm-3.9.0}/pyproject.toml +3 -1
  3. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otcs.py +32 -7
  4. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/app.py +20 -5
  5. pyxecm-3.9.0/src/pyxecm_api/config/__init__.py +7 -0
  6. pyxecm-3.9.0/src/pyxecm_api/config/functions.py +834 -0
  7. pyxecm-3.9.0/src/pyxecm_api/config/models.py +206 -0
  8. pyxecm-3.9.0/src/pyxecm_api/config/router.py +274 -0
  9. pyxecm-3.9.0/src/pyxecm_api/pods/__init__.py +7 -0
  10. pyxecm-3.9.0/src/pyxecm_api/pods/functions.py +675 -0
  11. pyxecm-3.9.0/src/pyxecm_api/pods/log_spool.py +251 -0
  12. pyxecm-3.9.0/src/pyxecm_api/pods/models.py +124 -0
  13. pyxecm-3.9.0/src/pyxecm_api/pods/router.py +341 -0
  14. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/settings.py +39 -0
  15. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/terminal/router.py +67 -6
  16. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_payload/functions.py +75 -2
  17. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_payload/log_reader.py +29 -12
  18. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_payload/models.py +3 -0
  19. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_payload/router.py +12 -83
  20. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/__main__.py +3 -2
  21. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/guidewire.py +1 -3
  22. pyxecm-3.9.0/src/pyxecm_customizer/log.py +153 -0
  23. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/payload_list.py +3 -3
  24. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/sap.py +4806 -738
  25. pyxecm-3.9.0/src/pyxecm_customizer/sap_forms.py +1471 -0
  26. pyxecm-3.9.0/src/pyxecm_customizer/sap_models.py +14079 -0
  27. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/settings.py +4 -2
  28. pyxecm-3.8.2/src/pyxecm_customizer/log.py +0 -45
  29. pyxecm-3.8.2/src/pyxecm_customizer/sap_models.py +0 -7266
  30. {pyxecm-3.8.2 → pyxecm-3.9.0}/.gitignore +0 -0
  31. {pyxecm-3.8.2 → pyxecm-3.9.0}/README.md +0 -0
  32. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/__init__.py +0 -0
  33. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/avts.py +0 -0
  34. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/coreshare.py +0 -0
  35. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/helper/__init__.py +0 -0
  36. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/helper/assoc.py +0 -0
  37. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/helper/data.py +0 -0
  38. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/helper/logadapter.py +0 -0
  39. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/helper/web.py +0 -0
  40. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/helper/xml.py +0 -0
  41. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otac.py +0 -0
  42. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otawp.py +0 -0
  43. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otca.py +0 -0
  44. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otds.py +0 -0
  45. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otiv.py +0 -0
  46. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otkd.py +0 -0
  47. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otmm.py +0 -0
  48. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/otpd.py +0 -0
  49. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm/py.typed +0 -0
  50. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/__init__.py +0 -0
  51. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/__main__.py +0 -0
  52. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/auth/__init__.py +0 -0
  53. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/auth/functions.py +0 -0
  54. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/auth/models.py +0 -0
  55. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/auth/router.py +0 -0
  56. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/common/__init__.py +0 -0
  57. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/common/functions.py +0 -0
  58. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/common/metrics.py +0 -0
  59. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/common/models.py +0 -0
  60. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/common/router.py +0 -0
  61. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/terminal/__init__.py +0 -0
  62. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_maintenance/__init__.py +0 -0
  63. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_maintenance/functions.py +0 -0
  64. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_maintenance/models.py +0 -0
  65. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_maintenance/router.py +0 -0
  66. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_otcs/__init__.py +0 -0
  67. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_otcs/functions.py +0 -0
  68. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_otcs/router.py +0 -0
  69. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_api/v1_payload/__init__.py +0 -0
  70. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/__init__.py +0 -0
  71. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/browser_automation.py +0 -0
  72. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/customizer.py +0 -0
  73. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/exceptions.py +0 -0
  74. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/k8s.py +0 -0
  75. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/m365.py +0 -0
  76. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/manager_push.py +0 -0
  77. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/payload.py +0 -0
  78. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/salesforce.py +0 -0
  79. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/servicenow.py +0 -0
  80. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/successfactors.py +0 -0
  81. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/translate.py +0 -0
  82. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_customizer/version.py +0 -0
  83. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_maintenance_page/__init__.py +0 -0
  84. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_maintenance_page/__main__.py +0 -0
  85. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_maintenance_page/app.py +0 -0
  86. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_maintenance_page/settings.py +0 -0
  87. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_maintenance_page/static/favicon.avif +0 -0
  88. {pyxecm-3.8.2 → pyxecm-3.9.0}/src/pyxecm_maintenance_page/templates/maintenance.html +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyxecm
3
- Version: 3.8.2
3
+ Version: 3.9.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>
@@ -27,6 +27,7 @@ Requires-Dist: xmltodict>=0.14.2
27
27
  Requires-Dist: zeep>=4.2.0
28
28
  Provides-Extra: api
29
29
  Requires-Dist: asyncio>=3.4.3; extra == 'api'
30
+ Requires-Dist: cryptography>=44.0.0; extra == 'api'
30
31
  Requires-Dist: fastapi>=0.116.0; extra == 'api'
31
32
  Requires-Dist: jinja2>=3.1.6; extra == 'api'
32
33
  Requires-Dist: opentelemetry-api>=1.34.1; extra == 'api'
@@ -42,6 +43,8 @@ Requires-Dist: openpyxl>=3.1.5; extra == 'customizer'
42
43
  Requires-Dist: playwright>=1.53.0; extra == 'customizer'
43
44
  Requires-Dist: pydantic>=2.12.0; extra == 'customizer'
44
45
  Requires-Dist: python-hcl2==7.3.1; extra == 'customizer'
46
+ Provides-Extra: forms
47
+ Requires-Dist: reportlab>=4.0; extra == 'forms'
45
48
  Provides-Extra: magic
46
49
  Requires-Dist: python-magic; extra == 'magic'
47
50
  Provides-Extra: saml
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyxecm"
3
- version = "3.8.2"
3
+ version = "3.9.0"
4
4
  description = 'A Python library to interact with Opentext Content Management Rest API'
5
5
  keywords = [
6
6
  'opentext',
@@ -44,6 +44,7 @@ classifiers = [
44
44
  magic = ['python-magic']
45
45
  sap = ['pyrfc==3.3.1']
46
46
  saml = ['signxml>=5.1.0']
47
+ forms = ['reportlab>=4.0']
47
48
  customizer = [
48
49
  "kubernetes>=33.1.0",
49
50
  "playwright>=1.53.0",
@@ -53,6 +54,7 @@ customizer = [
53
54
  ]
54
55
  api = [
55
56
  "asyncio>=3.4.3",
57
+ "cryptography>=44.0.0",
56
58
  "fastapi>=0.116.0",
57
59
  "jinja2>=3.1.6",
58
60
  "opentelemetry-api>=1.34.1",
@@ -9333,7 +9333,8 @@ class OTCS:
9333
9333
 
9334
9334
  elif os.path.exists(path_or_url):
9335
9335
  self.logger.debug("Uploading local file -> '%s'", path_or_url)
9336
- file_content = open(file=path_or_url, mode="rb") # noqa: SIM115
9336
+ with open(file=path_or_url, mode="rb") as local_file:
9337
+ file_content = local_file.read()
9337
9338
 
9338
9339
  else:
9339
9340
  self.logger.warning("Cannot access file -> '%s'", path_or_url)
@@ -9502,14 +9503,15 @@ class OTCS:
9502
9503
  If True, automatically extract ZIP files and upload extracted directory. If False,
9503
9504
  upload the unchanged Zip file.
9504
9505
  replace_existing (bool, optional):
9505
- If True, replaces an existing file with the same name in the target folder. If False,
9506
- the upload will fail if a file with the same name already exists.
9506
+ If True, an existing document with the same name in the target folder gets the file
9507
+ as a new version. If False, the upload will fail if a file with the same name already exists.
9507
9508
  show_error (bool, optional):
9508
9509
  If True, treats the upload failure as an error. If False, no error is shown (useful if the file already exists).
9509
9510
 
9510
9511
  Returns:
9511
9512
  dict | None:
9512
- The response from the upload operation or None if the upload fails.
9513
+ The response from the upload operation (or from add_document_version() if a new
9514
+ version of an existing document has been added) or None if the upload fails.
9513
9515
 
9514
9516
  """
9515
9517
 
@@ -9604,7 +9606,8 @@ class OTCS:
9604
9606
 
9605
9607
  elif os.path.exists(file_url):
9606
9608
  self.logger.debug("Uploading local file -> %s", file_url)
9607
- file_content = open(file=file_url, mode="rb") # noqa: SIM115
9609
+ with open(file=file_url, mode="rb") as local_file:
9610
+ file_content = local_file.read()
9608
9611
 
9609
9612
  else:
9610
9613
  self.logger.warning("Cannot access file -> '%s'", file_url)
@@ -9652,6 +9655,27 @@ class OTCS:
9652
9655
  if not mime_type:
9653
9656
  mime_type = "application/octet-stream" # Default to binary stream if mime type cannot be determined
9654
9657
 
9658
+ # If a document with the same name exists already we add a new version instead
9659
+ # (categories, classifications and external dates only apply to new documents):
9660
+ if replace_existing:
9661
+ response = self.get_node_by_parent_and_name(
9662
+ parent_id=parent_id, name=file_name, fields="properties{id,name}"
9663
+ )
9664
+ existing_document_id = self.get_result_value(response=response, key="id")
9665
+ if existing_document_id:
9666
+ self.logger.debug(
9667
+ "Document -> '%s' does already exist in parent with ID -> %d. Adding a new version...",
9668
+ file_name,
9669
+ parent_id,
9670
+ )
9671
+ return self.add_document_version(
9672
+ node_id=int(existing_document_id),
9673
+ file_name=file_name,
9674
+ mime_type=mime_type,
9675
+ file_content=file_content if isinstance(file_content, bytes) else file_content.read(),
9676
+ description=description,
9677
+ )
9678
+
9655
9679
  upload_post_files = [("file", (f"{file_name}", file_content, mime_type))]
9656
9680
 
9657
9681
  request_url = self.config()["nodesUrlv2"]
@@ -9997,7 +10021,8 @@ class OTCS:
9997
10021
 
9998
10022
  elif os.path.exists(file_url):
9999
10023
  self.logger.debug("Upload local file -> '%s' as new version.", file_url)
10000
- file_content = open(file=file_url, mode="rb") # noqa: SIM115
10024
+ with open(file=file_url, mode="rb") as local_file:
10025
+ file_content = local_file.read()
10001
10026
 
10002
10027
  else:
10003
10028
  self.logger.warning("Cannot access file -> '%s'", file_url)
@@ -10007,7 +10032,7 @@ class OTCS:
10007
10032
  upload_post_data = {"description": description}
10008
10033
 
10009
10034
  if not mime_type:
10010
- mime_type, _ = mimetypes.guess_type(file_url)
10035
+ mime_type, _ = mimetypes.guess_type(file_name)
10011
10036
 
10012
10037
  if not mime_type and magic_installed and file_url:
10013
10038
  try:
@@ -24,6 +24,7 @@ from opentelemetry.sdk.resources import Resource
24
24
  from opentelemetry.sdk.trace import TracerProvider
25
25
  from opentelemetry.sdk.trace.export import BatchSpanProcessor
26
26
  from prometheus_fastapi_instrumentator import Instrumentator
27
+ from pyxecm_customizer.log import LOG_DATE_FORMAT, LOG_FORMAT
27
28
  from pyxecm_customizer.version import customizer_version
28
29
  from pyxecm_maintenance_page import run_maintenance_page
29
30
 
@@ -31,6 +32,9 @@ from .auth.router import router as auth_router
31
32
  from .common.functions import PAYLOAD_LIST
32
33
  from .common.metrics import payload_logs_by_payload, payload_logs_total
33
34
  from .common.router import router as common_router
35
+ from .config.router import router as config_router
36
+ from .pods.router import LOG_SPOOL
37
+ from .pods.router import router as pods_router
34
38
  from .settings import api_settings
35
39
  from .terminal.router import router as terminal_router
36
40
  from .v1_maintenance.router import router as v1_maintenance_router
@@ -95,6 +99,7 @@ async def lifespan(
95
99
 
96
100
  logger.info("Shutdown")
97
101
  PAYLOAD_LIST.stop_payload_processing()
102
+ LOG_SPOOL.close()
98
103
 
99
104
 
100
105
  # end function lifespan
@@ -124,6 +129,11 @@ app = FastAPI(
124
129
  "name": "maintenance",
125
130
  "description": "Enable, disable or alter the maintenance mode.",
126
131
  },
132
+ {
133
+ "name": "pods",
134
+ "description": "List the pods of the namespace, browse, download and upload their files and read their "
135
+ "logs. Only available when pod_access is on (it follows ws_terminal).",
136
+ },
127
137
  ],
128
138
  )
129
139
 
@@ -152,6 +162,10 @@ app.include_router(router=v1_payload_router)
152
162
  if api_settings.ws_terminal:
153
163
  app.include_router(router=terminal_router)
154
164
 
165
+ if api_settings.pod_access:
166
+ app.include_router(router=pods_router)
167
+ app.include_router(router=config_router)
168
+
155
169
  ## Add Prometheus Instrumentator for /metrics,
156
170
  if api_settings.metrics:
157
171
  # Add Prometheus Instrumentator for /metricsf
@@ -183,15 +197,16 @@ def run_api() -> None:
183
197
  # Stdout
184
198
  log_config["formatters"]["standard"] = {
185
199
  "()": "uvicorn.logging.DefaultFormatter",
186
- "fmt": "%(asctime)s %(levelprefix)s [%(name)s] [%(threadName)s] %(message)s",
187
- "datefmt": "%d-%b-%Y %H:%M:%S",
200
+ # The log format with uvicorn's colored level name.
201
+ "fmt": LOG_FORMAT.replace("%(levelname)s", "%(levelprefix)s"),
202
+ "datefmt": LOG_DATE_FORMAT,
188
203
  "use_colors": True,
189
204
  }
190
205
 
191
206
  log_config["formatters"]["logfile"] = {
192
207
  "()": "uvicorn.logging.DefaultFormatter",
193
- "fmt": "%(asctime)s %(levelname)s [%(name)s] [%(threadName)s] %(message)s",
194
- "datefmt": "%d-%b-%Y %H:%M:%S",
208
+ "fmt": LOG_FORMAT,
209
+ "datefmt": LOG_DATE_FORMAT,
195
210
  "use_colors": True,
196
211
  }
197
212
 
@@ -205,7 +220,7 @@ def run_api() -> None:
205
220
  log_config["formatters"]["default"] = {
206
221
  "()": "uvicorn.logging.DefaultFormatter",
207
222
  "fmt": "%(asctime)s %(levelprefix)s %(message)s",
208
- "datefmt": "%d-%b-%Y %H:%M:%S",
223
+ "datefmt": LOG_DATE_FORMAT,
209
224
  "use_colors": False,
210
225
  }
211
226
 
@@ -0,0 +1,7 @@
1
+ """ConfigMaps and Secrets of the namespace: show and change them, and restart what uses them."""
2
+
3
+ __author__ = "Dr. Marc Diefenbruch"
4
+ __copyright__ = "Copyright (C) 2024-2025, OpenText"
5
+ __credits__ = ["Kai-Philip Gatzweiler"]
6
+ __maintainer__ = "Dr. Marc Diefenbruch"
7
+ __email__ = "mdiefenb@opentext.com"