Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.
First time visiting? Here are some places to start:- Looking for a certain topic? Check out the categories filter or use Search (upper right).
- Need support? Ask a question to our Community Support category.
- Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
- Be respectful, on topic and if you see a problem, Flag it.
If you would like to contact our Community Manager personally, feel free to send a private message or an email.
Geometric Variants using API, onshape-client
fluvio_lobo_fenoglietto
Member Posts: 36 PRO
@ethan_keller924
I am finally trying to get back to this project we started about a year ago!
https://forum.onshape.com/discussion/11860/geometric-variants-derivatives-using-onshapepy-api
I was trying to get familiar with the onshape-client repo., but I am afraid I may be a little rusty.
Our code accesses a document, changes some configurations, and exports an .STL
I want to make sure we can do the same thing with onshape_clients.
Here are a few sections of the module where you could, perhaps, just point our the basic changes.
Here is the function we created to define the client
Your help is much appreciated!
I am finally trying to get back to this project we started about a year ago!
https://forum.onshape.com/discussion/11860/geometric-variants-derivatives-using-onshapepy-api
I was trying to get familiar with the onshape-client repo., but I am afraid I may be a little rusty.
Our code accesses a document, changes some configurations, and exports an .STL
I want to make sure we can do the same thing with onshape_clients.
Here are a few sections of the module where you could, perhaps, just point our the basic changes.
Here is the function we created to define the client
def connect_to_sketch( self, args ):
'''
CONNECT TO ONSHAPE DOCUMENT
'''
print('[{:0.6f}] Connecting to Onshape document'.format(current_time( self )))
if( len(self.did) != 24 or # Ensure inputted IDs are valid
len(self.wid) != 24 or # ...
len(self.eid) != 24 ): # ...
raise ValueError( "Document, workspace, and element IDs must each be 24 characters in length" )
else:
part_URL = "https://cad.onshape.com/documents/{}/w/{}/e/{}".format( self.did, self.wid, self.eid )
self.myPart = Part( part_URL ) # Connect to part for modification
self.c = Client() # Create instance of the onshape client for exporting
<br>Here is our function for exporting the STLdef export_stl( self ):
'''
EXPORT STL OF GENERATED PART/VARIANT
'''
print('[{:0.6f}] Export new configurations from Onshape'.format(current_time( self )))
variant_iter = self.variant_iter
partname = self.partname
dest = self.dst
stl = self.c._api.request('get','/api/partstudios/d/{}/w/{}/e/{}/stl'.format(self.did, self.wid, self.eid))
stl_filename = ('{}{}_var{}.stl'.format(dest, partname, variant_iter))
with open( stl_filename, 'w' ) as f: # Write STL to file
f.write( stl.text )
self.stl_filename = stl_filename Your help is much appreciated!
Tagged:
1
Comments
When I execute this, I get the following error;
<div>onshape_client.oas.exceptions.ApiException: (404)</div><div>Reason: Not Found</div><div>HTTP response headers: HTTPHeaderDict({'Server': 'nginx', 'Date': 'Thu, 13 Aug 2020 15:50:13 GMT', 'Content-Type': 'application/json;charset=utf-8', 'Content-Length': '84', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'On-Version': '1.117.25799.ec2b15afb7f4', 'On-Request-Id': '38e3bed0508d9712b49878ed', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block'})</div><div>HTTP response body: b'{\n "moreInfoUrl" : "",\n "message" : "Not found.",\n "status" : 404,\n "code" : 0\n}'</div>What is the best way of creating an OnshapeElement so that I can pass the right structure to the "part_studio_api" functions?I was able to correct this on my program.
I also found another forum post that discussed how to use OnshapeElement() so my latest program looks like this;
# modules, libraries from onshape_client import OnshapeElement, Client # variables config_filename = '.onshape_client_config.yaml' # onshape variables did = '4106f8fea9cf4607edeba1db' wid = 'c11cf0ae6ab5e6297d09562d' eid = '3340d6f3b50b6e32e22d9a3b' # do things client = Client( config_filename ) # create client element = OnshapeElement('https://cad.onshape.com/documents/{}/w/{}/e/{}'.format(did,wid,eid)) response = client.part_studios_api.export_stl1(element.did, element.wvm, element.wvmid, element.eid, _preload_content=False)Now (of course) I have different problems;
If I run the code above, I get this error
Which I believe has to do with a mismatch between the base url on the config. file (.yaml) and the url I use for the OnshapeElement function.
To solve this, I test and "fix" this I changed the address on the config file to;
The code then ran without errors, but nothing exports and writing the .STL data from the response does not generate a valid geometry file.
I am using this code for writing the response into a .STL file
file = 'out.stl' with open(file, 'wb') as f: f.write(response.data)So I am stuck again
I believe the issue is your base_url should be "https://cad.onshape.com" instead of "https://cad.onshape.com/documents". The end point for STL export is "https://cad.onshape.com/api/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/stl". The way you have it written now I believe will make a call to "https://cad.onshape.com/documents/api/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/stl" which I believe will return 404 html page.
I'm no python export, so I may be misinterpreting the code, but the STL export endpoint requires a redirect to download. What I am assuming is happening is the malformed link is giving null for a redirect URL, which the python script is following and getting an empty response.
Thanks for the response and sorry for the delay.
Correct me if I am wrong, but I think there are two ways of solving this issue. I just want to understand both so that I can 'scale-up'
First, the semi-hardcoded way, where I just have python construct the URL and send the request via the webbrowser library.
# modules import webbrowser # onshape variables did = '4106f8fea9cf4607edeba1db' wid = 'c11cf0ae6ab5e6297d09562d' eid = '3340d6f3b50b6e32e22d9a3b' # do things webbrowser.open_new('https://cad.onshape.com/api/partstudios/d/{}/w/{}/e/{}/stl?'.format(did,wid,eid))Here I do not need to use the API functions at all.However, can anyone else run this script and download the STL?
Do other users need to have an API key?
Second, the api way, where I actually use the Onshape API to do this, is where I am having most of my issues... Here is what I have so far;
# modules from onshape_client import OnshapeElement, Client # variables config_filename = '.onshape_client_config.yaml' did = '4106f8fea9cf4607edeba1db' wid = 'c11cf0ae6ab5e6297d09562d' eid = '3340d6f3b50b6e32e22d9a3b' # do things client = Client( config_filename ) # create client element = OnshapeElement('https://cad.onshape.com/documents/{}/w/{}/e/{}'.format(did,wid,eid)) # create onshape element response = client.part_studios_api.export_stl1(element.did, element.wvm, element.wvmid, element.eid, _preload_content=False)I think my problem is understanding the need and proper use of the OnshapeElement and client.part_studios_api.export_stl1() functions.
If I OnshapeElement as shown above and print the values element.did, wvm, ...etc, I get the right values.
Still, when I use the client.part_studios_api.export_stl1() function, I now get this error;
onshape_client.oas.exceptions.ApiException: (404) Reason: HTTP response headers: HTTPHeaderDict({'Server': 'nginx', 'Date': 'Thu, 20 Aug 2020 15:45:39 GMT', 'Content-Type': 'text/html;charset=utf-8', 'Content-Length': '789', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'Last-Modified': 'Mon, 17 Aug 2020 16:27:55 GMT', 'ETag': 'W/"eQBDZHccMAEeQBCFIojmew"', 'Cache-Control': 'no-cache', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block'}) HTTP response body: b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">\n\n<html>\n<head>\n <meta http-equiv="Refresh" content="5; url=/">\n <title>www.onshape.com</title>\n <link rel="shortcut icon" type="image/ico" href="/favicon.ico" />\n</head>\n<body class="page-rec">\n <div id="wrapper">\n <div id="content" style="padding:100px;">\n <div style="padding: 10px; -moz-border-radius: 5px 5px 5px 5px; background: -moz-linear-gradient(center top, rgb(255, 249, 204) 0%, rgb(255, 237, 116) 100% ) repeat scroll 0pt 0pt transparent; font-size: 26pt; font-family: \'QuicksandBook\', Helvetica, Arial, sans-serif; text-shadow: 1px 1px 1px rgb(255, 255, 255); line-height: 1.2em; width: 730px;">\n Access denied. Click <a href="/">here</a> to go to home page.\n </div>\n </div>\n </div>\n</body>\n</html>\n'What is the proper way of using these functions?
https://github.com/onshape-public/onshape-clients/blob/0a3fa9c73e64bf6c2451a98a4c0677a0e222eca6/python/test/test_part_studios_api.py#L48
so given the error is "Access denied" I would check if your credentials match the user who has access to that document. Note that "export" permission has not been granted on that doc to anyone other than the owner as far as I can see.
Personally I found that onshape_clients was too complex to understand when debugging and unfinished (_preload_content=False.....) and just wrote my own wrapper to do the few API calls I needed using requests.
Can you elaborate on this;
Also,
Would you mind sharing an example function for how you handle requests directly?
I was trying using client.api_client.request() earlier, with 'POST' and URL as the inputs, but I get the a different error.
Here is my call;
client.api_client.request('POST','https://cad.onshape.com/api/partstudios/d/{}/w/{}/e/{}/stl?'.format(did,wid,eid))With the error;
Traceback (most recent call last): File "C:\Users\WOLF512\AppData\Local\Programs\Python\Python38-32\lib\urllib\parse.py", line 905, in urlencode if len(query) and not isinstance(query[0], tuple): TypeError: object of type 'NoneType' has no len()Thank you!
Can you sign into Onshape then go to `https://cad.onshape.com/api/users/apikeys` and validate that the API key you have set there is showing? If not, then you will have to generate/switch out the key/secret pair.
NOTE:
I know you haven't, but even while triaging issues like this, under no circumstance ever post your secret key and make sure all important data is sanitized before posting here.
This call is a `GET` not a `POST`. The error looks like a check that you are doing a `POST` with no body. If you do a `GET`, you should be getting back a redirect URL to follow to the get the STL.
<font face="Flama, sans-serif">@</font>fluvio_lobo_fenoglietto When I went to the <a href="https://cad.onshape.com/documents/4106f8fea9cf4607edeba1db/w/c11cf0ae6ab5e6297d09562d/e/3340d6f3b50b6e32e22d9a3b" title="Link: https://cad.onshape.com/documents/4106f8fea9cf4607edeba1db/w/c11cf0ae6ab5e6297d09562d/e/3340d6f3b50b6e32e22d9a3b">URL</a> and right clicked on Part1 there was no "Export" option. I just tried it again and it now has an export option so do not know what happened.<br><br>I can't share any code at current since not in a useful (standalone) state - sorry.<br><br> My configuration file is now;
I just created a new set of keys.
When I follow the link https://cad.onshape.com/api/users/apikeys, the accessKey is displayed and the secretKey is shown as null
Either way, I get the same error... which I think refers to how I am structuring the request...?
Traceback (most recent call last): File "C:\Users\WOLF512\AppData\Local\Programs\Python\Python38-32\lib\urllib\parse.py", line 905, in urlencode if len(query) and not isinstance(query[0], tuple): TypeError: object of type 'NoneType' has no len()...I also took a side step and tried using the python requests module. I think there is something fundamental that I am not understanding about requests (in general). The following code is, again, an attempt to send the same STL request...
# modules import requests import json from onshape_client import OnshapeElement, Client # variables config_filename = '.onshape_client_config.yaml' did = '4106f8fea9cf4607edeba1db' wid = 'c11cf0ae6ab5e6297d09562d' eid = '3340d6f3b50b6e32e22d9a3b' # do things client = Client( config_filename ) response = requests.get( 'https://cad.onshape.com/api/partstudios/d/{}/w/{}/e/{}/stl'.format(did,wid,eid), params=client.configuration.api_key )Here I am using onshape-client so I can extract the api_keys and pass them as payload in the GET request...But I still get a 401 response...
{'message': 'Unauthenticated API request', 'status': 401}Using the requests module, what is the best way of sending credentials to be able to execute the request?Here is the working code:
# modules from onshape_client import OnshapeElement, Client # variables config_file = '.onshape_client_config.yaml' # configuration file did = '4106f8fea9cf4607edeba1db' # did wid = 'c11cf0ae6ab5e6297d09562d' # wid eid = '3340d6f3b50b6e32e22d9a3b' # eid # do things client = Client( keys_file=config_file ) # create client using the specified configuration file element = OnshapeElement('https://cad.onshape.com/documents/{}/w/{}/e/{}'.format(did,wid,eid)) # create onshape element response = client.part_studios_api.export_stl1(did, 'w', wid, eid, _preload_content=False) # writing STL file with open( '{}.stl'.format(element.name), 'wb' ) as file: file.write(response.data) file.close()The program is not completely optimized and a little redundant, but it works!
The issue I was having was resolved by the _preload_content = False input.
I was not aware that the "redirect warning" was just a "warning" instead of an error