def make_sub_assembly_definition(self, sa_occurrence_path): """Get the AssemblyDefinition representing the subassembly.""" sa = self.get_instance(sa_occurrence_path) 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 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 = 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_configuration_encoding_response(self): res = 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 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 = get_client().drawings_api.create_drawing_translation elif self.element_type == "Assembly": func = get_client().assemblies_api.translate_format elif self.element_type == "Part Studio": func = 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( 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", **kwargs): """Returns a blank new document.""" client = get_client() doc_params = BTDocumentParams(name=name, is_public=True, **kwargs) 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 = 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 new_assembly(self, name="Assembly"): asm = 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 make_version(self, name, **kwargs): result = 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 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: get_client().translation_api.get_translation( translation_id ) return OnshapeElement.poll(polling_function, is_polling_done)
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 = 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 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 = 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 create_from_ids( did=None, wvm=None, wvmid=None, eid=None, partid=None, configuration=None, sibling=None, ): client = get_client() did = did if did else sibling.did wvm = wvm if wvm else sibling.wvm wvmid = wvmid if wvmid else sibling.wvmid 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_raw_configuration_params(self): response = 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 mass_properties(self) -> BTMassPropertiesBulkInfo: return get_client().part_studios_api.get_part_studio_mass_properties( **self._get_DWMVE() )
def delete(self): get_client().documents_api.delete_document(self.did)
def microversion(self): res = 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 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" from onshape_client.client import get_client if get_client().get_authentication_method() == "api_keys": # Ethan added: headers, multipart_boundary = add_onshape_specific_headers( method, url, self.configuration, query_params=query_params, headers=headers) else: multipart_boundary = None headers["Authorization"] = "Bearer {}".format( get_client().configuration.access_token) 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 "multipart/form-data" in headers["Content-Type"]: # must del headers['Content-Type'], or the correct # Content-Type which is 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, multipart_boundary=multipart_boundary, ) # 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) # In the python 3, the response.data is bytes. # we need to decode it to string. if six.PY3: r.data = r.data.decode("utf8") # log response body logger.debug("response body: %s", r.data) # 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 get_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
def _get_document_info(self): return get_client().documents_api.get_document(self.did)
def _get_element_infos(self): return get_client().documents_api.get_elements_in_document( self.did, self.wvm, self.wvmid )