def import_item(self, import_item): did = self.onshape_element.did wid = self.onshape_element.wvmid path = write_to_file(import_item["file"]) eid = import_file(path, did, wid) onshape_element = self.onshape_element onshape_element.eid = eid url = onshape_element.get_url() mass_properties = Client.get_client().part_studios_api.get_mass_properties(did, 'w', wid, eid) # type: BTMassPropResponse volume = mass_properties.bodies["-all-"].volume[0]*1000000000 bounding_box = Client.get_client().part_studios_api.get_bounding_boxes2(did, 'w', wid, eid, _preload_content=False) data = bounding_box.data if six.PY3: data = data.decode('utf-8') bounding_box = json.loads(data) x_span = (bounding_box["highX"]-bounding_box["lowX"])*1000 y_span = (bounding_box["highY"]-bounding_box["lowY"])*1000 z_span = (bounding_box["highZ"]-bounding_box["lowZ"])*1000 bounding_box = "L = {x_span}, W = {y_span}, H = {z_span}".format(x_span=x_span, y_span=y_span, z_span=z_span) if "part_metadata" in import_item or "element_metadata" in import_item: meta_data_to_be_set = MetaDataBody(OnshapeElement.create_from_ids(did, "w", wid, eid)) if "part_metadata" in import_item: part_metadata = import_item["part_metadata"] # Add the volume part volume property from the API: meta_data_to_be_set.add_to_part_metadata("Part Volume", volume) meta_data_to_be_set.add_to_part_metadata("Bounding Box", bounding_box) for k, v in part_metadata.items(): # For the fixed field items, set for the first part if k != "additionalItems": meta_data_to_be_set.add_to_part_metadata(k, v) else: for custom_metadata_item in v: meta_data_to_be_set.add_to_part_metadata(custom_metadata_item["part_id"], custom_metadata_item["property_name"], custom_metadata_item["new_value"]) if "element_metadata" in import_item: element_metadata = import_item["element_metadata"] for k, v in element_metadata.items(): if k != "additionalItems": meta_data_to_be_set.add_to_element_metadata(k,v) else: for custom_metadata_item in v: meta_data_to_be_set.add_to_element_metadata(custom_metadata_item["property_name"], custom_metadata_item["new_value"], eid=eid) meta_data_to_be_set.send() if "bounding_box" in import_item and import_item["bounding_box"]: feature_path = "bound_all_set_metadata.json" # feature_path = "bound_all_feature.json" # feature_path = "make_cube_feature.json" with open(os.path.dirname(__file__) + "/assets/" + feature_path, "r") as f: body = {"feature": json.loads(f.read())} Client.get_client().part_studios_api.add_feature1(did, "w", wid, eid, body=body)
def create_drawing(self, drawing_name="My Drawing"): """Create a four view drawing of the current element""" if self.wvm != "w": raise UserWarning( "Can only create a drawing in a workspace - not a version." ) drawing = Client.get_client().drawings_api.create_drawing_app_element( bt_drawing_params=BTDrawingParams( document_id=self.did, workspace_id=self.wvmid, drawing_name=drawing_name, element_id=self.eid, views="four", template_document_id="cbe6e776694549b5ba1a3e88", template_workspace_id="24d08acf10234dbc8d3ab585", template_element_id="17eef7862b224f6fb12cbc46", projection="third", hidden_lines="EXCLUDED", is_surface=False, element_configuration="default", is_flattened_part=False, reference_type=1, ) ) drawing = OnshapeElement.create_from_ids(eid=drawing.id, sibling=self) return drawing
def get_client(self): """Start the client if the client isn't already started.""" try: client = Client.get_client(create_if_needed=False) except Exception as e: if self.stack == "STAGE": base_url = "https://staging.dev.onshape.com" token_uri = "https://staging-oauth.dev.onshape.com/oauth/token" authorization_uri = "https://staging-oauth.dev.onshape.com/oauth/authorize" elif self.stack == "DEMOC": base_url = "https://demo-c.dev.onshape.com" token_uri = "https://demo-c-oauth.dev.onshape.com/oauth/token" authorization_uri = "https://demo-c-oauth.dev.onshape.com/oauth/authorize" # PROD stack is default. else: base_url = "https://cad.onshape.com" token_uri = "https://oauth.onshape.com/oauth/token" authorization_uri = "https://oauth.onshape.com/oauth/authorize" client = Client( configuration={ "client_id": self.client_id, "client_secret": self.client_secret, "base_url": base_url, "token_uri": token_uri, "authorization_uri": authorization_uri, "oauth_authorization_method": OAuthAuthorizationMethods.MANUAL_FLOW, "scope": ["OAuth2Read"], "redirect_uri": self.redirect_uri, "access_token": self.access_token, "refresh_token": self.refresh_token }) return client
def _get_configuration_encoding_response(self): res = Client.get_client().elements_api.encode_configuration_map( self.did, self.eid, self._get_bt_configuration_params_for_current_configuration(), _preload_content=False) return json.loads(res.data.decode("utf-8"))
def make_version(name, did): return json.loads(Client.get_client().documents_api.create_version( did, bt_version_or_workspace_params=BTVersionOrWorkspaceParams( name=name + "-" + str(datetime.now()), document_id=did), _preload_content=False, ).data)["id"]
def import_file(file_path, did, wid): """Import a file from the local file system. Returns the URL of the resulting element if translated.""" client = Client.get_client() file = open(file_path, 'rb').read() r = client.blob_elements_api.upload_file_create_element( did, wid, media_type="application/stl", file=file, translate=True, encodedFilename=file_path.split('/')[-1], _preload_content=False) translation_id = get_field(r, 'translationId') print("The translationId is: {}.".format(translation_id)) state = 'ACTIVE' while state == 'ACTIVE': time.sleep(2) r = client.translation_api.get_translation(translation_id, _preload_content=False) state = get_field(r, "requestState") element_id = get_field(r, 'resultElementIds')[0] # Make the actual download when the translation is done, otherwise report the error if state == "DONE": print( "Translated document available at {host}/documents/{did}/w/{wid}/e/{eid}" .format(host=client.configuration.host, did=get_field(r, 'documentId'), wid=get_field(r, 'workspaceId'), eid=element_id)) else: print("An error ocurred on the server! Here is the response: \n") return element_id
def do_POST(self): content_length = int(self.headers['Content-Length']) body = self.rfile.read(content_length) unquoted_s = "" if six.PY2: import urllib unquoted_s = urllib.unquote(body) elif six.PY3: unquoted_s = body.decode('utf-8') data = json.loads(unquoted_s) from onshape_client.oas.models import BTDocumentParams bt_document_params = BTDocumentParams(name=data["doc_name"]) new_doc_response = Client.get_client().documents_api.create11( bt_document_params, _preload_content=False) did = get_field(new_doc_response, "id") wid = get_field(new_doc_response, "defaultWorkspace")["id"] # Use a fake eid because it isn't used later. eid = "00000000000000" self.onshape_element = OnshapeElement.create_from_ids( did, "w", wid, eid) if "import_items" in data: for import_item in data["import_items"]: self.import_item(import_item) self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() content = { "document_href": self.onshape_element.get_url(url_type="document") } self.wfile.write(sendable(json.dumps(content)))
def client() -> Client: """Client needed to make API calls.""" try: client = Client.get_client() except Exception as e: client = Client(stack_key="onshape_client_test") return client
def export_file( self, file_path: Path, bt_translate_format_params: BTTranslateFormatParams ): """Exports the element this class is pointing to""" bt_translate_format_params.element_id = self.eid kwargs = {} kwargs.update( dict( did=self.did, wv=self.wvm, wvid=self.wvmid, eid=self.eid, bt_translate_format_params=bt_translate_format_params, ) ) if self._get_element_info().data_type == OnshapeElement.DRAWING_DATA_TYPE: func = Client.get_client().drawings_api.create_drawing_translation elif self.element_type == "Assembly": func = Client.get_client().assemblies_api.translate_format elif self.element_type == "Part Studio": func = Client.get_client().part_studios_api.create_part_studio_translation else: raise NotImplemented( f"Export for {self.element_type} through the OnshapeElement isn't supported yet." ) result = func(**kwargs) if ( "store_in_document" in bt_translate_format_params.to_dict() and bt_translate_format_params.store_in_document ): return translation_id = result.id result = OnshapeElement.poll_translation_result(translation_id) if result.result_external_data_ids: count = 0 for download_id in result.result_external_data_ids: file_path.write_bytes( Client.get_client() .documents_api.download_external_data( did=self.did, fid=download_id, _preload_content=False ) .data ) count = count+1 file_path.with_name(f"{file_path.name}-{count}")
def create(name="New Document"): """Returns a blank new document.""" client = Client.get_client() doc_params = BTDocumentParams(name=name, is_public=True) doc = client.documents_api.create_document(doc_params) doc = OnshapeElement.create_from_ids( did=doc.id, wvm="w", wvmid=doc.default_workspace.id ) return doc
def element_type(self): """ :return:String "APPLICATION" (for a drawing or 3rd party application), "PARTSTUDIO" or "ASSEMBLY" """ elements = Client.get_client().documents_api.get_elements_in_document( self.did, self.wvm, self.wvmid ) for element in elements: if element.id == self.eid: return element.type
def make_version(self, name, **kwargs): result = Client.get_client().documents_api.create_version( self.did, bt_version_or_workspace_params=BTVersionOrWorkspaceParams( name=name, document_id=self.did, **kwargs ), _preload_content=False, ) return self.create_from_ids( wvmid=json.loads(result.data)["id"], wvm="v", sibling=self )
def make_sub_assembly_definition(self, sa_occurrence_path): """Get the AssemblyDefinition representing the subassembly.""" sa = self.get_instance(sa_occurrence_path) result = Client.get_client().assemblies_api.get_assembly_definition( sa["documentId"], 'v', sa["documentVersion"], sa["elementId"], configuration=sa["configuration"], _preload_content=False) return AssemblyDefinition(json.loads(result.data.decode("UTF-8")))
def new_assembly(self, name="Assembly"): asm = Client.get_client().assemblies_api.create_assembly( self.did, self.wvmid, BTModelElementParams(name=name), _preload_content=False) asm = json.loads(asm.data.decode('utf-8')) return OnshapeElement.create_from_ids(did=self.did, wvm='w', wvmid=self.wvmid, eid=asm["id"])
def get_microversion_url(self): """Determine the microversion from the current version/workspace and return the path to that microversion. This will call the API to get the current microversion if the microversion is not already specified.""" if self.optional_microversion: return self.get_url() else: res = Client.get_client().documents_api.get_current_microversion( self.did, self.wvm, self.wvmid, _preload_content=False) microversion = json.loads(res.data.decode("UTF-8"))["microversion"] self.optional_microversion = microversion return self.get_url()
def poll_translation_result(translation_id): def is_polling_done(response): if response.request_state == "DONE": return True elif response.request_state == "ACTIVE": return False raise UserWarning(f"Translation failed") polling_function = lambda: Client.get_client().translation_api.get_translation( translation_id ) return OnshapeElement.poll(polling_function, is_polling_done)
def create_from_ids(did=None, wvm=None, wvmid=None, eid=None, partid=None, configuration=None): client = Client.get_client() url = client.configuration.host + "/documents/" + did + "/" + wvm + "/" + wvmid url = url + "/e/" + eid if eid else url url = url + "?configuration=" + configuration if configuration else url result = OnshapeElement(url) result.partid = partid return result
def get_element_property_name_to_property_id_map(self): """Get the element metadata for the workspace/version and build the map""" client = Client.get_client() property_map = {} response = client.metadata_api.get_wv_es_metadata(self.onshape_element.did, self.onshape_element.wvm, self.onshape_element.wvmid, _preload_content=False) data = json.loads(response.data) for element in data['items']: eid = element['elementId'] property_map[eid] = {} props_to_be_added = property_map[eid] for property in element['properties']: props_to_be_added[property['name']] = property['propertyId'] return property_map
def get_part_property_name_to_property_id_map(self): """Get the part property map for the element in the particular version and build out the property map""" client = Client.get_client() property_map = {} part_index_to_part_id = [] el = self.onshape_element response = client.metadata_api.get_wmve_ps_metadata(el.did, el.wvm, el.wvmid, el.eid, _preload_content=False) data = load_json(response) for i, part in enumerate(data['items']): partId = part['partId'] part_index_to_part_id.append(partId) property_map[partId] = {} props_to_be_added = property_map[partId] for property in part['properties']: props_to_be_added[property['name']] = property['propertyId'] return property_map, part_index_to_part_id
def import_file(self, file_path, translate=True, **kwargs): """Import a file from the local file system. Returns the URL of the resulting element if translated.""" client = Client.get_client() result = client.blob_elements_api.upload_file_create_element( self.did, self.wvmid, file=open(file_path, "rb"), encoded_filename=file_path.name, **kwargs, ) if translate: translation_id = result.translation_id result = OnshapeElement.poll_translation_result(translation_id) element_id = result.result_element_ids[0] else: element_id = result.id return OnshapeElement.create_from_ids(eid=element_id, sibling=self)
def __init__(self, url, *args, **kwargs): self.client = Client.get_client() self.original_url = url parsed_vals = parse(url) self.base_url = parsed_vals.scheme + "://" + parsed_vals.netloc path_list = parsed_vals.path.split('/') self.did = path_list[2] self.wvmid = path_list[4] self.wvm = path_list[3] if len(path_list) > 7: eid = path_list[8] optional_microversion = path_list[6] else: eid = path_list[6] # This is the microversion retrieved from get_microversion_path() and represents a part that is pointing towards # both a version/workspace and a microversion. optional_microversion = None self.eid = eid self.optional_microversion = optional_microversion
def __init__(self, name=None, max_points=1, onshape_element=None): """Initialize the definition of the check""" self.max_points = max_points # The points scored for this check self.points = 0 self.name = name if name else self.__name__ # Start client on the fly if need be. self.client = Client.get_client() # A key value map for template substitutions self.template_context = {"a_test_variable_name": "a test variable value"} self.onshape_element = onshape_element if isinstance(onshape_element, OnshapeElement) or not onshape_element \ else OnshapeElement(onshape_element) self.did = self.onshape_element.did self.wvm = self.onshape_element.wvm self.wvmid = self.onshape_element.wvmid self.eid = self.onshape_element.eid # Whether or not the check passed self.passed = False
def _get_raw_configuration_params(self): response = Client.get_client().elements_api.get_configuration( self.did, self.wvm, self.wvmid, self.eid, _preload_content=False) return json.loads(response.data.decode("utf-8"))
def create_from_ids(did, wvm, wvmid, eid): client = Client.get_client() return OnshapeElement(client.configuration.host + "/documents/" + did + "/" + wvm + "/" + wvmid + "/e/" + eid)
def _get_element_infos(self): return Client.get_client().documents_api.get_elements_in_document( self.did, self.wvm, self.wvmid)
def _get_document_info(self): return Client.get_client().documents_api.get_document(self.did)
def delete(self): Client.get_client().documents_api.delete_document(self.did)
def microversion(self): res = Client.get_client().documents_api.get_current_microversion( self.did, self.wvm, self.wvmid, _preload_content=False) microversion = json.loads(res.data.decode("UTF-8"))["microversion"] return microversion
def element_type(self): elements = Client.get_client().documents_api.get_elements_in_document( self.did, self.wvm, self.wvmid) for element in elements: if element.id == self.eid: return element.type
def request(self, method, url, query_params=None, headers=None, body=None, post_params=None, _preload_content=True, _request_timeout=None): """Perform requests. :param method: http request method :param url: http request url :param query_params: query parameters in the url :param headers: http request headers :param body: request json body, for `application/json` :param post_params: request post parameters, `application/x-www-form-urlencoded` and `multipart/form-data` :param _preload_content: if False, the urllib3.HTTPResponse object will be returned without reading/decoding response data. Default is True. :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of (connection, read) timeouts. """ method = method.upper() assert method in [ 'GET', 'HEAD', 'DELETE', 'POST', 'PUT', 'PATCH', 'OPTIONS' ] if post_params and body: raise ApiValueError( "body parameter cannot be used with post_params parameter.") post_params = post_params or {} headers = headers or {} timeout = None if _request_timeout: if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)): # noqa: E501,F821 timeout = urllib3.Timeout(total=_request_timeout) elif (isinstance(_request_timeout, tuple) and len(_request_timeout) == 2): timeout = urllib3.Timeout(connect=_request_timeout[0], read=_request_timeout[1]) if 'Content-Type' not in headers: headers['Content-Type'] = 'application/json' # Ethan added: add_onshape_specific_headers(method, url, self.configuration, query_params=query_params, headers=headers) try: # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: if query_params: url += '?' + urlencode(query_params) if re.search('json', headers['Content-Type'], re.IGNORECASE): request_body = None if body is not None: request_body = json.dumps(body) r = self.pool_manager.request( method, url, body=request_body, preload_content=_preload_content, timeout=timeout, headers=headers) elif headers[ 'Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 r = self.pool_manager.request( method, url, fields=post_params, encode_multipart=False, preload_content=_preload_content, timeout=timeout, headers=headers) elif headers['Content-Type'] == 'multipart/form-data': # must del headers['Content-Type'], or the correct # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] r = self.pool_manager.request( method, url, fields=post_params, encode_multipart=True, preload_content=_preload_content, timeout=timeout, headers=headers) # Pass a `string` parameter directly in the body to support # other content types than Json when `body` argument is # provided in serialized form elif isinstance(body, str) or isinstance(body, bytes): request_body = body r = self.pool_manager.request( method, url, body=request_body, preload_content=_preload_content, timeout=timeout, headers=headers) else: # Cannot generate the request from given parameters msg = """Cannot prepare a request message for provided arguments. Please check that your arguments match declared content type.""" raise ApiException(status=0, reason=msg) # For `GET`, `HEAD` else: r = self.pool_manager.request(method, url, fields=query_params, preload_content=_preload_content, timeout=timeout, headers=headers, redirect=False) except urllib3.exceptions.SSLError as e: msg = "{0}\n{1}".format(type(e).__name__, str(e)) raise ApiException(status=0, reason=msg) if _preload_content: r = RESTResponse(r) # TODO: Handle redirections # Ethan added the below clause to handle redirects correctly: if 300 <= r.status <= 399: # parse location location_string = r.getheaders()["Location"] location = urlparse(location_string) new_url = location.scheme + '://' + location.netloc + location.path logger.debug('request redirected to: ' + location_string) parsed_qs = parse_qs(location.query) for q in parsed_qs: parsed_qs[q] = parsed_qs[q][0] return self.request(method, new_url, headers=headers, query_params=parsed_qs, body=body, post_params=post_params, _preload_content=_preload_content, _request_timeout=_request_timeout) if r.status == 403 or r.status == 401: from onshape_client.client import Client client = Client.get_client() if client.get_authentication_method() == "oauth": client.do_oauth_flow() headers['Authorization'] = "Bearer {}".format( client.configuration.access_token) return self.request(method, url, query_params=query_params, headers=headers, body=body, post_params=post_params, _preload_content=_preload_content, _request_timeout=_request_timeout) if not 200 <= r.status <= 299: raise ApiException(http_resp=r) return r