stepxmlclient 1.0.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.
- stepxmlclient/__init__.py +22 -0
- stepxmlclient/client.py +373 -0
- stepxmlclient/creator.py +317 -0
- stepxmlclient/model/__init__.py +418 -0
- stepxmlclient/model/asset.py +250 -0
- stepxmlclient/model/attribute.py +288 -0
- stepxmlclient/model/business.py +233 -0
- stepxmlclient/model/classification.py +409 -0
- stepxmlclient/model/complex_elements.py +260 -0
- stepxmlclient/model/deletion.py +87 -0
- stepxmlclient/model/entity.py +368 -0
- stepxmlclient/model/metadata.py +199 -0
- stepxmlclient/model/organization.py +167 -0
- stepxmlclient/model/product.py +519 -0
- stepxmlclient/model/relations.py +105 -0
- stepxmlclient/model/replacement.py +417 -0
- stepxmlclient/parser.py +2805 -0
- stepxmlclient/rest_client/__init__.py +16 -0
- stepxmlclient/rest_client/base.py +388 -0
- stepxmlclient/rest_client/client.py +127 -0
- stepxmlclient/rest_client/exceptions.py +97 -0
- stepxmlclient/rest_client/models/__init__.py +175 -0
- stepxmlclient/rest_client/models/asset.py +253 -0
- stepxmlclient/rest_client/models/attribute.py +112 -0
- stepxmlclient/rest_client/models/background_process.py +23 -0
- stepxmlclient/rest_client/models/batch.py +41 -0
- stepxmlclient/rest_client/models/classification.py +57 -0
- stepxmlclient/rest_client/models/collection.py +26 -0
- stepxmlclient/rest_client/models/common.py +192 -0
- stepxmlclient/rest_client/models/context.py +16 -0
- stepxmlclient/rest_client/models/data_type_group.py +15 -0
- stepxmlclient/rest_client/models/entity.py +63 -0
- stepxmlclient/rest_client/models/event_processor.py +15 -0
- stepxmlclient/rest_client/models/import_export.py +43 -0
- stepxmlclient/rest_client/models/integration_endpoint.py +16 -0
- stepxmlclient/rest_client/models/product.py +200 -0
- stepxmlclient/rest_client/models/relations.py +280 -0
- stepxmlclient/rest_client/models/system_information.py +11 -0
- stepxmlclient/rest_client/models/user.py +28 -0
- stepxmlclient/rest_client/models/workflow.py +30 -0
- stepxmlclient/rest_client/operations/__init__.py +54 -0
- stepxmlclient/rest_client/operations/assets.py +652 -0
- stepxmlclient/rest_client/operations/attributes.py +252 -0
- stepxmlclient/rest_client/operations/background_processes.py +84 -0
- stepxmlclient/rest_client/operations/batch.py +28 -0
- stepxmlclient/rest_client/operations/classifications.py +248 -0
- stepxmlclient/rest_client/operations/collection_groups.py +46 -0
- stepxmlclient/rest_client/operations/collections.py +67 -0
- stepxmlclient/rest_client/operations/contexts.py +88 -0
- stepxmlclient/rest_client/operations/data_type_groups.py +68 -0
- stepxmlclient/rest_client/operations/entities.py +295 -0
- stepxmlclient/rest_client/operations/event_processors.py +109 -0
- stepxmlclient/rest_client/operations/exports.py +153 -0
- stepxmlclient/rest_client/operations/gateway.py +53 -0
- stepxmlclient/rest_client/operations/inbound.py +472 -0
- stepxmlclient/rest_client/operations/outbound.py +64 -0
- stepxmlclient/rest_client/operations/products.py +489 -0
- stepxmlclient/rest_client/operations/relations.py +349 -0
- stepxmlclient/rest_client/operations/reports.py +27 -0
- stepxmlclient/rest_client/operations/system_information.py +28 -0
- stepxmlclient/rest_client/operations/user_groups.py +79 -0
- stepxmlclient/rest_client/operations/users.py +119 -0
- stepxmlclient/rest_client/operations/workflow_tasks.py +61 -0
- stepxmlclient/rest_client/operations/workflows.py +50 -0
- stepxmlclient/upload.py +293 -0
- stepxmlclient-1.0.0.dist-info/METADATA +666 -0
- stepxmlclient-1.0.0.dist-info/RECORD +70 -0
- stepxmlclient-1.0.0.dist-info/WHEEL +5 -0
- stepxmlclient-1.0.0.dist-info/licenses/LICENSE +21 -0
- stepxmlclient-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Export and Import operations for STEP REST API v2."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
7
|
+
from ..exceptions import NotFoundError, ValidationError
|
|
8
|
+
from ..models.import_export import (
|
|
9
|
+
BackgroundProcessResponse,
|
|
10
|
+
ExportJobCreateRequest,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ExportOperations(BaseOperation):
|
|
15
|
+
"""Operations for STEP data exports and imports."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, client, logger: Optional[logging.Logger] = None,
|
|
18
|
+
context: str | None = None, workspace: str | None = None):
|
|
19
|
+
"""Initialize export operations.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
client: The REST API client
|
|
23
|
+
logger: Optional logger instance
|
|
24
|
+
context: STEP context ID for all API calls
|
|
25
|
+
workspace: STEP workspace ID (defaults to "Main" server-side)
|
|
26
|
+
"""
|
|
27
|
+
super().__init__(client, operation_name="ExportOperations", logger=logger,
|
|
28
|
+
context=context, workspace=workspace)
|
|
29
|
+
|
|
30
|
+
@handle_rest_errors
|
|
31
|
+
def create_export_job(self, export_configuration_id: str,
|
|
32
|
+
data: Optional[ExportJobCreateRequest] = None,
|
|
33
|
+
use_request_context_workspace: Optional[bool] = None) -> BackgroundProcessResponse:
|
|
34
|
+
"""Trigger an export using a pre-configured export configuration (POST /export/{exportConfigurationId}).
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
export_configuration_id: The ID of the export configuration to use (required)
|
|
38
|
+
data: Optional request body with additional export parameters
|
|
39
|
+
use_request_context_workspace: If True, use the workspace from the request context
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
ExportJobResponse with job details
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
ValidationError: If export_configuration_id is missing or data is invalid
|
|
46
|
+
RestApiError: For API errors
|
|
47
|
+
"""
|
|
48
|
+
self._validate_required_params(
|
|
49
|
+
{"export_configuration_id": export_configuration_id},
|
|
50
|
+
["export_configuration_id"]
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if data is not None:
|
|
54
|
+
if hasattr(data, 'model_dump'):
|
|
55
|
+
create_data = data.model_dump(exclude_none=True)
|
|
56
|
+
else:
|
|
57
|
+
create_data = dict(data) if not isinstance(data, dict) else data
|
|
58
|
+
else:
|
|
59
|
+
create_data = None
|
|
60
|
+
|
|
61
|
+
query_params: dict = self._build_context_params()
|
|
62
|
+
if use_request_context_workspace is not None:
|
|
63
|
+
query_params["useRequestContextWorkspace"] = use_request_context_workspace
|
|
64
|
+
|
|
65
|
+
self._log_operation("startExport", {"exportConfigurationId": export_configuration_id})
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
if create_data:
|
|
69
|
+
response = self.client.startExport(exportConfigurationId=export_configuration_id, json=create_data, **query_params)
|
|
70
|
+
else:
|
|
71
|
+
response = self.client.startExport(exportConfigurationId=export_configuration_id, **query_params)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
if "404" in str(e):
|
|
74
|
+
raise NotFoundError(export_configuration_id, "ExportConfiguration")
|
|
75
|
+
if "400" in str(e):
|
|
76
|
+
raise ValidationError(f"Export failed: {str(e)}")
|
|
77
|
+
raise
|
|
78
|
+
|
|
79
|
+
self._check_for_api_error(response, export_configuration_id, "ExportConfiguration")
|
|
80
|
+
if isinstance(response, dict):
|
|
81
|
+
return BackgroundProcessResponse(**response)
|
|
82
|
+
return response
|
|
83
|
+
|
|
84
|
+
@handle_rest_errors
|
|
85
|
+
def create_import_job(self, import_configuration_id: str,
|
|
86
|
+
data: Optional[object] = None,
|
|
87
|
+
process_description: str | None = None) -> BackgroundProcessResponse:
|
|
88
|
+
"""Trigger an import using a pre-configured import configuration (POST /import/{importConfigurationId}).
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
import_configuration_id: The ID of the import configuration to use (required)
|
|
92
|
+
data: Optional request body with import payload
|
|
93
|
+
process_description: Optional human-readable description for the import process
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
BackgroundProcessResponse with job/process details
|
|
97
|
+
|
|
98
|
+
Raises:
|
|
99
|
+
ValidationError: If import_configuration_id is missing or data is invalid
|
|
100
|
+
RestApiError: For API errors
|
|
101
|
+
"""
|
|
102
|
+
self._validate_required_params(
|
|
103
|
+
{"import_configuration_id": import_configuration_id},
|
|
104
|
+
["import_configuration_id"]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
query_params = self._build_context_params()
|
|
108
|
+
if process_description:
|
|
109
|
+
query_params["processDescription"] = process_description
|
|
110
|
+
|
|
111
|
+
self._log_operation("startImport", {"importConfigurationId": import_configuration_id})
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
if data is not None:
|
|
115
|
+
# Binary data: convert to bytes if needed
|
|
116
|
+
if isinstance(data, str):
|
|
117
|
+
binary_data = data.encode('utf-8')
|
|
118
|
+
elif isinstance(data, bytes):
|
|
119
|
+
binary_data = data
|
|
120
|
+
else:
|
|
121
|
+
# For Pydantic models or dicts, convert to JSON bytes
|
|
122
|
+
import json
|
|
123
|
+
|
|
124
|
+
from pydantic import BaseModel
|
|
125
|
+
if isinstance(data, BaseModel):
|
|
126
|
+
binary_data = json.dumps(data.model_dump(exclude_none=True)).encode('utf-8')
|
|
127
|
+
else:
|
|
128
|
+
binary_data = json.dumps(data).encode('utf-8')
|
|
129
|
+
|
|
130
|
+
response = self.client.startImport(
|
|
131
|
+
importConfigurationId=import_configuration_id,
|
|
132
|
+
data=binary_data,
|
|
133
|
+
**query_params
|
|
134
|
+
)
|
|
135
|
+
response_dict: dict[str, Any] = response if isinstance(response, dict) else {"success": True}
|
|
136
|
+
else:
|
|
137
|
+
response = self.client.startImport(
|
|
138
|
+
importConfigurationId=import_configuration_id,
|
|
139
|
+
**query_params
|
|
140
|
+
)
|
|
141
|
+
response_dict: dict[str, Any] = response if isinstance(response, dict) else {"success": True}
|
|
142
|
+
except Exception as e:
|
|
143
|
+
if "404" in str(e):
|
|
144
|
+
raise NotFoundError(import_configuration_id, "ImportConfiguration")
|
|
145
|
+
if "400" in str(e):
|
|
146
|
+
raise ValidationError(f"Import failed: {e!s}")
|
|
147
|
+
raise
|
|
148
|
+
|
|
149
|
+
self._check_for_api_error(response_dict, import_configuration_id, "ImportConfiguration")
|
|
150
|
+
if isinstance(response_dict, dict):
|
|
151
|
+
return BackgroundProcessResponse(**response_dict)
|
|
152
|
+
return response_dict
|
|
153
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Gateway integration endpoint operations for STEP REST API v2."""
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
5
|
+
from ..exceptions import NotFoundError
|
|
6
|
+
from ..models.integration_endpoint import IntegrationEndpointResponse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GatewayOperations(BaseOperation):
|
|
10
|
+
def __init__(self, client, logger=None, context=None, workspace=None):
|
|
11
|
+
super().__init__(client, operation_name="GatewayOperations", logger=logger, context=context, workspace=workspace)
|
|
12
|
+
|
|
13
|
+
@handle_rest_errors
|
|
14
|
+
def get_gateway_endpoints(self) -> list[dict[str, Any]]:
|
|
15
|
+
self._log_operation("getGatewayIntegrationEndpoints", {})
|
|
16
|
+
r = self.client.getGatewayIntegrationEndpoints(**self._build_context_params())
|
|
17
|
+
return r if isinstance(r, list) else []
|
|
18
|
+
|
|
19
|
+
@handle_rest_errors
|
|
20
|
+
def get_gateway_endpoint(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
21
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
22
|
+
self._log_operation("getGatewayIntegrationEndpoint", {"id": ep_id})
|
|
23
|
+
try:
|
|
24
|
+
r = self.client.getGatewayIntegrationEndpoint(id=ep_id, **self._build_context_params())
|
|
25
|
+
except Exception as e:
|
|
26
|
+
if "404" in str(e): raise NotFoundError(ep_id, "GatewayIntegrationEndpoint")
|
|
27
|
+
raise
|
|
28
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
29
|
+
|
|
30
|
+
@handle_rest_errors
|
|
31
|
+
def get_gateway_endpoint_status(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
32
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
33
|
+
self._log_operation("getGatewayIntegrationEndpointStatus", {"id": ep_id})
|
|
34
|
+
try:
|
|
35
|
+
r = self.client.getGatewayIntegrationEndpointStatus(id=ep_id, **self._build_context_params())
|
|
36
|
+
except Exception as e:
|
|
37
|
+
if "404" in str(e): raise NotFoundError(ep_id, "GatewayIntegrationEndpoint")
|
|
38
|
+
raise
|
|
39
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
40
|
+
|
|
41
|
+
@handle_rest_errors
|
|
42
|
+
def enable_gateway_endpoint(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
43
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
44
|
+
self._log_operation("enableGatewayIntegrationEndpoint", {"id": ep_id})
|
|
45
|
+
r = self.client.enableGatewayIntegrationEndpoint(id=ep_id, **self._build_context_params())
|
|
46
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
47
|
+
|
|
48
|
+
@handle_rest_errors
|
|
49
|
+
def disable_gateway_endpoint(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
50
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
51
|
+
self._log_operation("disableGatewayIntegrationEndpoint", {"id": ep_id})
|
|
52
|
+
r = self.client.disableGatewayIntegrationEndpoint(id=ep_id, **self._build_context_params())
|
|
53
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"""Inbound Integration Endpoint operations for STEP REST API v2.
|
|
2
|
+
|
|
3
|
+
Provides high-level operations for uploading STEP-XML to Inbound Integration Endpoints
|
|
4
|
+
and managing their status, including enabling/disabling endpoints and retrieving execution reports.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Any, Optional, Union
|
|
9
|
+
|
|
10
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
11
|
+
from ..exceptions import NotFoundError, RestApiError, ValidationError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class InboundOperations(BaseOperation):
|
|
15
|
+
"""Operations for STEP Inbound Integration Endpoints (IIEP).
|
|
16
|
+
|
|
17
|
+
Handles uploading STEP-XML documents to configured inbound endpoints
|
|
18
|
+
and managing endpoint status and execution reports.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
```python
|
|
22
|
+
from stepxmlclient.rest_client.client import StepRestClient
|
|
23
|
+
from stepxmlclient.creator import Creator
|
|
24
|
+
|
|
25
|
+
# Create and setup client
|
|
26
|
+
client = StepRestClient(
|
|
27
|
+
location_base="https://your-step.com/restapiv2",
|
|
28
|
+
authorisation=auth,
|
|
29
|
+
context="Context1"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Generate STEP-XML
|
|
33
|
+
creator = Creator(context_id="Context1")
|
|
34
|
+
# ... add products, assets, etc ...
|
|
35
|
+
creator.build()
|
|
36
|
+
xml_bytes = creator.to_bytes()
|
|
37
|
+
|
|
38
|
+
# Send to inbound endpoint
|
|
39
|
+
result = client.inbound.upload_and_invoke(
|
|
40
|
+
endpoint_id="my_inbound_endpoint",
|
|
41
|
+
xml_data=xml_bytes,
|
|
42
|
+
file_name="import_data.xml"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
print(f"Uploaded {result.get('processId')} to endpoint")
|
|
46
|
+
```
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, client, logger: Optional[logging.Logger] = None,
|
|
50
|
+
context: str | None = None, workspace: str | None = None):
|
|
51
|
+
"""Initialize inbound operations.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
client: The REST API client
|
|
55
|
+
logger: Optional logger instance
|
|
56
|
+
context: STEP context ID for all API calls (required)
|
|
57
|
+
workspace: STEP workspace ID (defaults to "Main" server-side)
|
|
58
|
+
"""
|
|
59
|
+
super().__init__(client, operation_name="InboundOperations", logger=logger,
|
|
60
|
+
context=context, workspace=workspace)
|
|
61
|
+
|
|
62
|
+
@handle_rest_errors
|
|
63
|
+
def upload_and_invoke(self, endpoint_id: str, xml_data: Union[bytes, str],
|
|
64
|
+
file_name: str | None = None) -> dict[str, Any]:
|
|
65
|
+
"""Upload STEP-XML to an inbound endpoint and trigger processing.
|
|
66
|
+
|
|
67
|
+
Posts STEP-XML content to a configured Inbound Integration Endpoint
|
|
68
|
+
with a REST receiver plugin. The endpoint is immediately invoked
|
|
69
|
+
to process the uploaded data.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
endpoint_id: ID of the inbound integration endpoint (required)
|
|
73
|
+
xml_data: STEP-XML content as bytes or string
|
|
74
|
+
file_name: Optional filename hint for the upload (e.g., "import_data.xml")
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Dictionary with response details (typically includes processId or similar)
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
ValidationError: If endpoint_id is missing or endpoint not enabled
|
|
81
|
+
NotFoundError: If endpoint cannot be found
|
|
82
|
+
RestApiError: For other API errors
|
|
83
|
+
|
|
84
|
+
Note:
|
|
85
|
+
- Endpoint must have status "enabled" to invoke
|
|
86
|
+
- Endpoint must have a REST-enabled receiver plugin configured
|
|
87
|
+
- The endpoint will begin processing immediately
|
|
88
|
+
"""
|
|
89
|
+
self._validate_required_params(
|
|
90
|
+
{"endpoint_id": endpoint_id, "xml_data": xml_data},
|
|
91
|
+
["endpoint_id", "xml_data"]
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Convert string to bytes if needed
|
|
95
|
+
if isinstance(xml_data, str):
|
|
96
|
+
xml_data = xml_data.encode('utf-8')
|
|
97
|
+
|
|
98
|
+
# Prepare query parameters (context and workspace, plus optional fileName)
|
|
99
|
+
params: dict[str, Any] = {}
|
|
100
|
+
if file_name:
|
|
101
|
+
params["fileName"] = file_name
|
|
102
|
+
params.update(self._build_context_params())
|
|
103
|
+
|
|
104
|
+
self._log_operation("uploadFileToAndInvokeInboundRestEndpoint", {
|
|
105
|
+
"endpointId": endpoint_id,
|
|
106
|
+
"fileSize": len(xml_data),
|
|
107
|
+
"fileName": file_name or "(not specified)"
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
requestor = getattr(self.client, "requestor", None)
|
|
111
|
+
server_url = None
|
|
112
|
+
server = getattr(self.client, "server", None)
|
|
113
|
+
if server is not None:
|
|
114
|
+
server_url = getattr(server, "url", None)
|
|
115
|
+
if not server_url:
|
|
116
|
+
server_url = getattr(self.client, "_server", None)
|
|
117
|
+
if server_url is not None:
|
|
118
|
+
server_url = getattr(server_url, "url", None)
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
if requestor is not None and hasattr(requestor, "post") and server_url:
|
|
122
|
+
url = f"{server_url.rstrip('/')}/inbound-integration-endpoints/{endpoint_id}/upload-and-invoke"
|
|
123
|
+
response = requestor.post(url, data=xml_data, params=params, timeout=120)
|
|
124
|
+
try:
|
|
125
|
+
response.raise_for_status()
|
|
126
|
+
except Exception as exc:
|
|
127
|
+
error_str = str(exc)
|
|
128
|
+
if "404" in error_str:
|
|
129
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
130
|
+
elif "400" in error_str:
|
|
131
|
+
if "not enabled" in error_str.lower() or "disabled" in error_str.lower():
|
|
132
|
+
raise ValidationError(
|
|
133
|
+
f"Inbound endpoint '{endpoint_id}' is not enabled. "
|
|
134
|
+
f"Enable it first using enable_endpoint()."
|
|
135
|
+
)
|
|
136
|
+
elif "REST receiver" in error_str:
|
|
137
|
+
raise ValidationError(
|
|
138
|
+
f"Inbound endpoint '{endpoint_id}' does not have a REST-enabled receiver plugin. "
|
|
139
|
+
f"Configure a REST receiver in the endpoint settings."
|
|
140
|
+
)
|
|
141
|
+
raise ValidationError(f"Upload failed: {error_str}")
|
|
142
|
+
elif "503" in error_str:
|
|
143
|
+
raise RestApiError(503, "Endpoint temporarily unavailable", details=error_str)
|
|
144
|
+
raise
|
|
145
|
+
|
|
146
|
+
if isinstance(response, dict):
|
|
147
|
+
return response
|
|
148
|
+
if hasattr(response, "json"):
|
|
149
|
+
try:
|
|
150
|
+
payload = response.json()
|
|
151
|
+
except Exception:
|
|
152
|
+
payload = None
|
|
153
|
+
if isinstance(payload, dict):
|
|
154
|
+
return payload
|
|
155
|
+
return {"success": True, "endpoint": endpoint_id}
|
|
156
|
+
|
|
157
|
+
# Fallback to generated OpenAPI operation when a requestor is not available.
|
|
158
|
+
response = self.client.uploadFileToAndInvokeInboundRestEndpoint(
|
|
159
|
+
id=endpoint_id,
|
|
160
|
+
data=xml_data,
|
|
161
|
+
**params
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
if isinstance(response, dict):
|
|
165
|
+
return response
|
|
166
|
+
if hasattr(response, "json"):
|
|
167
|
+
try:
|
|
168
|
+
payload = response.json()
|
|
169
|
+
except Exception: # noqa: BLE001
|
|
170
|
+
payload = None
|
|
171
|
+
if isinstance(payload, dict):
|
|
172
|
+
return payload
|
|
173
|
+
return {"success": True, "endpoint": endpoint_id}
|
|
174
|
+
|
|
175
|
+
except Exception as e:
|
|
176
|
+
error_str = str(e)
|
|
177
|
+
if "404" in error_str:
|
|
178
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
179
|
+
elif "400" in error_str:
|
|
180
|
+
if "not enabled" in error_str.lower() or "disabled" in error_str.lower():
|
|
181
|
+
raise ValidationError(
|
|
182
|
+
f"Inbound endpoint '{endpoint_id}' is not enabled. "
|
|
183
|
+
f"Enable it first using enable_endpoint()."
|
|
184
|
+
)
|
|
185
|
+
elif "REST receiver" in error_str:
|
|
186
|
+
raise ValidationError(
|
|
187
|
+
f"Inbound endpoint '{endpoint_id}' does not have a REST-enabled receiver plugin. "
|
|
188
|
+
f"Configure a REST receiver in the endpoint settings."
|
|
189
|
+
)
|
|
190
|
+
raise ValidationError(f"Upload failed: {error_str}")
|
|
191
|
+
elif "503" in error_str:
|
|
192
|
+
raise RestApiError(503, "Endpoint temporarily unavailable", details=error_str)
|
|
193
|
+
raise
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@handle_rest_errors
|
|
197
|
+
def list_endpoints(self) -> list[dict[str, Any]]:
|
|
198
|
+
"""Get all accessible inbound integration endpoints.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of inbound endpoint representations with ID, name, and status info
|
|
202
|
+
|
|
203
|
+
Raises:
|
|
204
|
+
RestApiError: For API errors
|
|
205
|
+
"""
|
|
206
|
+
params = self._build_context_params()
|
|
207
|
+
|
|
208
|
+
self._log_operation("getInboundIntegrationEndpoints", {})
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
response = self.client.getInboundIntegrationEndpoints(**params)
|
|
212
|
+
except Exception as e:
|
|
213
|
+
raise RestApiError(0, f"Failed to list inbound endpoints: {str(e)}", details=str(e))
|
|
214
|
+
|
|
215
|
+
return self._coerce_list_payload(response)
|
|
216
|
+
|
|
217
|
+
@handle_rest_errors
|
|
218
|
+
def get_status(self, endpoint_id: str) -> dict[str, Any]:
|
|
219
|
+
"""Get the current status of an inbound endpoint.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
endpoint_id: ID of the inbound integration endpoint
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Dictionary with status information (status, enabled state, etc.)
|
|
226
|
+
|
|
227
|
+
Raises:
|
|
228
|
+
ValidationError: If endpoint_id is missing
|
|
229
|
+
NotFoundError: If endpoint cannot be found
|
|
230
|
+
RestApiError: For API errors
|
|
231
|
+
"""
|
|
232
|
+
self._validate_required_params(
|
|
233
|
+
{"endpoint_id": endpoint_id},
|
|
234
|
+
["endpoint_id"]
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
self._log_operation("getInboundIntegrationEndpointStatus", {
|
|
238
|
+
"endpointId": endpoint_id
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
response = self.client.getInboundIntegrationEndpointStatus(
|
|
243
|
+
id=endpoint_id,
|
|
244
|
+
**self._build_context_params()
|
|
245
|
+
)
|
|
246
|
+
except Exception as e:
|
|
247
|
+
if "404" in str(e):
|
|
248
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
249
|
+
raise
|
|
250
|
+
|
|
251
|
+
self._check_for_api_error(response, endpoint_id, "InboundIntegrationEndpoint")
|
|
252
|
+
|
|
253
|
+
if isinstance(response, dict):
|
|
254
|
+
return response
|
|
255
|
+
return {"endpoint": endpoint_id}
|
|
256
|
+
|
|
257
|
+
@handle_rest_errors
|
|
258
|
+
def enable_endpoint(self, endpoint_id: str) -> dict[str, Any]:
|
|
259
|
+
"""Enable an inbound integration endpoint.
|
|
260
|
+
|
|
261
|
+
Enables the endpoint so it can receive and process uploads.
|
|
262
|
+
If endpoint has status "failed", this will resume it.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
endpoint_id: ID of the inbound integration endpoint
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Response from the enable operation
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
ValidationError: If endpoint_id is missing
|
|
272
|
+
NotFoundError: If endpoint cannot be found
|
|
273
|
+
RestApiError: For API errors
|
|
274
|
+
"""
|
|
275
|
+
self._validate_required_params(
|
|
276
|
+
{"endpoint_id": endpoint_id},
|
|
277
|
+
["endpoint_id"]
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
self._log_operation("enableInboundIntegrationEndpoint", {
|
|
281
|
+
"endpointId": endpoint_id
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
response = self.client.enableInboundIntegrationEndpoint(
|
|
286
|
+
id=endpoint_id,
|
|
287
|
+
**self._build_context_params()
|
|
288
|
+
)
|
|
289
|
+
except Exception as e:
|
|
290
|
+
if "404" in str(e):
|
|
291
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
292
|
+
raise
|
|
293
|
+
|
|
294
|
+
self._check_for_api_error(response, endpoint_id, "InboundIntegrationEndpoint")
|
|
295
|
+
|
|
296
|
+
if isinstance(response, dict):
|
|
297
|
+
return response
|
|
298
|
+
return {"success": True, "endpoint": endpoint_id, "action": "enabled"}
|
|
299
|
+
|
|
300
|
+
@handle_rest_errors
|
|
301
|
+
def disable_endpoint(self, endpoint_id: str) -> dict[str, Any]:
|
|
302
|
+
"""Disable an inbound integration endpoint.
|
|
303
|
+
|
|
304
|
+
Disables the endpoint so it will not accept uploads or process data.
|
|
305
|
+
Can be called regardless of the endpoint's current status.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
endpoint_id: ID of the inbound integration endpoint
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Response from the disable operation
|
|
312
|
+
|
|
313
|
+
Raises:
|
|
314
|
+
ValidationError: If endpoint_id is missing
|
|
315
|
+
NotFoundError: If endpoint cannot be found
|
|
316
|
+
RestApiError: For API errors
|
|
317
|
+
"""
|
|
318
|
+
self._validate_required_params(
|
|
319
|
+
{"endpoint_id": endpoint_id},
|
|
320
|
+
["endpoint_id"]
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
self._log_operation("disableInboundIntegrationEndpoint", {
|
|
324
|
+
"endpointId": endpoint_id
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
response = self.client.disableInboundIntegrationEndpoint(
|
|
329
|
+
id=endpoint_id,
|
|
330
|
+
**self._build_context_params()
|
|
331
|
+
)
|
|
332
|
+
except Exception as e:
|
|
333
|
+
if "404" in str(e):
|
|
334
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
335
|
+
raise
|
|
336
|
+
|
|
337
|
+
self._check_for_api_error(response, endpoint_id, "InboundIntegrationEndpoint")
|
|
338
|
+
|
|
339
|
+
if isinstance(response, dict):
|
|
340
|
+
return response
|
|
341
|
+
return {"success": True, "endpoint": endpoint_id, "action": "disabled"}
|
|
342
|
+
|
|
343
|
+
@handle_rest_errors
|
|
344
|
+
def get_execution_report(self, endpoint_id: str) -> list[dict[str, Any]]:
|
|
345
|
+
"""Get the execution report for an inbound endpoint's main process.
|
|
346
|
+
|
|
347
|
+
Returns detailed information about the last execution or current state.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
endpoint_id: ID of the inbound integration endpoint
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
List of execution report entries with details about operations performed
|
|
354
|
+
|
|
355
|
+
Raises:
|
|
356
|
+
ValidationError: If endpoint_id is missing
|
|
357
|
+
NotFoundError: If endpoint cannot be found
|
|
358
|
+
RestApiError: For API errors
|
|
359
|
+
"""
|
|
360
|
+
self._validate_required_params(
|
|
361
|
+
{"endpoint_id": endpoint_id},
|
|
362
|
+
["endpoint_id"]
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
self._log_operation("getInboundIntegrationEndpointExecutionReport", {
|
|
366
|
+
"endpointId": endpoint_id
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
try:
|
|
370
|
+
response = self.client.getInboundIntegrationEndpointExecutionReport(
|
|
371
|
+
id=endpoint_id,
|
|
372
|
+
**self._build_context_params()
|
|
373
|
+
)
|
|
374
|
+
except Exception as e:
|
|
375
|
+
if "404" in str(e):
|
|
376
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
377
|
+
raise
|
|
378
|
+
|
|
379
|
+
self._check_for_api_error(response, endpoint_id, "InboundIntegrationEndpoint")
|
|
380
|
+
|
|
381
|
+
if isinstance(response, (list, dict)):
|
|
382
|
+
return self._coerce_list_payload(response)
|
|
383
|
+
if response is not None:
|
|
384
|
+
return [response]
|
|
385
|
+
return []
|
|
386
|
+
|
|
387
|
+
@handle_rest_errors
|
|
388
|
+
def get_statistics(self, endpoint_id: str) -> dict[str, Any]:
|
|
389
|
+
"""Get statistics for an inbound integration endpoint.
|
|
390
|
+
|
|
391
|
+
Returns operational statistics and metrics about the endpoint.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
endpoint_id: ID of the inbound integration endpoint
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
Dictionary with statistics (message counts, error counts, etc.)
|
|
398
|
+
|
|
399
|
+
Raises:
|
|
400
|
+
ValidationError: If endpoint_id is missing
|
|
401
|
+
NotFoundError: If endpoint cannot be found
|
|
402
|
+
RestApiError: For API errors
|
|
403
|
+
"""
|
|
404
|
+
self._validate_required_params(
|
|
405
|
+
{"endpoint_id": endpoint_id},
|
|
406
|
+
["endpoint_id"]
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
self._log_operation("getInboundIntegrationEndpointStatistics", {
|
|
410
|
+
"endpointId": endpoint_id
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
response = self.client.getInboundIntegrationEndpointStatistics(
|
|
415
|
+
id=endpoint_id,
|
|
416
|
+
**self._build_context_params()
|
|
417
|
+
)
|
|
418
|
+
except Exception as e:
|
|
419
|
+
if "404" in str(e):
|
|
420
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
421
|
+
raise
|
|
422
|
+
|
|
423
|
+
self._check_for_api_error(response, endpoint_id, "InboundIntegrationEndpoint")
|
|
424
|
+
|
|
425
|
+
if isinstance(response, dict):
|
|
426
|
+
return response
|
|
427
|
+
return {}
|
|
428
|
+
|
|
429
|
+
@handle_rest_errors
|
|
430
|
+
def get_worker_processes(self, endpoint_id: str,
|
|
431
|
+
status_filter: str | None = None) -> list[str]:
|
|
432
|
+
"""Get background process IDs started by this endpoint.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
endpoint_id: ID of the inbound integration endpoint
|
|
436
|
+
status_filter: Optional filter by process status (PENDING, PROCESSING, COMPLETED, FAILED)
|
|
437
|
+
|
|
438
|
+
Returns:
|
|
439
|
+
List of background process IDs
|
|
440
|
+
|
|
441
|
+
Raises:
|
|
442
|
+
ValidationError: If endpoint_id is missing
|
|
443
|
+
NotFoundError: If endpoint cannot be found
|
|
444
|
+
RestApiError: For API errors
|
|
445
|
+
"""
|
|
446
|
+
self._validate_required_params(
|
|
447
|
+
{"endpoint_id": endpoint_id},
|
|
448
|
+
["endpoint_id"]
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
params: dict[str, Any] = self._build_context_params()
|
|
452
|
+
if status_filter:
|
|
453
|
+
params["status"] = status_filter
|
|
454
|
+
|
|
455
|
+
self._log_operation("getInboundIntegrationEndpointWorkerProcesses", {
|
|
456
|
+
"endpointId": endpoint_id,
|
|
457
|
+
"statusFilter": status_filter
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
try:
|
|
461
|
+
response = self.client.getInboundIntegrationEndpointWorkerProcesses(
|
|
462
|
+
id=endpoint_id,
|
|
463
|
+
**params
|
|
464
|
+
)
|
|
465
|
+
except Exception as e:
|
|
466
|
+
if "404" in str(e):
|
|
467
|
+
raise NotFoundError(endpoint_id, "InboundIntegrationEndpoint")
|
|
468
|
+
raise
|
|
469
|
+
|
|
470
|
+
self._check_for_api_error(response, endpoint_id, "InboundIntegrationEndpoint")
|
|
471
|
+
|
|
472
|
+
return self._coerce_list_payload(response)
|