TeeA commited on
Commit
385569a
·
1 Parent(s): 49c8e40
onshape/README.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Onshape API Utilities
2
+
3
+ This module provides utilities for interacting with the Onshape API, including uploading and translating files and downloading translated files.
4
+
5
+ ## Prerequisites
6
+
7
+ 1. Set the following environment variables:
8
+ - `ONSHAPE_ACCESS_KEY`
9
+ - `ONSHAPE_SECRET_KEY`
10
+
11
+ 2. Install required Python packages:
12
+ ```bash
13
+ pip install requests loguru
14
+ ```
15
+
16
+ ## Modules
17
+
18
+ ### `onshape_base.py`
19
+
20
+ Provides the `OnshapeBase` class for shared functionality like authentication and base URL construction.
21
+
22
+ ### `onshape_translation.py`
23
+
24
+ Handles file upload and translation. Supports any file type and export format.
25
+
26
+ #### Example Usage:
27
+ ```python
28
+ from onshape_translation import OnshapeTranslation
29
+
30
+ did = "your_document_id"
31
+ wid = "your_workspace_id"
32
+ file_path = "path_to_your_file"
33
+ format_name = "desired_format" # e.g., "STEP", "IGES", etc.
34
+
35
+ translator = OnshapeTranslation(did, wid, file_path, format_name)
36
+ translator.upload_and_translate()
37
+ ```
38
+
39
+ ### `onshape_download.py`
40
+
41
+ Handles downloading translated files.
42
+
43
+ #### Example Usage:
44
+ ```python
45
+ from onshape_download import OnshapeDownload
46
+
47
+ did = "your_document_id"
48
+ wid = "your_workspace_id"
49
+ eid = "your_element_id" # you can find it in `resultElementIds` when `requestState` of `TranslationStatusResponse` is `DONE`
50
+ output_file = "output_file_name"
51
+
52
+ downloader = OnshapeDownload(did, wid, eid, output_file)
53
+ downloader.download()
54
+ ```
55
+
56
+ ## Logging
57
+
58
+ This module uses `loguru` for logging. Logs will display detailed information about the operations performed.
onshape/onshape_base.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import base64
3
+
4
+
5
+ class OnshapeBase:
6
+ def __init__(self):
7
+ self.access_key = os.environ.get("ONSHAPE_ACCESS_KEY")
8
+ self.secret_key = os.environ.get("ONSHAPE_SECRET_KEY")
9
+ self.base_url = "https://cad.onshape.com/api/v10"
10
+
11
+ if not self.access_key or not self.secret_key:
12
+ raise ValueError(
13
+ "ONSHAPE_ACCESS_KEY and ONSHAPE_SECRET_KEY must be set in environment variables."
14
+ )
15
+
16
+ def get_auth_header(self):
17
+ credentials_raw = f"{self.access_key}:{self.secret_key}"
18
+ credentials_base64 = base64.b64encode(credentials_raw.encode("utf-8")).decode(
19
+ "utf-8"
20
+ )
21
+ return {"Authorization": f"Basic {credentials_base64}"}
onshape/onshape_download.py CHANGED
@@ -1,33 +1,39 @@
1
- import os
2
  import requests
3
- import base64
4
-
5
- access_key = os.environ.get("ONSHAPE_ACCESS_KEY")
6
- secret_key = os.environ.get("ONSHAPE_SECRET_KEY")
7
- did = "ef42d7639096f3e61a4d4f07"
8
- wid = "5fcd0f25ce3dee08bbb823bf"
9
- prt_file_path = "prt0002.prt"
10
- tid = "68382b8879834455c6382294"
11
- resulteid = "c46568af3e8bf618762a1db3"
12
-
13
- # Basic Auth header
14
- credentials_raw = f"{access_key}:{secret_key}"
15
- credentials_base64 = base64.b64encode(credentials_raw.encode("utf-8")).decode("utf-8")
16
-
17
- url = "https://cad.onshape.com/api/v10" + f"/blobelements/d/{did}/w/{wid}/e/{resulteid}"
18
-
19
- headers = {
20
- "Accept": "application/json;charset=UTF-8; qs=0.09",
21
- "Authorization": f"Basic {credentials_base64}",
22
- # "X-XSRF-TOKEN": "QcscTFRgL6vE7h7UFHKmng==",
23
- # DO NOT set Content-Type manually when sending files with requests
24
- }
25
-
26
-
27
- files = {"file": open(prt_file_path, "rb")}
28
-
29
- response = requests.get(url, headers=headers)
30
-
31
- with open("downloaded_file.step", "wb") as f:
32
- f.write(response.content)
33
- print("File downloaded successfully as 'downloaded_file.step'.")
 
 
 
 
 
 
 
 
 
