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,666 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stepxmlclient
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python client for Stibo Systems STEP XML and REST API v2
|
|
5
|
+
Author-email: everleah <everleah@hansch.info>
|
|
6
|
+
Maintainer-email: everleah <everleah@hansch.info>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Source, https://git.claudiapps.de/Hoerl-IM/StepXML-Client
|
|
9
|
+
Keywords: stibo,step,mdm,xml,rest,pim
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: requests-openapi
|
|
20
|
+
Requires-Dist: requests
|
|
21
|
+
Requires-Dist: pydantic>=2.0
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# STEP XML Client
|
|
25
|
+
|
|
26
|
+
Python client library for Stibo Systems STEP MDM (Master Data Management), supporting the STEP-XML protocol and STEP REST API v2.
|
|
27
|
+
|
|
28
|
+
## Overview
|
|
29
|
+
|
|
30
|
+
This library enables seamless integration with STEP systems via:
|
|
31
|
+
- **OIEP (Outbound Integration Endpoint)**: Retrieve data from STEP as STEP-XML
|
|
32
|
+
- **IIEP (Inbound Integration Endpoint)**: Send data to STEP as STEP-XML
|
|
33
|
+
- **REST API v2**: Grouped, typed client for STEP REST API v2
|
|
34
|
+
|
|
35
|
+
## Current Features
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
**REST API v2 Client**
|
|
39
|
+
- 22 operation groups for STEP REST API v2
|
|
40
|
+
- Full CRUD, approval, values, children, data containers, purge for Products/Assets/Classifications/Entities
|
|
41
|
+
- Contexts, Users, User Groups, Collections, Workflows, Background Processes, Event Processors
|
|
42
|
+
- Inbound/Outbound/Gateway integration endpoints
|
|
43
|
+
- Type-safe Pydantic models, unified authentication, OpenAPI caching
|
|
44
|
+
- ✅ See [docs/REST_API_USAGE.md](docs/REST_API_USAGE.md) for full usage guide
|
|
45
|
+
|
|
46
|
+
STEP-XML parsing for a broad set of STEP entities, with XML generation for core entities.
|
|
47
|
+
|
|
48
|
+
### Core Capabilities
|
|
49
|
+
- ✅ **STEP-XML Parsing**: Parse 20+ STEP entity types including Products, Assets, Classifications, Entities, Attributes, and more
|
|
50
|
+
- ✅ **STEP-XML Generation**: Create and serialize XML documents for core entities (Phase 1 complete)
|
|
51
|
+
- ✅ **Relationship Management**: Full support for all cross-reference types (Asset, Product, Classification, Entity)
|
|
52
|
+
- ✅ **REST API Integration**: Client for STEP REST API v2 authentication and operations
|
|
53
|
+
- ✅ **Asset Binary Upload/Download**: Upload files (images, documents) and retrieve asset content via REST API
|
|
54
|
+
- **Schema Validation**: XML can be validated against a STEP XSD obtained from Stibo Systems
|
|
55
|
+
- ✅ **Deletion Operations**: Support for product and asset deletions, link severance
|
|
56
|
+
- ✅ **Product Replacement Rules**: Create and manage product replacement configurations
|
|
57
|
+
|
|
58
|
+
### Parsed Entity Types (Phase 2-14)
|
|
59
|
+
- **Products** - Full support with all attributes and relationships ✅
|
|
60
|
+
- **Assets** - Full support with key values and cross-references ✅
|
|
61
|
+
- **Classifications** - Full hierarchical parsing ✅
|
|
62
|
+
- **Entities** - Complete entity structure parsing ✅
|
|
63
|
+
- **Attributes** - Full attribute definition parsing ✅
|
|
64
|
+
- **AttributeGroups** - Hierarchical group definitions ✅
|
|
65
|
+
- **ListOfValues** - LOV items and associations ✅
|
|
66
|
+
- **Contexts, Qualifiers, Dimensions** - Configuration elements ✅
|
|
67
|
+
- **UserTypes, LinkTypes** - Type definitions ✅
|
|
68
|
+
- **Tags, TagGroups, Units** - Metadata and classification ✅
|
|
69
|
+
- **BusinessRules, Workflows** - Advanced configuration ✅
|
|
70
|
+
- **Collections, CollectionGroups** - Collection management ✅
|
|
71
|
+
- **Delete Operations** - Products, Assets, and link severance ✅
|
|
72
|
+
- **Replacement Rules** - Product replacement configurations ✅
|
|
73
|
+
|
|
74
|
+
### Generation Capabilities (Phase 1 Complete)
|
|
75
|
+
- **Products** - Create with attributes, values, and cross-references
|
|
76
|
+
- **Assets** - Create with key values and cross-references
|
|
77
|
+
- **Cross-References** - All relationship types (Asset, Product, Classification, Entity)
|
|
78
|
+
- **Deletion Operations** - Delete products/assets and sever links
|
|
79
|
+
- **Product Replacement Rules** - Create replacement configurations
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
**First public release**: `1.0.0`. Package metadata and the release version are defined in `pyproject.toml`.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Install from PyPI (or your package repository)
|
|
88
|
+
pip install stepxmlclient
|
|
89
|
+
|
|
90
|
+
# Or build from source
|
|
91
|
+
pip install -r requirements-release.txt
|
|
92
|
+
python -m build
|
|
93
|
+
pip install dist/stepxmlclient-x.x.x-py3-none-any.whl
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Requirements**:
|
|
97
|
+
- Python 3.9+
|
|
98
|
+
- requests-openapi
|
|
99
|
+
- requests
|
|
100
|
+
- pydantic>=2.0
|
|
101
|
+
- xml.etree.ElementTree (built-in)
|
|
102
|
+
|
|
103
|
+
## Quick Start
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
### REST API Client (Full Usage)
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from stepxmlclient.client import StiboStepRestClient, BasicAuthorisation
|
|
110
|
+
from stepxmlclient.rest_client import StepRestClient
|
|
111
|
+
from stepxmlclient.rest_client.models.product import ProductCreateRequest
|
|
112
|
+
|
|
113
|
+
# Shared authentication
|
|
114
|
+
auth = BasicAuthorisation(user="your-username", pwd="your-password")
|
|
115
|
+
|
|
116
|
+
# 1) Direct OpenAPI access (raw operation IDs)
|
|
117
|
+
raw_client = StiboStepRestClient(
|
|
118
|
+
location_base="https://your-step-server/restapiv2",
|
|
119
|
+
authorisation=auth,
|
|
120
|
+
context="Context1"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# 2) Grouped wrapper access (recommended for most usage)
|
|
124
|
+
ops_client = StepRestClient(
|
|
125
|
+
location_base="https://your-step-server/restapiv2",
|
|
126
|
+
authorisation=auth,
|
|
127
|
+
context="Context1"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
created = ops_client.products.create_product(
|
|
131
|
+
ProductCreateRequest(
|
|
132
|
+
objectType="SalesItem",
|
|
133
|
+
parent="RootProduct",
|
|
134
|
+
name="Sample Product"
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
retrieved = ops_client.products.get_product(created.id)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
See [docs/REST_API_USAGE.md](docs/REST_API_USAGE.md) for detailed usage and all operation/model examples.
|
|
141
|
+
|
|
142
|
+
### Asset Binary Upload & Download
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from stepxmlclient.client import StiboStepRestClient, BasicAuthorisation
|
|
146
|
+
from stepxmlclient.upload import AssetUploader
|
|
147
|
+
|
|
148
|
+
# Create authenticated client
|
|
149
|
+
auth = BasicAuthorisation('username', 'password')
|
|
150
|
+
client = StiboStepRestClient(
|
|
151
|
+
'https://your-step-server.com/restapiv2',
|
|
152
|
+
auth
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# Initialize uploader
|
|
156
|
+
uploader = AssetUploader(client)
|
|
157
|
+
|
|
158
|
+
# Upload local file to asset
|
|
159
|
+
result = uploader.upload_file(
|
|
160
|
+
file_path='product_image.jpg',
|
|
161
|
+
asset_id='ASSET_001',
|
|
162
|
+
context_id='Context1',
|
|
163
|
+
workspace_id='Main'
|
|
164
|
+
)
|
|
165
|
+
print(f"Upload successful: {result['asset_id']}")
|
|
166
|
+
|
|
167
|
+
# Upload from URL
|
|
168
|
+
result = uploader.upload_file(
|
|
169
|
+
file_path='https://example.com/image.jpg',
|
|
170
|
+
asset_id='ASSET_002',
|
|
171
|
+
context_id='Context1'
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Download asset content
|
|
175
|
+
content = uploader.get_content(
|
|
176
|
+
asset_id='ASSET_001',
|
|
177
|
+
context_id='Context1'
|
|
178
|
+
)
|
|
179
|
+
with open('downloaded.jpg', 'wb') as f:
|
|
180
|
+
f.write(content)
|
|
181
|
+
|
|
182
|
+
# Download OIEP REST delivery result by ResultURI (uses same client credentials)
|
|
183
|
+
result_uri = "restapi/integrationendpoints/asdf/BGP_213226/result.zip"
|
|
184
|
+
downloaded_file = client.download_result_uri(
|
|
185
|
+
result_uri,
|
|
186
|
+
target_dir="./downloads"
|
|
187
|
+
)
|
|
188
|
+
print(f"Result file downloaded to: {downloaded_file}")
|
|
189
|
+
|
|
190
|
+
# Or pass the complete OIEP response directly
|
|
191
|
+
oiep_response = {"ResultURI": "restapi/integrationendpoints/asdf/BGP_213226/result.zip"}
|
|
192
|
+
downloaded_file = client.download_oiep_result(
|
|
193
|
+
oiep_response,
|
|
194
|
+
target_dir="./downloads"
|
|
195
|
+
)
|
|
196
|
+
print(f"Result file downloaded to: {downloaded_file}")
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### XML Parsing (Comprehensive)
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from stepxmlclient.parser import Parser
|
|
203
|
+
|
|
204
|
+
# Parse STEP-XML from file
|
|
205
|
+
parser = Parser()
|
|
206
|
+
parser.parse_file('step_export.xml')
|
|
207
|
+
|
|
208
|
+
# Access parsed entities (20+ types supported)
|
|
209
|
+
products = parser.products
|
|
210
|
+
assets = parser.assets
|
|
211
|
+
classifications = parser.classifications
|
|
212
|
+
entities = parser.entities
|
|
213
|
+
attributes = parser.attributes
|
|
214
|
+
attribute_groups = parser.attribute_groups
|
|
215
|
+
list_of_values = parser.list_of_values
|
|
216
|
+
tags = parser.tags
|
|
217
|
+
workflows = parser.workflows
|
|
218
|
+
business_rules = parser.business_rules
|
|
219
|
+
|
|
220
|
+
# Handle deletion operations
|
|
221
|
+
deleted_products = parser.delete_products
|
|
222
|
+
deleted_assets = parser.delete_assets
|
|
223
|
+
|
|
224
|
+
# Example: Navigate product relationships
|
|
225
|
+
for product in products:
|
|
226
|
+
print(f"Product: {product['ID']}")
|
|
227
|
+
print(f" Name: {product.get('Name')}")
|
|
228
|
+
|
|
229
|
+
# Check for asset relationships
|
|
230
|
+
if 'AssetCrossReference' in product:
|
|
231
|
+
asset_ref = product['AssetCrossReference']
|
|
232
|
+
print(f" Asset: {asset_ref['AssetID']}")
|
|
233
|
+
|
|
234
|
+
# Check for product relationships
|
|
235
|
+
if 'ProductCrossReference' in product:
|
|
236
|
+
prod_ref = product['ProductCrossReference']
|
|
237
|
+
print(f" Related Product: {prod_ref['ProductID']}")
|
|
238
|
+
|
|
239
|
+
# Check for classification relationships
|
|
240
|
+
if 'ClassificationCrossReference' in product:
|
|
241
|
+
class_ref = product['ClassificationCrossReference']
|
|
242
|
+
print(f" Classification: {class_ref['ClassificationID']}")
|
|
243
|
+
|
|
244
|
+
# Access attribute values
|
|
245
|
+
if 'Values' in product:
|
|
246
|
+
for value in product['Values']:
|
|
247
|
+
print(f" {value['AttributeID']}: {value.get('Value')}")
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### XML Creation
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
from stepxmlclient.creator import Creator
|
|
254
|
+
from stepxmlclient.model import Product, Asset
|
|
255
|
+
|
|
256
|
+
# Create XML document for specific context and workspace
|
|
257
|
+
creator = Creator(
|
|
258
|
+
context_id="Context1",
|
|
259
|
+
workspace_id="Main"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Create a product with asset relationship
|
|
263
|
+
product = Product({
|
|
264
|
+
"ID": "PROD_001",
|
|
265
|
+
"Name": "Sample Product",
|
|
266
|
+
"UserTypeID": "StandardProduct",
|
|
267
|
+
"AssetCrossReference": {
|
|
268
|
+
"AssetID": "ASSET_001",
|
|
269
|
+
"Changed": True,
|
|
270
|
+
"Type": "Primary Image"
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
# Create an asset
|
|
275
|
+
asset = Asset({
|
|
276
|
+
"ID": "ASSET_001",
|
|
277
|
+
"Name": "Product Image",
|
|
278
|
+
"KeyValue": "IMG_001"
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
# Add entities to creator
|
|
282
|
+
creator.add(product)
|
|
283
|
+
creator.add(asset)
|
|
284
|
+
|
|
285
|
+
# Generate XML document
|
|
286
|
+
creator.build()
|
|
287
|
+
|
|
288
|
+
# Export as string or tree
|
|
289
|
+
xml_string = creator.to_string()
|
|
290
|
+
print(xml_string)
|
|
291
|
+
|
|
292
|
+
# Or save to file
|
|
293
|
+
creator.tree.write('output.xml', encoding='utf-8')
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Product Replacement Rules
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
from stepxmlclient.creator import Creator
|
|
300
|
+
from stepxmlclient.model import ProductReplacementRule
|
|
301
|
+
|
|
302
|
+
creator = Creator(context_id="Context1", workspace_id="Main")
|
|
303
|
+
|
|
304
|
+
# Create replacement rule
|
|
305
|
+
replacement = ProductReplacementRule({
|
|
306
|
+
"ID": "RULE_001",
|
|
307
|
+
"SourceProductID": "OLD_PROD",
|
|
308
|
+
"ReplacementProductID": "NEW_PROD"
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
creator.add(replacement)
|
|
312
|
+
creator.build()
|
|
313
|
+
xml_string = creator.to_string()
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Project Structure
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
stepxmlclient/
|
|
320
|
+
├── __init__.py # Namespace definitions (STEPXML_NS)
|
|
321
|
+
├── client.py # StiboStepRestClient (Base client)
|
|
322
|
+
├── parser.py # STEP-XML parsing engine (~2800 lines)
|
|
323
|
+
├── creator.py # STEP-XML document generator
|
|
324
|
+
├── upload.py # Asset binary upload/download via REST API
|
|
325
|
+
├── rest_client/ # REST API v2 typed wrapper layer
|
|
326
|
+
│ ├── __init__.py
|
|
327
|
+
│ ├── client.py # StepRestClient (grouped operation wrappers)
|
|
328
|
+
│ ├── base.py # BaseOperation, handle_rest_errors
|
|
329
|
+
│ ├── exceptions.py
|
|
330
|
+
│ ├── models/ # Pydantic models (20 files)
|
|
331
|
+
│ └── operations/ # Operation groups (22 files)
|
|
332
|
+
└── model/ # STEP-XML object models (BaseObject)
|
|
333
|
+
|
|
334
|
+
docs/
|
|
335
|
+
├── AGENTS.md
|
|
336
|
+
├── REST_API_STATE.md, REST_API_USAGE.md
|
|
337
|
+
├── PARSER_STATUS.md, PARSER_USAGE.md
|
|
338
|
+
├── CREATOR_STATUS.md, CREATOR_USAGE.md
|
|
339
|
+
└── INBOUND_OPERATIONS_SUMMARY.md
|
|
340
|
+
|
|
341
|
+
examples/
|
|
342
|
+
├── step_products_only.xml, step_assets_only.xml
|
|
343
|
+
├── step_products_assets_refs.xml, step_asset_pixxio.xml
|
|
344
|
+
|
|
345
|
+
tests/
|
|
346
|
+
├── __init__.py
|
|
347
|
+
├── test.py # Manual connectivity script
|
|
348
|
+
├── test_parser_phaseX_*.py # Parser phase tests
|
|
349
|
+
├── test_rest_client_phaseX_*.py # REST client tests
|
|
350
|
+
├── test_creator_*.py # Creator tests
|
|
351
|
+
├── test_inbound_*.py # Inbound endpoint tests
|
|
352
|
+
└── validate_xml_xsd.py # XSD validation
|
|
353
|
+
|
|
354
|
+
## Development
|
|
355
|
+
|
|
356
|
+
### Build & Test
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Install development dependencies
|
|
360
|
+
pip install -r requirements.txt
|
|
361
|
+
pip install -r requirements-release.txt
|
|
362
|
+
|
|
363
|
+
# Build wheel package
|
|
364
|
+
./build_wheel.bat # Windows
|
|
365
|
+
# or
|
|
366
|
+
python -m build # Cross-platform; creates an sdist and a wheel from that sdist
|
|
367
|
+
|
|
368
|
+
# Run the unit test suite
|
|
369
|
+
python -m unittest discover -s tests -p "test_*.py"
|
|
370
|
+
|
|
371
|
+
# Optional: validate if STEP.xsd has been obtained from Stibo Systems
|
|
372
|
+
python tests/validate_xml_xsd.py
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
The distribution does not include Stibo Systems' OpenAPI specification or XML schema. The REST client fetches the OpenAPI specification from the configured STEP server by default; alternatively, supply a licensed specification using `openapi_file`. Obtain the STEP XSD separately from Stibo Systems if you want to run schema validation.
|
|
376
|
+
|
|
377
|
+
### Publishing to PyPI
|
|
378
|
+
|
|
379
|
+
The PyPI package is `stepxmlclient`, maintained by **everleah**
|
|
380
|
+
(`everleah@hansch.info`). The first successful upload creates the PyPI project;
|
|
381
|
+
the owner is the PyPI account that issued the upload token, not the author
|
|
382
|
+
metadata. Sign in as `everleah`, verify the account email and enable PyPI's
|
|
383
|
+
required two-factor authentication before creating a token.
|
|
384
|
+
|
|
385
|
+
From the repository root, using your Python environment:
|
|
386
|
+
|
|
387
|
+
```powershell
|
|
388
|
+
.\.venv\Scripts\python.exe -m pip install -r requirements-release.txt
|
|
389
|
+
|
|
390
|
+
# Once: enter a NEW token locally at the hidden prompt, never in chat or a command.
|
|
391
|
+
.\upload_wheel_to_pypi.bat --configure-token
|
|
392
|
+
|
|
393
|
+
# Build and validate only; does not contact the upload endpoint.
|
|
394
|
+
.\upload_wheel_to_pypi.bat --check-only
|
|
395
|
+
|
|
396
|
+
# Publish the freshly built and checked wheel AND source distribution.
|
|
397
|
+
.\upload_wheel_to_pypi.bat
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Cross-platform equivalents are `python publish_pypi.py --configure-token`,
|
|
401
|
+
`python publish_pypi.py --check-only`, and `python publish_pypi.py --publish`.
|
|
402
|
+
Without an action, the Python script only builds and checks.
|
|
403
|
+
|
|
404
|
+
- Tokens are saved by `keyring` in the local OS credential store (Windows
|
|
405
|
+
Credential Manager on Windows), never in the repository or a `.pypirc`.
|
|
406
|
+
The existing Forgejo credentials remain separate; Forgejo uses the shared
|
|
407
|
+
modern build script when it needs to build a wheel.
|
|
408
|
+
- Revoke any token previously shared in chat. An account-wide token is needed
|
|
409
|
+
for a new project. After the first upload, replace it with a token scoped to
|
|
410
|
+
`stepxmlclient` by running `--configure-token` again.
|
|
411
|
+
- Every release uses an isolated build, builds the wheel from the sdist, checks
|
|
412
|
+
metadata with `twine check --strict`, and rejects specifications and credential
|
|
413
|
+
files in either archive. Only the two newly checked files are uploaded.
|
|
414
|
+
- Validated artifacts are retained in `dist\pypi\<version>`. Old files elsewhere
|
|
415
|
+
in `dist` are not uploaded. Failures return a nonzero exit code; existing
|
|
416
|
+
PyPI versions are not silently skipped.
|
|
417
|
+
- Before subsequent releases, update `project.version` in `pyproject.toml`,
|
|
418
|
+
run the relevant tests, and run `--check-only`. PyPI releases cannot be
|
|
419
|
+
overwritten; use a new version for changed content.
|
|
420
|
+
- To remove the locally saved token:
|
|
421
|
+
`python -m keyring delete https://upload.pypi.org/legacy/ __token__`.
|
|
422
|
+
|
|
423
|
+
### Architecture Highlights
|
|
424
|
+
|
|
425
|
+
**Parser Architecture**:
|
|
426
|
+
- Stateful parser maintains separate typed lists (products, assets, classifications, etc.)
|
|
427
|
+
- Namespace-aware tag handling with `_get_local_tag()` for robust XML processing
|
|
428
|
+
- Parser functions strictly named `_parse_<element_name>()` for consistency
|
|
429
|
+
- Boolean conversion with `_str_to_bool()` for XML "true"/"false" strings
|
|
430
|
+
- ~80% STEP-XML schema coverage across 14 phases
|
|
431
|
+
|
|
432
|
+
**Creator Architecture**:
|
|
433
|
+
- BaseObject declarative model with `_TAG_NAME`, `_GROUP_NAME`, `_ATTRIBUTE_NAMES`, `_TEXT_NAMES`, `_CHILDREN_NAMES`
|
|
434
|
+
- Auto-serialization via `to_element()` based on model configuration
|
|
435
|
+
- Automatic routing of objects to correct collection lists via `_GROUP_NAME`
|
|
436
|
+
- Support for 20+ entity types with full relationship mapping
|
|
437
|
+
|
|
438
|
+
**REST Client**:
|
|
439
|
+
- Wraps `requests-openapi` for type-safe API calls
|
|
440
|
+
- Basic authentication with configurable SSL/proxy support
|
|
441
|
+
- OpenAPI specification caching for improved performance
|
|
442
|
+
- No method wrappers—access underlying client directly
|
|
443
|
+
|
|
444
|
+
### Key Patterns
|
|
445
|
+
|
|
446
|
+
**XML Namespace Handling**:
|
|
447
|
+
```python
|
|
448
|
+
from stepxmlclient import STEPXML_NS
|
|
449
|
+
|
|
450
|
+
# Use namespace dictionary for find operations
|
|
451
|
+
element.find('Products', STEPXML_NS)
|
|
452
|
+
element.findall('Product', STEPXML_NS)
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Model Class Configuration**:
|
|
456
|
+
```python
|
|
457
|
+
from stepxmlclient.model import BaseObject
|
|
458
|
+
|
|
459
|
+
class MyEntity(BaseObject):
|
|
460
|
+
_GROUP_NAME = 'my_entities' # Collection name in Creator
|
|
461
|
+
_TAG_NAME = 'MyEntity' # XML element tag name
|
|
462
|
+
_ATTRIBUTE_NAMES = ("ID", "UserTypeID") # XML attributes
|
|
463
|
+
_TEXT_NAMES = ("Name",) # Child text elements
|
|
464
|
+
_CHILDREN_NAMES = ("Values",) # Ordered child elements
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
**Parser Function Pattern**:
|
|
468
|
+
```python
|
|
469
|
+
def _parse_my_entity(element: ET.Element) -> dict:
|
|
470
|
+
"""Parse MyEntity element into dictionary."""
|
|
471
|
+
data = {}
|
|
472
|
+
# Extract attributes
|
|
473
|
+
data['ID'] = element.get('ID')
|
|
474
|
+
# Extract text content
|
|
475
|
+
name_elem = element.find('Name', STEPXML_NS)
|
|
476
|
+
if name_elem is not None:
|
|
477
|
+
data['Name'] = name_elem.text
|
|
478
|
+
# Process children
|
|
479
|
+
data['Values'] = self._parse_item_list(element, 'Value', self._parse_value)
|
|
480
|
+
return data
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Testing Strategy
|
|
484
|
+
|
|
485
|
+
The project uses a phased testing approach with all test modules under `tests/`:
|
|
486
|
+
- **Primary coverage**: phase suites (`tests/test_parser_phaseX_*.py`, `tests/test_rest_client_phaseX_*.py`) plus focused `tests/test_*.py` modules
|
|
487
|
+
- **Utility script**: `tests/test.py` is a simple manual connectivity/example script
|
|
488
|
+
- **Phase tests**: `tests/test_parser_phaseX_*.py` target specific entity types
|
|
489
|
+
- **Validation**: `tests/validate_xml_xsd.py` checks generated XML when an authorized STEP XSD is available locally
|
|
490
|
+
- **Roundtrip tests**: `tests/test_creator_roundtrip.py` parses generated XML
|
|
491
|
+
|
|
492
|
+
When adding new functionality:
|
|
493
|
+
1. Extend existing phase test or create new `tests/test_parser_phaseX_*.py`
|
|
494
|
+
2. Add corresponding model class in `stepxmlclient/model/`
|
|
495
|
+
3. Add parser function in `stepxmlclient/parser.py`
|
|
496
|
+
4. Optionally add creator support in `stepxmlclient/creator.py`
|
|
497
|
+
5. Validate with `tests/validate_xml_xsd.py`
|
|
498
|
+
|
|
499
|
+
## Configuration
|
|
500
|
+
|
|
501
|
+
### REST API Client
|
|
502
|
+
|
|
503
|
+
```python
|
|
504
|
+
from stepxmlclient.client import StiboStepRestClient, BasicAuthorisation
|
|
505
|
+
|
|
506
|
+
# Standard configuration
|
|
507
|
+
auth = BasicAuthorisation('username', 'password')
|
|
508
|
+
client = StiboStepRestClient(
|
|
509
|
+
'https://your-step-server.com/restapiv2',
|
|
510
|
+
auth
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Development - disable SSL verification
|
|
514
|
+
client = StiboStepRestClient(..., nocert=True)
|
|
515
|
+
|
|
516
|
+
# Or create 'nocert' file in working directory to disable SSL globally
|
|
517
|
+
# Production - proper certificates handled by OS certificate store
|
|
518
|
+
|
|
519
|
+
# Proxy support
|
|
520
|
+
client = StiboStepRestClient(
|
|
521
|
+
...,
|
|
522
|
+
proxies={'http': 'proxy.company.com:8080',
|
|
523
|
+
'https': 'proxy.company.com:8080'}
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
# OpenAPI caching for better performance
|
|
527
|
+
client = StiboStepRestClient(
|
|
528
|
+
...,
|
|
529
|
+
cache_openapi=True
|
|
530
|
+
# Creates/uses 'openapi.json' in working directory
|
|
531
|
+
)
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### XML Parsing Configuration
|
|
535
|
+
|
|
536
|
+
```python
|
|
537
|
+
from stepxmlclient.parser import Parser
|
|
538
|
+
|
|
539
|
+
parser = Parser()
|
|
540
|
+
|
|
541
|
+
# Parse from file
|
|
542
|
+
parser.parse_file('data.xml')
|
|
543
|
+
|
|
544
|
+
# Parse from string
|
|
545
|
+
parser.parse_str(xml_string)
|
|
546
|
+
|
|
547
|
+
# Access results
|
|
548
|
+
products = parser.products
|
|
549
|
+
classifications = parser.classifications
|
|
550
|
+
# ... all 20+ entity types
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### XML Creation Configuration
|
|
554
|
+
|
|
555
|
+
```python
|
|
556
|
+
from stepxmlclient.creator import Creator
|
|
557
|
+
|
|
558
|
+
# Specify context and workspace
|
|
559
|
+
creator = Creator(
|
|
560
|
+
context_id='YourContext',
|
|
561
|
+
workspace_id='Main' # Default: 'Main'
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
# Generate XML with specific encoding
|
|
565
|
+
creator.build()
|
|
566
|
+
xml_bytes = creator.to_bytes(encoding='utf-8')
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## Roadmap
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
### REST API v2 Client (22 operation groups)
|
|
573
|
+
|
|
574
|
+
The typed wrappers cover the operations documented in the STEP REST API specification.
|
|
575
|
+
See [docs/REST_API_STATE.md](docs/REST_API_STATE.md) for the full coverage matrix.
|
|
576
|
+
|
|
577
|
+
### ✅ Parser - Complete (Phase 14, ~80% coverage)
|
|
578
|
+
|
|
579
|
+
**Implemented**:
|
|
580
|
+
- Core entities: Products, Assets, Classifications, Entities
|
|
581
|
+
- Attributes system: Attributes, AttributeGroups, ListOfValues
|
|
582
|
+
- Configuration: Contexts, Qualifiers, Dimensions, LinkTypes, UserTypes
|
|
583
|
+
- Metadata: Tags, TagGroups, Units
|
|
584
|
+
- Advanced: BusinessRules, Workflows, Collections
|
|
585
|
+
- Operations: Deletion, Replacement Rules
|
|
586
|
+
- Relations: All cross-reference types (Asset, Product, Classification, Entity)
|
|
587
|
+
|
|
588
|
+
**Next**: Remaining 20% of STEP-XML schema (minor/specialized elements)
|
|
589
|
+
|
|
590
|
+
### 🔄 Creator - Phase 1 Complete, Expanding (~10% coverage)
|
|
591
|
+
|
|
592
|
+
**Phase 1 Complete (Core Entities)**:
|
|
593
|
+
- ✅ Products with all attributes and cross-references
|
|
594
|
+
- ✅ Assets with key values and cross-references
|
|
595
|
+
- ✅ All cross-reference types
|
|
596
|
+
- ✅ Deletion operations
|
|
597
|
+
- ✅ Product replacement rules
|
|
598
|
+
|
|
599
|
+
**Phase 2 Planning (Attributes & Classification)**:
|
|
600
|
+
- Classifications and hierarchies
|
|
601
|
+
- Attributes and AttributeGroups
|
|
602
|
+
- ListOfValues with proper associations
|
|
603
|
+
|
|
604
|
+
**Future Phases**:
|
|
605
|
+
- Entities and EntityTypes
|
|
606
|
+
- Tags, Units, and Metadata
|
|
607
|
+
- Workflows and BusinessRules
|
|
608
|
+
- Collections and CollectionGroups
|
|
609
|
+
- Full parity with Parser coverage
|
|
610
|
+
|
|
611
|
+
### Current Status Summary
|
|
612
|
+
- **REST API v2 Client**: 22 operation groups for STEP REST API v2
|
|
613
|
+
- **Parser**: Supports the documented STEP-XML entity types for data export and analysis
|
|
614
|
+
- **Creator**: Core functionality complete, suitable for basic import scenarios
|
|
615
|
+
- **Testing**: Extensive phase-based test coverage with unit and integration tests
|
|
616
|
+
|
|
617
|
+
For detailed phase status, see:
|
|
618
|
+
- [docs/PARSER_STATUS.md](docs/PARSER_STATUS.md)
|
|
619
|
+
- [docs/CREATOR_STATUS.md](docs/CREATOR_STATUS.md)
|
|
620
|
+
- [docs/REST_API_USAGE.md](docs/REST_API_USAGE.md)
|
|
621
|
+
- [docs/REST_API_STATE.md](docs/REST_API_STATE.md)
|
|
622
|
+
|
|
623
|
+
## Core References
|
|
624
|
+
|
|
625
|
+
### STEP Schema
|
|
626
|
+
|
|
627
|
+
The STEP XML schema is provided by Stibo Systems and is not included in this distribution. Obtain an authorized copy from Stibo Systems for schema reference or validation.
|
|
628
|
+
|
|
629
|
+
### Documentation
|
|
630
|
+
- [PARSER_STATUS.md](docs/PARSER_STATUS.md) - Detailed parser feature coverage and phase breakdown
|
|
631
|
+
- [CREATOR_STATUS.md](docs/CREATOR_STATUS.md) - Creator implementation status and expansion roadmap
|
|
632
|
+
- [PARSER_USAGE.md](docs/PARSER_USAGE.md) - Parser implementation guide and patterns
|
|
633
|
+
- [CREATOR_USAGE.md](docs/CREATOR_USAGE.md) - Creator implementation guide and patterns
|
|
634
|
+
|
|
635
|
+
### Requirements
|
|
636
|
+
|
|
637
|
+
- Python 3.9+
|
|
638
|
+
- requests-openapi - OpenAPI client generation
|
|
639
|
+
- requests - HTTP library
|
|
640
|
+
- xml.etree.ElementTree (built-in)
|
|
641
|
+
|
|
642
|
+
## Contributing
|
|
643
|
+
|
|
644
|
+
When extending functionality:
|
|
645
|
+
1. **Parser**: Add `_parse_<element>()` function, create phase test in `test_parser_phaseX_*.py`
|
|
646
|
+
2. **Model**: Extend `BaseObject` with declarative configuration per project conventions
|
|
647
|
+
3. **Creator**: Implement serialization in model class `to_element()` method
|
|
648
|
+
4. **Schema**: Validate against a locally available, authorized STEP XSD when applicable
|
|
649
|
+
5. **Tests**: Ensure coverage with roundtrip parsing + XSD validation
|
|
650
|
+
|
|
651
|
+
Follow established patterns from:
|
|
652
|
+
- Existing parser functions in [stepxmlclient/parser.py](stepxmlclient/parser.py)
|
|
653
|
+
- Model classes in [stepxmlclient/model/](stepxmlclient/model/)
|
|
654
|
+
- Phase tests in [tests/](tests/)
|
|
655
|
+
|
|
656
|
+
## License
|
|
657
|
+
|
|
658
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE).
|
|
659
|
+
|
|
660
|
+
## Security
|
|
661
|
+
|
|
662
|
+
Please report suspected vulnerabilities privately to [everleah@hansch.info](mailto:everleah@hansch.info) rather than opening a public issue.
|
|
663
|
+
|
|
664
|
+
## Maintainer
|
|
665
|
+
|
|
666
|
+
Everleah — [everleah@hansch.info](mailto:everleah@hansch.info)
|