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,349 @@
|
|
|
1
|
+
"""Reference (relation) operations for STEP REST API v2.
|
|
2
|
+
|
|
3
|
+
In the STEP REST API, references are modeled as sub-resources on entity types:
|
|
4
|
+
GET/PUT/DELETE /products/{id}/references/{referenceTypeId}/{targetId}
|
|
5
|
+
GET/PUT/DELETE /assets/{id}/references/{referenceTypeId}/{targetId}
|
|
6
|
+
GET/PUT/DELETE /classifications/{id}/references/{referenceTypeId}/{targetId}
|
|
7
|
+
GET/PUT/DELETE /entities/{id}/references/{referenceTypeId}/{targetId}
|
|
8
|
+
GET /reference-types/{id}
|
|
9
|
+
|
|
10
|
+
There is no standalone "relationship" or "cross-reference" resource in the spec.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from typing import Any, Literal, Optional
|
|
15
|
+
|
|
16
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
17
|
+
from ..exceptions import NotFoundError, ValidationError
|
|
18
|
+
from ..models.relations import (
|
|
19
|
+
RelationshipListResponse,
|
|
20
|
+
RelationshipResponse,
|
|
21
|
+
RelationshipTypeResponse,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Supported entity types for reference operations
|
|
25
|
+
EntityType = Literal["products", "assets", "classifications", "entities"]
|
|
26
|
+
|
|
27
|
+
# Map entity type to operation-ID prefix (v1.4.0 operationIds)
|
|
28
|
+
_OP_PREFIX = {
|
|
29
|
+
"products": "Product",
|
|
30
|
+
"assets": "Asset",
|
|
31
|
+
"classifications": "Classification",
|
|
32
|
+
"entities": "Entity",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Map entity type to the noun used in list-reference operation IDs
|
|
36
|
+
_OP_LIST_REF = {
|
|
37
|
+
"products": "ProductReference",
|
|
38
|
+
"assets": "AssetReferences",
|
|
39
|
+
"classifications": "ClassificationReferences",
|
|
40
|
+
"entities": "EntityReferences",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RelationOperations(BaseOperation):
|
|
45
|
+
"""Operations for managing references between STEP entities.
|
|
46
|
+
|
|
47
|
+
The STEP REST API models references as sub-resources attached to a source entity.
|
|
48
|
+
All methods require specifying the ``entity_type`` ('products', 'assets',
|
|
49
|
+
'classifications', or 'entities') of the *source* object.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, client, logger: Optional[logging.Logger] = None,
|
|
53
|
+
context: str | None = None, workspace: str | None = None):
|
|
54
|
+
"""Initialize relation operations.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
client: The REST API client
|
|
58
|
+
logger: Optional logger instance
|
|
59
|
+
context: STEP context ID for all API calls
|
|
60
|
+
workspace: STEP workspace ID (defaults to "Main" server-side)
|
|
61
|
+
"""
|
|
62
|
+
super().__init__(client, operation_name="RelationOperations", logger=logger,
|
|
63
|
+
context=context, workspace=workspace)
|
|
64
|
+
|
|
65
|
+
# ============================================================================
|
|
66
|
+
# Reference Operations
|
|
67
|
+
# ============================================================================
|
|
68
|
+
|
|
69
|
+
@handle_rest_errors
|
|
70
|
+
def list_references(self, entity_type: EntityType,
|
|
71
|
+
entity_id: str,
|
|
72
|
+
reference_type_id: str,
|
|
73
|
+
key_id: str | None = None) -> RelationshipListResponse:
|
|
74
|
+
"""List all outgoing references of a given type for a source entity.
|
|
75
|
+
|
|
76
|
+
Calls: GET /{entity_type}/{id}/references/{referenceTypeId}
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
entity_type: Source entity type ('products', 'assets', 'classifications', 'entities')
|
|
80
|
+
entity_id: Source entity ID (or alternate key value if key_id is set)
|
|
81
|
+
reference_type_id: The reference type ID to list
|
|
82
|
+
key_id: Alternate key ID for the source entity (optional)
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
RelationshipListResponse with list of references
|
|
86
|
+
"""
|
|
87
|
+
self._validate_required_params(
|
|
88
|
+
{"entity_id": entity_id, "reference_type_id": reference_type_id},
|
|
89
|
+
["entity_id", "reference_type_id"]
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
list_ref = _OP_LIST_REF.get(entity_type)
|
|
93
|
+
if not list_ref:
|
|
94
|
+
raise ValidationError(f"Invalid entity_type: {entity_type!r}. Must be one of {list(_OP_LIST_REF)}")
|
|
95
|
+
# Spec operationId uses literal braces: e.g. getProductReferenceEntryByReferenceTypeIdAndTargetIdByReferenceTypeId
|
|
96
|
+
op_id = "get" + list_ref + "ByReferenceTypeId"
|
|
97
|
+
|
|
98
|
+
query_params = self._build_context_params()
|
|
99
|
+
if key_id:
|
|
100
|
+
query_params["keyId"] = key_id
|
|
101
|
+
self._log_operation(op_id, {"entity_id": entity_id, "reference_type_id": reference_type_id})
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
op_func = getattr(self.client, op_id)
|
|
105
|
+
response = op_func(id=entity_id, referenceTypeId=reference_type_id, **query_params)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
if "404" in str(e):
|
|
108
|
+
prefix = _OP_PREFIX.get(entity_type, "Product")
|
|
109
|
+
raise NotFoundError(entity_id, prefix)
|
|
110
|
+
raise
|
|
111
|
+
|
|
112
|
+
if isinstance(response, dict):
|
|
113
|
+
return RelationshipListResponse(**response)
|
|
114
|
+
return response
|
|
115
|
+
|
|
116
|
+
@handle_rest_errors
|
|
117
|
+
def get_reference(self, entity_type: EntityType,
|
|
118
|
+
entity_id: str,
|
|
119
|
+
reference_type_id: str,
|
|
120
|
+
target_id: str,
|
|
121
|
+
key_id: str | None = None,
|
|
122
|
+
target_key_id: str | None = None,
|
|
123
|
+
include_inherited_data: bool = False) -> RelationshipResponse:
|
|
124
|
+
"""Get a single outgoing reference.
|
|
125
|
+
|
|
126
|
+
Calls: GET /{entity_type}/{id}/references/{referenceTypeId}/{targetId}
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
entity_type: Source entity type
|
|
130
|
+
entity_id: Source entity ID (or alternate key if key_id is set)
|
|
131
|
+
reference_type_id: The reference type ID
|
|
132
|
+
target_id: Target entity ID (or alternate key if target_key_id is set)
|
|
133
|
+
key_id: Alternate key ID for source entity (optional)
|
|
134
|
+
target_key_id: Alternate key ID for target entity (optional)
|
|
135
|
+
include_inherited_data: Whether to include inherited attribute values (default: False)
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
RelationshipResponse with reference details
|
|
139
|
+
"""
|
|
140
|
+
self._validate_required_params(
|
|
141
|
+
{"entity_id": entity_id, "reference_type_id": reference_type_id, "target_id": target_id},
|
|
142
|
+
["entity_id", "reference_type_id", "target_id"]
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
prefix = _OP_PREFIX.get(entity_type, "Product")
|
|
146
|
+
op_id = f"get{prefix}ReferenceEntryByReferenceTypeIdAndTargetId"
|
|
147
|
+
|
|
148
|
+
query_params: dict[str, Any] = self._build_context_params()
|
|
149
|
+
if key_id:
|
|
150
|
+
query_params["keyId"] = key_id
|
|
151
|
+
if target_key_id:
|
|
152
|
+
query_params["targetKeyId"] = target_key_id
|
|
153
|
+
if include_inherited_data:
|
|
154
|
+
query_params["includeInheritedData"] = include_inherited_data
|
|
155
|
+
self._log_operation(op_id, {"entity_id": entity_id, "reference_type_id": reference_type_id, "target_id": target_id})
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
op_func = getattr(self.client, op_id)
|
|
159
|
+
response = op_func(id=entity_id, referenceTypeId=reference_type_id, targetId=target_id, **query_params)
|
|
160
|
+
except Exception as e:
|
|
161
|
+
if "404" in str(e):
|
|
162
|
+
raise NotFoundError(entity_id, prefix)
|
|
163
|
+
raise
|
|
164
|
+
|
|
165
|
+
if isinstance(response, dict):
|
|
166
|
+
return RelationshipResponse(**response)
|
|
167
|
+
return response
|
|
168
|
+
|
|
169
|
+
@handle_rest_errors
|
|
170
|
+
def put_reference(self, entity_type: EntityType,
|
|
171
|
+
entity_id: str,
|
|
172
|
+
reference_type_id: str,
|
|
173
|
+
target_id: str,
|
|
174
|
+
data: Optional[dict[str, Any]] = None,
|
|
175
|
+
key_id: str | None = None,
|
|
176
|
+
target_key_id: str | None = None,
|
|
177
|
+
allow_overwrite: bool = False) -> RelationshipResponse:
|
|
178
|
+
"""Create or replace an outgoing reference (PUT).
|
|
179
|
+
|
|
180
|
+
Calls: PUT /{entity_type}/{id}/references/{referenceTypeId}/{targetId}
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
entity_type: Source entity type
|
|
184
|
+
entity_id: Source entity ID (or alternate key if key_id is set)
|
|
185
|
+
reference_type_id: The reference type ID
|
|
186
|
+
target_id: Target entity ID (or alternate key if target_key_id is set)
|
|
187
|
+
data: Optional body with reference attribute values
|
|
188
|
+
key_id: Alternate key ID for source entity (optional)
|
|
189
|
+
target_key_id: Alternate key ID for target entity (optional)
|
|
190
|
+
allow_overwrite: Whether to allow overwriting an existing reference
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
RelationshipResponse with created/replaced reference
|
|
194
|
+
"""
|
|
195
|
+
self._validate_required_params(
|
|
196
|
+
{"entity_id": entity_id, "reference_type_id": reference_type_id, "target_id": target_id},
|
|
197
|
+
["entity_id", "reference_type_id", "target_id"]
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
prefix = _OP_PREFIX.get(entity_type, "Product")
|
|
201
|
+
op_id = f"replace{prefix}ReferenceEntryByReferenceTypeIdAndTargetId"
|
|
202
|
+
|
|
203
|
+
query_params: dict[str, Any] = self._build_context_params()
|
|
204
|
+
if key_id:
|
|
205
|
+
query_params["keyId"] = key_id
|
|
206
|
+
if target_key_id:
|
|
207
|
+
query_params["targetKeyId"] = target_key_id
|
|
208
|
+
if allow_overwrite:
|
|
209
|
+
query_params["allow-overwrite"] = allow_overwrite
|
|
210
|
+
self._log_operation(op_id, {"entity_id": entity_id, "reference_type_id": reference_type_id, "target_id": target_id})
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
op_func = getattr(self.client, op_id)
|
|
214
|
+
if data:
|
|
215
|
+
response = op_func(id=entity_id, referenceTypeId=reference_type_id, targetId=target_id, json=data, **query_params)
|
|
216
|
+
else:
|
|
217
|
+
response = op_func(id=entity_id, referenceTypeId=reference_type_id, targetId=target_id, **query_params)
|
|
218
|
+
except Exception as e:
|
|
219
|
+
if "404" in str(e):
|
|
220
|
+
raise NotFoundError(entity_id, prefix)
|
|
221
|
+
if "400" in str(e):
|
|
222
|
+
raise ValidationError(str(e))
|
|
223
|
+
raise
|
|
224
|
+
|
|
225
|
+
if isinstance(response, dict):
|
|
226
|
+
return RelationshipResponse(**response)
|
|
227
|
+
return response
|
|
228
|
+
|
|
229
|
+
@handle_rest_errors
|
|
230
|
+
def delete_reference(self, entity_type: EntityType,
|
|
231
|
+
entity_id: str,
|
|
232
|
+
reference_type_id: str,
|
|
233
|
+
target_id: str,
|
|
234
|
+
key_id: str | None = None,
|
|
235
|
+
target_key_id: str | None = None) -> bool:
|
|
236
|
+
"""Delete an outgoing reference.
|
|
237
|
+
|
|
238
|
+
Calls: DELETE /{entity_type}/{id}/references/{referenceTypeId}/{targetId}
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
entity_type: Source entity type
|
|
242
|
+
entity_id: Source entity ID (or alternate key if key_id is set)
|
|
243
|
+
reference_type_id: The reference type ID
|
|
244
|
+
target_id: Target entity ID (or alternate key if target_key_id is set)
|
|
245
|
+
key_id: Alternate key ID for source entity (optional)
|
|
246
|
+
target_key_id: Alternate key ID for target entity (optional)
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
True if deletion was successful
|
|
250
|
+
"""
|
|
251
|
+
self._validate_required_params(
|
|
252
|
+
{"entity_id": entity_id, "reference_type_id": reference_type_id, "target_id": target_id},
|
|
253
|
+
["entity_id", "reference_type_id", "target_id"]
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
prefix = _OP_PREFIX.get(entity_type, "Product")
|
|
257
|
+
op_id = f"delete{prefix}ReferenceEntryByReferenceTypeIdAndTargetId"
|
|
258
|
+
|
|
259
|
+
query_params = self._build_context_params()
|
|
260
|
+
if key_id:
|
|
261
|
+
query_params["keyId"] = key_id
|
|
262
|
+
if target_key_id:
|
|
263
|
+
query_params["targetKeyId"] = target_key_id
|
|
264
|
+
self._log_operation(op_id, {"entity_id": entity_id, "reference_type_id": reference_type_id, "target_id": target_id})
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
op_func = getattr(self.client, op_id)
|
|
268
|
+
op_func(id=entity_id, referenceTypeId=reference_type_id, targetId=target_id, **query_params)
|
|
269
|
+
return True
|
|
270
|
+
except Exception as e:
|
|
271
|
+
if "404" in str(e):
|
|
272
|
+
raise NotFoundError(entity_id, prefix)
|
|
273
|
+
raise
|
|
274
|
+
|
|
275
|
+
@handle_rest_errors
|
|
276
|
+
def get_incoming_references(self, entity_type: EntityType,
|
|
277
|
+
entity_id: str,
|
|
278
|
+
reference_type_id: str,
|
|
279
|
+
key_id: str | None = None) -> RelationshipListResponse:
|
|
280
|
+
"""List incoming references of a given type for a target entity.
|
|
281
|
+
|
|
282
|
+
Calls: GET /{entity_type}/{id}/incoming-references/{referenceTypeId}
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
entity_type: Target entity type
|
|
286
|
+
entity_id: Target entity ID (or alternate key if key_id is set)
|
|
287
|
+
reference_type_id: The reference type ID to list
|
|
288
|
+
key_id: Alternate key ID for the target entity (optional)
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
RelationshipListResponse with list of incoming references
|
|
292
|
+
"""
|
|
293
|
+
self._validate_required_params(
|
|
294
|
+
{"entity_id": entity_id, "reference_type_id": reference_type_id},
|
|
295
|
+
["entity_id", "reference_type_id"]
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
prefix = _OP_PREFIX.get(entity_type, "Product")
|
|
299
|
+
op_id = f"get{prefix}IncomingReferences"
|
|
300
|
+
|
|
301
|
+
query_params = self._build_context_params()
|
|
302
|
+
if key_id:
|
|
303
|
+
query_params["keyId"] = key_id
|
|
304
|
+
self._log_operation(op_id, {"entity_id": entity_id, "reference_type_id": reference_type_id})
|
|
305
|
+
|
|
306
|
+
try:
|
|
307
|
+
op_func = getattr(self.client, op_id)
|
|
308
|
+
response = op_func(id=entity_id, referenceTypeId=reference_type_id, **query_params)
|
|
309
|
+
except Exception as e:
|
|
310
|
+
if "404" in str(e):
|
|
311
|
+
raise NotFoundError(entity_id, prefix)
|
|
312
|
+
raise
|
|
313
|
+
|
|
314
|
+
if isinstance(response, dict):
|
|
315
|
+
return RelationshipListResponse(**response)
|
|
316
|
+
return response
|
|
317
|
+
|
|
318
|
+
# ============================================================================
|
|
319
|
+
# Reference Type Lookup
|
|
320
|
+
# ============================================================================
|
|
321
|
+
|
|
322
|
+
@handle_rest_errors
|
|
323
|
+
def get_reference_type(self, reference_type_id: str) -> RelationshipTypeResponse:
|
|
324
|
+
"""Get a reference type definition by ID (GET /reference-types/{id}).
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
reference_type_id: The reference type ID
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
RelationshipTypeResponse with reference type details
|
|
331
|
+
"""
|
|
332
|
+
self._validate_required_params(
|
|
333
|
+
{"reference_type_id": reference_type_id},
|
|
334
|
+
["reference_type_id"]
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
query_params = self._build_context_params()
|
|
338
|
+
self._log_operation("getReferenceType", {"reference_type_id": reference_type_id})
|
|
339
|
+
|
|
340
|
+
try:
|
|
341
|
+
response = self.client.getReferenceType(id=reference_type_id, **query_params)
|
|
342
|
+
except Exception as e:
|
|
343
|
+
if "404" in str(e):
|
|
344
|
+
raise NotFoundError(reference_type_id, "ReferenceType")
|
|
345
|
+
raise
|
|
346
|
+
|
|
347
|
+
if isinstance(response, dict):
|
|
348
|
+
return RelationshipTypeResponse(**response)
|
|
349
|
+
return response
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Reporting operations for STEP REST API v2."""
|
|
2
|
+
from typing import Any, Optional
|
|
3
|
+
|
|
4
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ReportOperations(BaseOperation):
|
|
8
|
+
def __init__(self, client, logger=None, context=None, workspace=None):
|
|
9
|
+
super().__init__(client, operation_name="ReportOperations", logger=logger, context=context, workspace=workspace)
|
|
10
|
+
|
|
11
|
+
@handle_rest_errors
|
|
12
|
+
def start_historic_changes_report(self, report_id: str, data: Optional[dict[str, Any]] = None) -> dict[str, Any]:
|
|
13
|
+
self._validate_required_params({"report_id": report_id}, ["report_id"])
|
|
14
|
+
self._log_operation("startHistoricChangesReport", {"reportID": report_id})
|
|
15
|
+
kwargs: dict[str, Any] = {"id": report_id}
|
|
16
|
+
kwargs.update(self._build_context_params())
|
|
17
|
+
if data is not None:
|
|
18
|
+
kwargs["json"] = data
|
|
19
|
+
r = self.client.startHistoricChangesReport(**kwargs)
|
|
20
|
+
return r if isinstance(r, dict) else r
|
|
21
|
+
|
|
22
|
+
@handle_rest_errors
|
|
23
|
+
def clean_up_historic_changes_report(self, report_id: str) -> dict[str, Any]:
|
|
24
|
+
self._validate_required_params({"report_id": report_id}, ["report_id"])
|
|
25
|
+
self._log_operation("cleanUpHistoricChangesReport", {"reportID": report_id})
|
|
26
|
+
r = self.client.cleanUpHistoricChangesReport(id=report_id, **self._build_context_params())
|
|
27
|
+
return r if isinstance(r, dict) else r
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""System information operations for STEP REST API v2.
|
|
2
|
+
|
|
3
|
+
Covers the /system-information endpoint introduced in v1.4.0.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
9
|
+
from ..models.system_information import SystemInformationResponse
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SystemInformationOperations(BaseOperation):
|
|
13
|
+
"""Operations for STEP system information."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, client, logger: logging.Logger | None = None,
|
|
16
|
+
context: str | None = None, workspace: str | None = None):
|
|
17
|
+
super().__init__(client, operation_name="SystemInformationOperations", logger=logger,
|
|
18
|
+
context=context, workspace=workspace)
|
|
19
|
+
|
|
20
|
+
@handle_rest_errors
|
|
21
|
+
def get_system_information(self) -> SystemInformationResponse:
|
|
22
|
+
"""Get system information and capabilities.
|
|
23
|
+
|
|
24
|
+
Calls: GET /system-information -> getSystemInformation
|
|
25
|
+
"""
|
|
26
|
+
self._log_operation("getSystemInformation", {})
|
|
27
|
+
response = self.client.getSystemInformation(**self._build_context_params())
|
|
28
|
+
return SystemInformationResponse(**response) if isinstance(response, dict) else response
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""User group operations for STEP REST API v2."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
6
|
+
from ..exceptions import NotFoundError, ValidationError
|
|
7
|
+
from ..models.user import UserGroupResponse
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class UserGroupOperations(BaseOperation):
|
|
11
|
+
"""Operations for STEP User Groups."""
|
|
12
|
+
def __init__(self, client, logger=None, context=None, workspace=None):
|
|
13
|
+
super().__init__(client, operation_name="UserGroupOperations", logger=logger, context=context, workspace=workspace)
|
|
14
|
+
|
|
15
|
+
@handle_rest_errors
|
|
16
|
+
def get_user_group(self, group_id: str) -> UserGroupResponse:
|
|
17
|
+
self._validate_required_params({"group_id": group_id}, ["group_id"])
|
|
18
|
+
self._log_operation("getUserGroup", {"id": group_id})
|
|
19
|
+
try:
|
|
20
|
+
r = self.client.getUserGroup(id=group_id, **self._build_context_params())
|
|
21
|
+
except Exception as e:
|
|
22
|
+
if "404" in str(e): raise NotFoundError(group_id, "UserGroup")
|
|
23
|
+
raise
|
|
24
|
+
return UserGroupResponse(**r) if isinstance(r, dict) else r
|
|
25
|
+
|
|
26
|
+
@handle_rest_errors
|
|
27
|
+
def create_or_replace_user_group(self, group_id: str, data: dict[str, Any]) -> UserGroupResponse:
|
|
28
|
+
self._validate_required_params({"group_id": group_id}, ["group_id"])
|
|
29
|
+
self._log_operation("createOrReplaceUserGroup", {"id": group_id})
|
|
30
|
+
try:
|
|
31
|
+
r = self.client.createOrReplaceUserGroup(id=group_id, json=data, **self._build_context_params())
|
|
32
|
+
except Exception as e:
|
|
33
|
+
if "400" in str(e): raise ValidationError(str(e))
|
|
34
|
+
raise
|
|
35
|
+
return UserGroupResponse(**r) if isinstance(r, dict) else r
|
|
36
|
+
|
|
37
|
+
@handle_rest_errors
|
|
38
|
+
def update_user_group(self, group_id: str, data: dict[str, Any]) -> UserGroupResponse:
|
|
39
|
+
self._validate_required_params({"group_id": group_id}, ["group_id"])
|
|
40
|
+
self._log_operation("updateUserGroup", {"id": group_id})
|
|
41
|
+
try:
|
|
42
|
+
r = self.client.updateUserGroup(id=group_id, json=data, **self._build_context_params())
|
|
43
|
+
except Exception as e:
|
|
44
|
+
if "404" in str(e): raise NotFoundError(group_id, "UserGroup")
|
|
45
|
+
raise
|
|
46
|
+
return UserGroupResponse(**r) if isinstance(r, dict) else r
|
|
47
|
+
|
|
48
|
+
@handle_rest_errors
|
|
49
|
+
def delete_user_group(self, group_id: str) -> bool:
|
|
50
|
+
self._validate_required_params({"group_id": group_id}, ["group_id"])
|
|
51
|
+
self._log_operation("deleteUserGroup", {"id": group_id})
|
|
52
|
+
try:
|
|
53
|
+
self.client.deleteUserGroup(id=group_id, **self._build_context_params())
|
|
54
|
+
return True
|
|
55
|
+
except Exception as e:
|
|
56
|
+
if "404" in str(e): raise NotFoundError(group_id, "UserGroup")
|
|
57
|
+
raise
|
|
58
|
+
|
|
59
|
+
@handle_rest_errors
|
|
60
|
+
def get_user_group_users(self, group_id: str) -> list[dict[str, Any]]:
|
|
61
|
+
self._validate_required_params({"group_id": group_id}, ["group_id"])
|
|
62
|
+
self._log_operation("getUserGroupUsers", {"id": group_id})
|
|
63
|
+
try:
|
|
64
|
+
r = self.client.getUserGroupUsers(id=group_id, **self._build_context_params())
|
|
65
|
+
except Exception as e:
|
|
66
|
+
if "404" in str(e): raise NotFoundError(group_id, "UserGroup")
|
|
67
|
+
raise
|
|
68
|
+
return r if isinstance(r, list) else []
|
|
69
|
+
|
|
70
|
+
@handle_rest_errors
|
|
71
|
+
def get_user_group_children(self, group_id: str) -> list[str]:
|
|
72
|
+
self._validate_required_params({"group_id": group_id}, ["group_id"])
|
|
73
|
+
self._log_operation("getUserGroupChildren", {"id": group_id})
|
|
74
|
+
try:
|
|
75
|
+
r = self.client.getUserGroupChildren(id=group_id, **self._build_context_params())
|
|
76
|
+
except Exception as e:
|
|
77
|
+
if "404" in str(e): raise NotFoundError(group_id, "UserGroup")
|
|
78
|
+
raise
|
|
79
|
+
return r if isinstance(r, list) else []
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""User operations for STEP REST API v2.
|
|
2
|
+
|
|
3
|
+
Covers the /users endpoints introduced in v1.4.0.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
10
|
+
from ..exceptions import NotFoundError, ValidationError
|
|
11
|
+
from ..models.user import UserResponse
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class UserOperations(BaseOperation):
|
|
15
|
+
"""Operations for STEP Users."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, client, logger: logging.Logger | None = None,
|
|
18
|
+
context: str | None = None, workspace: str | None = None):
|
|
19
|
+
super().__init__(client, operation_name="UserOperations", logger=logger,
|
|
20
|
+
context=context, workspace=workspace)
|
|
21
|
+
|
|
22
|
+
@handle_rest_errors
|
|
23
|
+
def get_user(self, user_id: str) -> UserResponse:
|
|
24
|
+
"""Get a user by ID.
|
|
25
|
+
Calls: GET /users/{id} -> getUser
|
|
26
|
+
"""
|
|
27
|
+
self._validate_required_params({"user_id": user_id}, ["user_id"])
|
|
28
|
+
self._log_operation("getUser", {"id": user_id})
|
|
29
|
+
try:
|
|
30
|
+
r = self.client.getUser(id=user_id, **self._build_context_params())
|
|
31
|
+
except Exception as e:
|
|
32
|
+
if "404" in str(e): raise NotFoundError(user_id, "User")
|
|
33
|
+
raise
|
|
34
|
+
return UserResponse(**r) if isinstance(r, dict) else r
|
|
35
|
+
|
|
36
|
+
@handle_rest_errors
|
|
37
|
+
def create_or_replace_user(self, user_id: str, data: dict[str, Any]) -> UserResponse:
|
|
38
|
+
"""Create or fully replace a user.
|
|
39
|
+
Calls: PUT /users/{id} -> createOrReplaceUser
|
|
40
|
+
"""
|
|
41
|
+
self._validate_required_params({"user_id": user_id}, ["user_id"])
|
|
42
|
+
self._log_operation("createOrReplaceUser", {"id": user_id})
|
|
43
|
+
try:
|
|
44
|
+
r = self.client.createOrReplaceUser(id=user_id, json=data, **self._build_context_params())
|
|
45
|
+
except Exception as e:
|
|
46
|
+
if "400" in str(e): raise ValidationError(str(e))
|
|
47
|
+
raise
|
|
48
|
+
return UserResponse(**r) if isinstance(r, dict) else r
|
|
49
|
+
|
|
50
|
+
@handle_rest_errors
|
|
51
|
+
def update_user(self, user_id: str, data: dict[str, Any]) -> UserResponse:
|
|
52
|
+
"""Partially update a user.
|
|
53
|
+
Calls: PATCH /users/{id} -> updateUser
|
|
54
|
+
"""
|
|
55
|
+
self._validate_required_params({"user_id": user_id}, ["user_id"])
|
|
56
|
+
self._log_operation("updateUser", {"id": user_id})
|
|
57
|
+
try:
|
|
58
|
+
r = self.client.updateUser(id=user_id, json=data, **self._build_context_params())
|
|
59
|
+
except Exception as e:
|
|
60
|
+
if "404" in str(e): raise NotFoundError(user_id, "User")
|
|
61
|
+
if "400" in str(e): raise ValidationError(str(e))
|
|
62
|
+
raise
|
|
63
|
+
return UserResponse(**r) if isinstance(r, dict) else r
|
|
64
|
+
|
|
65
|
+
@handle_rest_errors
|
|
66
|
+
def delete_user(self, user_id: str) -> bool:
|
|
67
|
+
"""Delete a user.
|
|
68
|
+
Calls: DELETE /users/{id} -> deleteUser
|
|
69
|
+
"""
|
|
70
|
+
self._validate_required_params({"user_id": user_id}, ["user_id"])
|
|
71
|
+
self._log_operation("deleteUser", {"id": user_id})
|
|
72
|
+
try:
|
|
73
|
+
self.client.deleteUser(id=user_id, **self._build_context_params())
|
|
74
|
+
return True
|
|
75
|
+
except Exception as e:
|
|
76
|
+
if "404" in str(e): raise NotFoundError(user_id, "User")
|
|
77
|
+
raise
|
|
78
|
+
|
|
79
|
+
@handle_rest_errors
|
|
80
|
+
def randomize_password(self, user_id: str) -> UserResponse:
|
|
81
|
+
"""Randomize a user's password.
|
|
82
|
+
Calls: POST /users/{id}/randomize-password -> randomizeStepPassword
|
|
83
|
+
"""
|
|
84
|
+
self._validate_required_params({"user_id": user_id}, ["user_id"])
|
|
85
|
+
self._log_operation("randomizeStepPassword", {"id": user_id})
|
|
86
|
+
try:
|
|
87
|
+
r = self.client.randomizeStepPassword(id=user_id, **self._build_context_params())
|
|
88
|
+
except Exception as e:
|
|
89
|
+
if "404" in str(e): raise NotFoundError(user_id, "User")
|
|
90
|
+
raise
|
|
91
|
+
return UserResponse(**r) if isinstance(r, dict) else r
|
|
92
|
+
|
|
93
|
+
@handle_rest_errors
|
|
94
|
+
def add_user_to_group(self, user_id: str, group_data: dict[str, Any]) -> UserResponse:
|
|
95
|
+
"""Add a user to a group.
|
|
96
|
+
Calls: POST /users/{id}/add-to-group -> addUserToGroup
|
|
97
|
+
"""
|
|
98
|
+
self._validate_required_params({"user_id": user_id}, ["user_id"])
|
|
99
|
+
self._log_operation("addUserToGroup", {"id": user_id})
|
|
100
|
+
try:
|
|
101
|
+
r = self.client.addUserToGroup(id=user_id, json=group_data, **self._build_context_params())
|
|
102
|
+
except Exception as e:
|
|
103
|
+
if "404" in str(e): raise NotFoundError(user_id, "User")
|
|
104
|
+
raise
|
|
105
|
+
return UserResponse(**r) if isinstance(r, dict) else r
|
|
106
|
+
|
|
107
|
+
@handle_rest_errors
|
|
108
|
+
def remove_user_from_group(self, user_id: str, group_data: dict[str, Any]) -> UserResponse:
|
|
109
|
+
"""Remove a user from a group.
|
|
110
|
+
Calls: POST /users/{id}/remove-from-group -> removeUserFromGroup
|
|
111
|
+
"""
|
|
112
|
+
self._validate_required_params({"user_id": user_id}, ["user_id"])
|
|
113
|
+
self._log_operation("removeUserFromGroup", {"id": user_id})
|
|
114
|
+
try:
|
|
115
|
+
r = self.client.removeUserFromGroup(id=user_id, json=group_data, **self._build_context_params())
|
|
116
|
+
except Exception as e:
|
|
117
|
+
if "404" in str(e): raise NotFoundError(user_id, "User")
|
|
118
|
+
raise
|
|
119
|
+
return UserResponse(**r) if isinstance(r, dict) else r
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Workflow task 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.workflow import WorkflowTaskResponse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class WorkflowTaskOperations(BaseOperation):
|
|
10
|
+
def __init__(self, client, logger=None, context=None, workspace=None):
|
|
11
|
+
super().__init__(client, operation_name="WorkflowTaskOperations", logger=logger, context=context, workspace=workspace)
|
|
12
|
+
|
|
13
|
+
@handle_rest_errors
|
|
14
|
+
def search_workflow_tasks(self, condition: dict[str, Any]) -> WorkflowTaskResponse:
|
|
15
|
+
self._validate_required_params({"condition": condition}, ["condition"])
|
|
16
|
+
self._log_operation("searchWorkflowTasks", {})
|
|
17
|
+
r = self.client.searchWorkflowTasks(json={"condition": condition}, **self._build_context_params())
|
|
18
|
+
return WorkflowTaskResponse(**r) if isinstance(r, dict) else r
|
|
19
|
+
|
|
20
|
+
@handle_rest_errors
|
|
21
|
+
def get_workflow_task(self, task_id: str) -> WorkflowTaskResponse:
|
|
22
|
+
self._validate_required_params({"task_id": task_id}, ["task_id"])
|
|
23
|
+
self._log_operation("getWorkflowTask", {"id": task_id})
|
|
24
|
+
try:
|
|
25
|
+
r = self.client.getWorkflowTask(id=task_id, **self._build_context_params())
|
|
26
|
+
except Exception as e:
|
|
27
|
+
if "404" in str(e): raise NotFoundError(task_id, "WorkflowTask")
|
|
28
|
+
raise
|
|
29
|
+
return WorkflowTaskResponse(**r) if isinstance(r, dict) else r
|
|
30
|
+
|
|
31
|
+
@handle_rest_errors
|
|
32
|
+
def claim_workflow_task(self, task_id: str) -> WorkflowTaskResponse:
|
|
33
|
+
self._validate_required_params({"task_id": task_id}, ["task_id"])
|
|
34
|
+
self._log_operation("claimWorkflowTask", {"id": task_id})
|
|
35
|
+
r = self.client.claimWorkflowTask(id=task_id, **self._build_context_params())
|
|
36
|
+
return WorkflowTaskResponse(**r) if isinstance(r, dict) else r
|
|
37
|
+
|
|
38
|
+
@handle_rest_errors
|
|
39
|
+
def get_workflow_task_events(self, task_id: str) -> list[dict[str, Any]]:
|
|
40
|
+
self._validate_required_params({"task_id": task_id}, ["task_id"])
|
|
41
|
+
self._log_operation("getWorkflowTaskEvents", {"id": task_id})
|
|
42
|
+
try:
|
|
43
|
+
r = self.client.getWorkflowTaskEvents(id=task_id, **self._build_context_params())
|
|
44
|
+
except Exception as e:
|
|
45
|
+
if "404" in str(e): raise NotFoundError(task_id, "WorkflowTask")
|
|
46
|
+
raise
|
|
47
|
+
return r if isinstance(r, list) else []
|
|
48
|
+
|
|
49
|
+
@handle_rest_errors
|
|
50
|
+
def trigger_workflow_task_event(self, task_id: str, data: dict[str, Any]) -> WorkflowTaskResponse:
|
|
51
|
+
self._validate_required_params({"task_id": task_id}, ["task_id"])
|
|
52
|
+
self._log_operation("triggerWorkflowTaskEvent", {"id": task_id})
|
|
53
|
+
r = self.client.triggerWorkflowTaskEvent(id=task_id, json=data, **self._build_context_params())
|
|
54
|
+
return WorkflowTaskResponse(**r) if isinstance(r, dict) else r
|
|
55
|
+
|
|
56
|
+
@handle_rest_errors
|
|
57
|
+
def release_workflow_task(self, task_id: str) -> WorkflowTaskResponse:
|
|
58
|
+
self._validate_required_params({"task_id": task_id}, ["task_id"])
|
|
59
|
+
self._log_operation("releaseWorkflowTask", {"id": task_id})
|
|
60
|
+
r = self.client.releaseWorkflowTask(id=task_id, **self._build_context_params())
|
|
61
|
+
return WorkflowTaskResponse(**r) if isinstance(r, dict) else r
|