1
  import requests
2
+ from loguru import logger
3
+ from onshape_base import OnshapeBase
4
+
5
+
6
+ class OnshapeDownload(OnshapeBase):
7
+ def __init__(self, did, wid, eid, output_file):
8
+ super().__init__()
9
+ self.did = did
10
+ self.wid = wid
11
+ self.eid = eid
12
+ self.output_file = output_file
13
+
14
+ def download(self):
15
+ url = f"{self.base_url}/blobelements/d/{self.did}/w/{self.wid}/e/{self.eid}"
16
+ headers = {
17
+ "Accept": "application/json;charset=UTF-8; qs=0.09",
18
+ **self.get_auth_header(),
19
+ }
20
+
21
+ logger.info(
22
+ f"Downloading file with element ID '{self.eid}' to '{self.output_file}'."
23
+ )
24
+ response = requests.get(url, headers=headers)
25
+
26
+ with open(self.output_file, "wb") as f:
27
+ f.write(response.content)
28
+ logger.success(f"File downloaded successfully as '{self.output_file}'.")
29
+
30
+
31
+ # Example usage
32
+ if __name__ == "__main__":
33
+ did = "ef42d7639096f3e61a4d4f07"
34
+ wid = "5fcd0f25ce3dee08bbb823bf"
35
+ eid = "fd0dbebc1ac05de1f1d1ed07" # you can find it in `resultElementIds` when `requestState` of `TranslationStatusResponse` is `DONE`
36
+ output_file = "output_file.step"
37
+
38
+ downloader = OnshapeDownload(did, wid, eid, output_file)
39
+ downloader.download()
onshape/onshape_schema.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class TranslationResponse(BaseModel):
5
+ document_id: str = Field(alias="documentId")
6
+ failure_reason: str | None = Field(alias="failureReason", default=None)
7
+ href: str
8
+ id: str
9
+ name: str
10
+ request_element_id: str = Field(alias="requestElementId")
11
+ request_state: str = Field(alias="requestState")
12
+ result_document_id: str = Field(alias="resultDocumentId")
13
+ result_element_ids: list[str] | None = Field(alias="resultElementIds", default=None)
14
+ result_external_data_ids: list[str] | None = Field(
15
+ alias="resultExternalDataIds", default=None
16
+ )
17
+ result_workspace_id: str | None = Field(alias="resultWorkspaceId", default=None)
18
+ version_id: str | None = Field(alias="versionId", default=None)
19
+ view_ref: str | None = Field(alias="viewRef", default=None)
20
+ workspace_id: str = Field(alias="workspaceId")
21
+
22
+
23
+ class TranslationStatusResponse(BaseModel):
24
+ id: str
25
+ request_state: str = Field(alias="requestState")
26
+ request_element_id: str = Field(alias="requestElementId")
27
+ result_external_data_ids: list[str] | None = Field(
28
+ alias="resultExternalDataIds", default=None
29
+ )
30
+ export_rule_file_name: str | None = Field(alias="exportRuleFileName", default=None)
31
+ version_id: str | None = Field(alias="versionId", default=None)
32
+ workspace_id: str = Field(alias="workspaceId")
33
+ document_id: str = Field(alias="documentId")
34
+ result_element_ids: list[str] | None = Field(alias="resultElementIds", default=None)
35
+ result_document_id: str = Field(alias="resultDocumentId")
36
+ failure_reason: str | None = Field(alias="failureReason", default=None)
37
+ result_workspace_id: str | None = Field(alias="resultWorkspaceId", default=None)
38
+ name: str
39
+ href: str
onshape/onshape_translation.py CHANGED
@@ -1,35 +1,96 @@
1
- import os
 
2
  import requests
3
- import base64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- access_key = os.environ.get("ONSHAPE_ACCESS_KEY")
6
- secret_key = os.environ.get("ONSHAPE_SECRET_KEY")
7
- did = "ef42d7639096f3e61a4d4f07"
8
- wid = "5fcd0f25ce3dee08bbb823bf"
9
- prt_file_path = "prt0002.prt"
10
 
11
- # Basic Auth header
12
- credentials_raw = f"{access_key}:{secret_key}"
13
- credentials_base64 = base64.b64encode(credentials_raw.encode("utf-8")).decode("utf-8")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- url = "https://cad.onshape.com/api/v10" + f"/translations/d/{did}/w/{wid}"
 
 
 
 
 
16
 
17
- headers = {
18
- "Accept": "application/json;charset=UTF-8; qs=0.09",
19
- "Authorization": f"Basic {credentials_base64}",
20
- # "X-XSRF-TOKEN": "QcscTFRgL6vE7h7UFHKmng==",
21
- # DO NOT set Content-Type manually when sending files with requests
22
- }
23
 
24
- # All form fields as strings (empty strings '' where appropriate)
25
- data = {"translate": "true", "formatName": "STEP"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- files = {"file": open(prt_file_path, "rb")}
28
 
29
- response = requests.post(url, headers=headers, data=data, files=files)
 
 
 
 
 
30
 
31
- try:
32
- print(f"✅ Translate response: {response.json()}")
33
- except Exception:
34
- print(f"Status: {response.status_code}")
35
- print(response.text)
 
 
 
 
 
 
1
+ import time
2
+
3
  import requests
4
+ from loguru import logger
5
+ from onshape_base import OnshapeBase
6
+ from onshape_schema import TranslationResponse, TranslationStatusResponse
7
+
8
+
9
+ class OnshapeTranslation(OnshapeBase):
10
+ def __init__(self, did: str, wid: str, file_path: str, format_name: str):
11
+ super().__init__()
12
+ self.did = did
13
+ self.wid = wid
14
+ self.file_path = file_path
15
+ self.format_name = format_name
16
+
17
+ def upload_and_translate(self):
18
+ url = f"{self.base_url}/translations/d/{self.did}/w/{self.wid}"
19
+ headers = {
20
+ "Accept": "application/json;charset=UTF-8; qs=0.09",
21
+ **self.get_auth_header(),
22
+ }
23
+ data = {"translate": "true", "formatName": self.format_name}
24
+ files = {"file": open(self.file_path, "rb")}
25
 
26
+ logger.info(
27
+ f"Uploading file '{self.file_path}' for translation to '{self.format_name}' format."
28
+ )
29
+ response = requests.post(url, headers=headers, data=data, files=files)
 
30
 
31
+ try:
32
+ translate_response = response.json()
33
+ if response.status_code != 200:
34
+ logger.error(
35
+ f"Failed to upload file. Status code: {response.status_code}"
36
+ )
37
+ logger.error(response.text)
38
+ raise Exception(
39
+ f"Failed to upload file. Status code: {response.status_code}"
40
+ )
41
+ logger.success(f"Translate response: {translate_response}")
42
+ return TranslationResponse(**translate_response)
43
+ except Exception:
44
+ logger.error(f"Status: {response.status_code}")
45
+ logger.error(response.text)
46
+ raise Exception(
47
+ f"Failed to upload and translate file. Status code: {response.status_code}"
48
+ )
49
 
50
+ def get_translation_status(self, translation_id: str):
51
+ url = f"{self.base_url}/translations/{translation_id}"
52
+ headers = {
53
+ "Accept": "application/json;charset=UTF-8; qs=0.09",
54
+ **self.get_auth_header(),
55
+ }
56
 
57
+ logger.info(f"Checking translation status for ID '{translation_id}'.")
58
+ response = requests.get(url, headers=headers)
 
 
 
 
59
 
60
+ try:
61
+ status = response.json()
62
+ if response.status_code != 200:
63
+ logger.error(
64
+ f"Failed to get translation status. Status code: {response.status_code}"
65
+ )
66
+ logger.error(response.text)
67
+ raise Exception(
68
+ f"Failed to get translation status. Status code: {response.status_code}"
69
+ )
70
+ logger.success(f"Translation status: {status}")
71
+ return TranslationStatusResponse(**status)
72
+ except Exception:
73
+ logger.error(f"Status: {response.status_code}")
74
+ logger.error(response.text)
75
+ raise Exception(
76
+ f"Failed to get translation status. Status code: {response.status_code}"
77
+ )
78
 
 
79
 
80
+ # Example usage
81
+ if __name__ == "__main__":
82
+ did = "ef42d7639096f3e61a4d4f07"
83
+ wid = "5fcd0f25ce3dee08bbb823bf"
84
+ file_path = "onshape/example/prt0002.prt"
85
+ format_name = "STEP"
86
 
87
+ translator = OnshapeTranslation(did, wid, file_path, format_name)
88
+ response = translator.upload_and_translate()
89
+ response = translator.get_translation_status(response.id)
90
+ while response.request_state not in ["DONE", "FAILED"]:
91
+ logger.info(
92
+ f"Waiting for translation to complete. Current state: {response.request_state}"
93
+ )
94
+ response = translator.get_translation_status(response.id)
95
+ time.sleep(3)
96
+ logger.success(f"Translation completed with state: {response.request_state}")