diff --git a/doc/Makefile b/doc/Makefile index 0d1e62ab..8a1d4bcd 100755 --- a/doc/Makefile +++ b/doc/Makefile @@ -2,7 +2,7 @@ # # You can set these variables from the command line. -SPHINXOPTS = -j auto -W --color +SPHINXOPTS = -j auto -W --keep-going SPHINXBUILD = sphinx-build SOURCEDIR = source BUILDDIR = _build diff --git a/doc/changelog.d/454.documentation.md b/doc/changelog.d/454.documentation.md new file mode 100644 index 00000000..db04913b --- /dev/null +++ b/doc/changelog.d/454.documentation.md @@ -0,0 +1 @@ +feat: add type hints \ No newline at end of file diff --git a/doc/source/api/analysis_types.rst b/doc/source/api/analysis_types.rst new file mode 100644 index 00000000..16343b44 --- /dev/null +++ b/doc/source/api/analysis_types.rst @@ -0,0 +1,23 @@ +.. _ref_analysis_types: + +Analysis Types +============== +.. automodule:: ansys.sherlock.core.types.analysis_types +.. currentmodule:: ansys.sherlock.core.types.analysis_types + +Constants +--------- +.. autoclass:: ElementOrder + :members: +.. autoclass:: ModelSource + :members: +.. autoclass:: RunAnalysisRequestAnalysisType + :members: +.. autoclass:: RunStrainMapAnalysisRequestAnalysisType + :members: +.. autoclass:: UpdatePcbModelingPropsRequestAnalysisType + :members: +.. autoclass:: UpdatePcbModelingPropsRequestPcbMaterialModel + :members: +.. autoclass:: UpdatePcbModelingPropsRequestPcbModelType + :members: diff --git a/doc/source/api/common_types.rst b/doc/source/api/common_types.rst index 1c1bf5b4..c5643a80 100644 --- a/doc/source/api/common_types.rst +++ b/doc/source/api/common_types.rst @@ -11,3 +11,5 @@ Constants :members: .. autoclass:: TableDelimiter :members: +.. autoclass:: Measurement + :members: diff --git a/doc/source/api/index.rst b/doc/source/api/index.rst index a59bb895..4a543c9b 100644 --- a/doc/source/api/index.rst +++ b/doc/source/api/index.rst @@ -11,14 +11,15 @@ Use the search feature or click links to view API documentation. :hidden: analysis + analysis_types common common_types launcher layer + layer_types lifecycle model parts - layer_types parts_types project project_types @@ -27,13 +28,15 @@ Use the search feature or click links to view API documentation. .. autosummary:: ansys.sherlock.core.analysis + ansys.sherlock.core.types.analysis_types ansys.sherlock.core.common + ansys.sherlock.core.types.common_types ansys.sherlock.core.launcher ansys.sherlock.core.layer + ansys.sherlock.core.types.layer_types ansys.sherlock.core.lifecycle ansys.sherlock.core.model ansys.sherlock.core.parts - ansys.sherlock.core.types.layer_types ansys.sherlock.core.types.parts_types ansys.sherlock.core.project ansys.sherlock.core.types.project_types diff --git a/pyproject.toml b/pyproject.toml index 561fd3d0..81d9257c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ dependencies = [ "ansys-api-sherlock==0.1.34", - "grpcio>=1.17", + "grpcio>=1.17, <1.68.0", "protobuf>=3.20", "pydantic>=2.9.2", ] diff --git a/src/ansys/sherlock/core/analysis.py b/src/ansys/sherlock/core/analysis.py index 419afe4b..7d6cb497 100644 --- a/src/ansys/sherlock/core/analysis.py +++ b/src/ansys/sherlock/core/analysis.py @@ -1,6 +1,19 @@ # Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module containing all analysis capabilities.""" +from typing import Optional + +import grpc + +from ansys.sherlock.core.types.analysis_types import ( + ElementOrder, + ModelSource, + RunAnalysisRequestAnalysisType, + RunStrainMapAnalysisRequestAnalysisType, + UpdatePcbModelingPropsRequestAnalysisType, + UpdatePcbModelingPropsRequestPcbMaterialModel, + UpdatePcbModelingPropsRequestPcbModelType, +) try: import SherlockAnalysisService_pb2 @@ -12,6 +25,7 @@ from ansys.sherlock.core import LOG from ansys.sherlock.core.errors import ( SherlockGetPartsListValidationAnalysisPropsError, + SherlockNoGrpcConnectionException, SherlockRunAnalysisError, SherlockRunStrainMapAnalysisError, SherlockUpdateHarmonicVibePropsError, @@ -31,7 +45,7 @@ class Analysis(GrpcStub): """Contains all analysis capabilities.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize a gRPC stub for the Sherlock Analysis service.""" super().__init__(channel, server_version) self.stub = SherlockAnalysisService_pb2_grpc.SherlockAnalysisServiceStub(channel) @@ -69,7 +83,7 @@ def __init__(self, channel, server_version): "usePartTempRiseMin": "use_part_temp_rise_min", } - def _translate_field_names(self, names_list): + def _translate_field_names(self, names_list: list[str]) -> list[str]: names = [] for name in list(names_list): names.append(self.FIELD_NAMES.get(name)) @@ -77,7 +91,10 @@ def _translate_field_names(self, names_list): return names @staticmethod - def _add_analyses(request, analyses): + def _add_analyses( + request: SherlockAnalysisService_pb2.RunAnalysisRequest, + analyses: list[tuple[RunAnalysisRequestAnalysisType, tuple[str, str]]], + ): """Add analyses.""" for a in analyses: analysis = request.analyses.add() @@ -92,34 +109,34 @@ def _add_analyses(request, analyses): @require_version() def run_analysis( self, - project, - cca_name, - analyses, - ): + project: str, + cca_name: str, + analyses: list[tuple[RunAnalysisRequestAnalysisType, tuple[str, str]]], + ) -> int: """Run one or more Sherlock analyses. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - analyses : list of ``elements`` + analyses: list of ``elements`` - - elements: list + - elements: list[tuple[RunAnalysisRequestAnalysisType, tuple[str, str]]] Tuples (``type``, ``event``) - - analysis_type : RunAnalysisRequestAnalysisType + - analysis_type: RunAnalysisRequestAnalysisType Type of analysis to run. - - event : list + - event: list[tuple[str, str]] Tuples (``phase_name``, ``event_name``) - - phase_name : str + - phase_name: str Name of the life cycle phase. - - event_name : str + - event_name: str Name of the life cycle event. Returns @@ -166,8 +183,7 @@ def run_analysis( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockAnalysisService_pb2.RunAnalysisRequest( project=project, @@ -189,20 +205,22 @@ def run_analysis( raise e @require_version() - def get_harmonic_vibe_input_fields(self, model_source=None): + def get_harmonic_vibe_input_fields( + self, model_source: Optional[ModelSource] = None + ) -> list[str]: """Get harmonic vibe property fields based on the user configuration. Available Since: 2024R1 Parameters ---------- - model_source : ModelSource, optional + model_source: ModelSource, optional Model source to get the harmonic vibe property fields from. The default is ``None``. Returns ------- - list + list[str] Harmonic vibe property fields based on the user configuration. Examples @@ -221,8 +239,7 @@ def get_harmonic_vibe_input_fields(self, model_source=None): >>> sherlock.analysis.get_harmonic_vibe_input_fields(ModelSource.GENERATED) """ if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() message = SherlockAnalysisService_pb2.GetHarmonicVibeInputFieldsRequest( modelSource=model_source @@ -230,32 +247,30 @@ def get_harmonic_vibe_input_fields(self, model_source=None): response = self.stub.getHarmonicVibeInputFields(message) fields = self._translate_field_names(response.fieldName) - LOG.info(fields) - return fields @require_version() def update_harmonic_vibe_props( self, - project, - harmonic_vibe_properties, - ): + project: str, + harmonic_vibe_properties: list[dict[str, bool | int | float | str]], + ) -> int: """Update properties for a harmonic vibe analysis. Available Since: 2024R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - harmonic_vibe_properties : list + harmonic_vibe_properties: list[dict[str, bool | int | float | str]] Harmonic vibe properties for a CCA consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - model_source: ModelSource Model source. The default is ``None``. - - harmonic_vibe_count : int + - harmonic_vibe_count: int Number of harmonic vibe result layers to generate. The default is ``None``. - harmonic_vibe_damping: str One or more modal damping ratios. The default is ``None``. @@ -361,8 +376,7 @@ def update_harmonic_vibe_props( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.updateHarmonicVibeProps(request) @@ -376,7 +390,8 @@ def update_harmonic_vibe_props( LOG.error(str(e)) raise e - def _set_update_harmonic_vibe_props_request_properties(self, request, harmonic_vibe_properties): + @staticmethod + def _set_update_harmonic_vibe_props_request_properties(request, harmonic_vibe_properties): for i, harmonic_vibe_props in enumerate(harmonic_vibe_properties): if not isinstance(harmonic_vibe_props, dict): raise SherlockUpdateHarmonicVibePropsError( @@ -529,15 +544,16 @@ def _set_update_harmonic_vibe_props_request_properties(self, request, harmonic_v props_request.strainMapNaturalFreq = strain_map_natural_freq @require_version(241) - def get_ict_analysis_input_fields(self): + def get_ict_analysis_input_fields(self) -> list[str]: """Get ICT analysis property fields based on the user configuration. Available Since: 2024R1 Returns ------- - list + list[str] ICT analysis property fields based on the user configuration. + ``None`` if not connected to Sherlock. Examples -------- @@ -546,8 +562,7 @@ def get_ict_analysis_input_fields(self): >>> sherlock.analysis.get_ict_analysis_input_fields() """ if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() message = SherlockAnalysisService_pb2.GetICTAnalysisInputFieldsRequest() response = self.stub.getICTAnalysisInputFields(message) @@ -560,25 +575,25 @@ def get_ict_analysis_input_fields(self): @require_version(241) def update_ict_analysis_props( self, - project, - ict_analysis_properties, - ): + project: str, + ict_analysis_properties: list[dict[str, bool | float | int | str]], + ) -> int: """Update properties for an ICT analysis. Available Since: 2024R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - ict_analysis_properties : list + ict_analysis_properties: list[dict[str, bool | float | int | str]] ICT analysis properties for a CCA consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - - ict_application_time : double + - ict_application_time: float Specifies the amount of time to complete one ICT event. - - ict_application_time_units : str + - ict_application_time_units: str Application time units. Options are ``"ms"``, ``"sec"``, ``"min"``, ``"hr"``, ``"day"``, ``"year"``. - ict_number_of_events: int @@ -692,8 +707,7 @@ def update_ict_analysis_props( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.updateICTAnalysisProps(request) @@ -708,21 +722,23 @@ def update_ict_analysis_props( raise e @require_version(241) - def get_mechanical_shock_input_fields(self, model_source=None): + def get_mechanical_shock_input_fields( + self, model_source: Optional[ModelSource] = None + ) -> list[str]: """Get mechanical shock property fields based on the user configuration. Available Since: 2024R1 Parameters ---------- - model_source : ModelSource, optional + model_source: ModelSource, optional Model source to get the random vibe property fields from. - Only ModelSource.GENERATED is supported. + Only GENERATED is supported. Default is ``None``. Returns ------- - list + list[str] Mechanical shock property fields based on the user configuration. Examples @@ -741,8 +757,7 @@ def get_mechanical_shock_input_fields(self, model_source=None): >>> sherlock.analysis.get_mechanical_shock_input_fields(ModelSource.GENERATED) """ if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() message = SherlockAnalysisService_pb2.GetMechanicalShockInputFieldsRequest( modelSource=model_source @@ -757,21 +772,21 @@ def get_mechanical_shock_input_fields(self, model_source=None): @require_version(241) def update_mechanical_shock_props( self, - project, - mechanical_shock_properties, - ): + project: str, + mechanical_shock_properties: list[dict[str, bool | float | int | str]], + ) -> int: """Update properties for a mechanical shock analysis. Available Since: 2024R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - mechanical_shock_properties : list + mechanical_shock_properties: list[dict[str, bool | float | int | str]] Mechanical shock properties for a CCA consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - model_source: ModelSource, optional Model source. The default is ``None``. @@ -799,7 +814,7 @@ def update_mechanical_shock_props( - natural_freq_max_units: str Maximum frequency units. The default is ``None``. Options are ``"HZ"``, ``"KHZ"``, ``"MHZ"``, and ``"GHZ"``. - - analysis_temp: double + - analysis_temp: float Temperature. The default is ``None``. - analysis_temp_units: str Temperature units. The default is ``None``. @@ -946,8 +961,7 @@ def update_mechanical_shock_props( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.updateMechanicalShockProps(request) @@ -962,14 +976,14 @@ def update_mechanical_shock_props( raise e @require_version(241) - def get_solder_fatigue_input_fields(self): + def get_solder_fatigue_input_fields(self) -> list[str]: """Get solder fatigue property fields based on the user configuration. Available Since: 2024R1 Returns ------- - list + list[str] Solder fatigue property fields based on the user configuration. Examples @@ -988,39 +1002,36 @@ def get_solder_fatigue_input_fields(self): >>> sherlock.analysis.get_solder_fatigue_input_fields() """ if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() message = SherlockAnalysisService_pb2.GetSolderFatigueInputFieldsRequest() response = self.stub.getSolderFatigueInputFields(message) fields = self._translate_field_names(response.fieldName) - LOG.info(fields) - return fields @require_version(241) def update_solder_fatigue_props( self, - project, - solder_fatigue_properties, - ): + project: str, + solder_fatigue_properties: list[dict[str, bool | float | str]], + ) -> int: """Update properties for a solder fatigue analysis. Available Since: 2024R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - solder_fatigue_properties : list + solder_fatigue_properties: list[dict[str, bool | float | str]] Mechanical shock properties for a CCA consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - solder_material: str Solder material. The default is ``None``. - - part_temp : float + - part_temp: float Part temperature. The default is ``None``. - part_temp_units: str Part temperature units. The default is ``None``. @@ -1124,8 +1135,7 @@ def update_solder_fatigue_props( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.updateSolderFatigueProps(request) @@ -1140,21 +1150,21 @@ def update_solder_fatigue_props( raise e @require_version() - def get_random_vibe_input_fields(self, model_source=None): + def get_random_vibe_input_fields(self, model_source: Optional[ModelSource] = None) -> list[str]: """Get random vibe property fields based on the user configuration. Available Since: 2023R2 Parameters ---------- - model_source : ModelSource, optional + model_source: ModelSource, optional Model source to get the random vibe property fields from. The default is ``None``. Returns ------- - list - Random vibe property fields based on the user configuration. + list[str] + Random vibe input field property names based on the user configuration. Examples -------- @@ -1172,8 +1182,7 @@ def get_random_vibe_input_fields(self, model_source=None): >>> sherlock.analysis.get_random_vibe_input_fields(ModelSource.STRAIN_MAP) """ if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() message = SherlockAnalysisService_pb2.GetRandomVibeInputFieldsRequest( modelSource=model_source @@ -1181,39 +1190,37 @@ def get_random_vibe_input_fields(self, model_source=None): response = self.stub.getRandomVibeInputFields(message) fields = self._translate_field_names(response.fieldName) - LOG.info(fields) - return fields @require_version() def update_random_vibe_props( self, - project, - cca_name, - random_vibe_damping=None, - natural_freq_min=None, - natural_freq_min_units=None, - natural_freq_max=None, - natural_freq_max_units=None, - analysis_temp=None, - analysis_temp_units=None, - part_validation_enabled=None, - force_model_rebuild=None, - reuse_modal_analysis=None, - perform_nf_freq_range_check=None, - require_material_assignment_enabled=None, - model_source=None, - strain_map_natural_freqs=None, - ): + project: str, + cca_name: str, + random_vibe_damping: Optional[str] = None, + natural_freq_min: Optional[float] = None, + natural_freq_min_units: Optional[str] = None, + natural_freq_max: Optional[float] = None, + natural_freq_max_units: Optional[str] = None, + analysis_temp: Optional[float] = None, + analysis_temp_units: Optional[str] = None, + part_validation_enabled: Optional[bool] = None, + force_model_rebuild: Optional[str] = None, + reuse_modal_analysis: Optional[bool] = None, + perform_nf_freq_range_check: Optional[bool] = None, + require_material_assignment_enabled: Optional[bool] = None, + model_source: Optional[ModelSource] = None, + strain_map_natural_freqs: Optional[str] = None, + ) -> int: """Update properties for a random vibe analysis. Available Since: 2024R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. random_vibe_damping: str, optional One or more modal damping ratios. The default is ``None``. @@ -1253,8 +1260,8 @@ def update_random_vibe_props( model_source: ModelSource, optional Model source. The default is ``None``. This parameter is required for strain map analysis. - strain_map_natural_freqs : list, optional - Natural frequencies. The default is ``None``. + strain_map_natural_freqs: str, optional + Comma-separated list of natural frequencies. The default is ``None``. This parameter is required for strain map analysis. Returns @@ -1304,8 +1311,7 @@ def update_random_vibe_props( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockAnalysisService_pb2.UpdateRandomVibePropsRequest( project=project, @@ -1341,14 +1347,14 @@ def update_random_vibe_props( raise e @require_version() - def get_natural_frequency_input_fields(self): + def get_natural_frequency_input_fields(self) -> list[str]: """Get natural frequency property fields based on the user configuration. Available Since: 2023R2 Returns ------- - list + list[str] Matural frequency property fields based on the user configuration. Examples @@ -1367,15 +1373,12 @@ def get_natural_frequency_input_fields(self): >>> sherlock.analysis.get_natural_frequency_input_fields() """ if not self._is_connection_up(): - LOG.error("There is not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() message = SherlockAnalysisService_pb2.GetNaturalFrequencyInputFieldsRequest() response = self.stub.getNaturalFrequencyInputFields(message) fields = self._translate_field_names(response.fieldName) - LOG.info(fields) - return fields @require_version() @@ -1390,18 +1393,18 @@ def update_natural_frequency_props( natural_freq_max_units: str, part_validation_enabled: bool, require_material_assignment_enabled: bool, - analysis_temp: float = None, - analysis_temp_units: str = None, - ): + analysis_temp: Optional[float] = None, + analysis_temp_units: Optional[str] = None, + ) -> int: """Update properties for a natural frequency analysis. Available Since:2023R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. natural_freq_count: int Natural frequency result count. @@ -1467,8 +1470,7 @@ def update_natural_frequency_props( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockAnalysisService_pb2.UpdateNaturalFrequencyPropsRequest( project=project, @@ -1499,38 +1501,38 @@ def update_natural_frequency_props( @require_version() def run_strain_map_analysis( self, - project, - cca_name, - strain_map_analyses, - ): + project: str, + cca_name: str, + strain_map_analyses: list[list[RunStrainMapAnalysisRequestAnalysisType | list[list[str]]]], + ) -> int: """Run one or more strain map analyses. Available Since: 2023R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the main CCA for the analysis. - strain_map_analyses : list + strain_map_analyses: list[list[RunStrainMapAnalysisRequestAnalysisType | list[list[str]]]] Analyses consisting of these properties: - - analysis_type : RunStrainMapAnalysisRequestAnalysisType + - analysis_type: RunStrainMapAnalysisRequestAnalysisType Type of analysis to run. - - event_strain_maps : list + - event_strain_maps: list Strain maps assigned to the desired life cycle events for a given PCB side. The list consists of these properties: - - phase_name : str + - phase_name: str Life cycle phase name for the strain map assignment. - - event_name : str + - event_name: str Life cycle event name for the strain map assignment. - - pcb_side : str + - pcb_side: str PCB side for the strain map. Options are ``"TOP"`` and ``"BOTTOM"``. - - strain_map : str + - strain_map: str Name of the strain map assigned to the life cycle event. - - sub_assembly_name : str, optional + - sub_assembly_name: str, optional Name of the subassembly CCA to assign the strain map to. Returns @@ -1541,6 +1543,9 @@ def run_strain_map_analysis( Examples -------- >>> from ansys.sherlock.core.launcher import launch_sherlock + >>> from ansys.sherlock.core.types.analysis_types import ( + >>> RunStrainMapAnalysisRequestAnalysisType + >>> ) >>> sherlock = launch_sherlock() >>> analysis_request = SherlockAnalysisService_pb2.RunStrainMapAnalysisRequest >>> sherlock.analysis.run_strain_map_analysis( @@ -1637,13 +1642,16 @@ def run_strain_map_analysis( if len(event_strain_map) == 5: event_strain_map_request.subAssemblyName = event_strain_map[4] + except SherlockRunStrainMapAnalysisError as e: + LOG.error(str(e)) + raise e - if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + if not self._is_connection_up(): + raise SherlockNoGrpcConnectionException() - response = self.stub.runStrainMapAnalysis(request) + response = self.stub.runStrainMapAnalysis(request) + try: if response.value == -1: raise SherlockRunStrainMapAnalysisError(response.message) else: @@ -1654,42 +1662,61 @@ def run_strain_map_analysis( raise e @require_version() - def update_pcb_modeling_props(self, project, cca_names, analyses): + def update_pcb_modeling_props( + self, + project: str, + cca_names: list[str], + analyses: list[ + tuple[ + bool + | float + | str + | UpdatePcbModelingPropsRequestAnalysisType + | UpdatePcbModelingPropsRequestPcbModelType + | UpdatePcbModelingPropsRequestPcbMaterialModel + | ElementOrder, + ..., + ] + ], + ) -> int: """Update FEA PCB Modeling properties for one or more CCAs. Available Since: 2023R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_names : list + cca_names: list Names of the CCAs to be used for the analysis. - analyses : list + analyses: list[tuple[bool | float | str | UpdatePcbModelingPropsRequestAnalysisType\ + | UpdatePcbModelingPropsRequestPcbModelType\ + | UpdatePcbModelingPropsRequestPcbMaterialModel\ + | ElementOrder, ...]] Elements consisting of the following properties: - - analysis_type : UpdatePcbModelingPropsRequestAnalysisType + - analysis_type: UpdatePcbModelingPropsRequestAnalysisType Type of analysis applied. - - pcb_model_type : UpdatePcbModelingPropsRequestPcbModelType + - pcb_model_type: UpdatePcbModelingPropsRequestPcbModelType The PCB modeling mesh type. - - modeling_region_enabled : bool + - modeling_region_enabled: bool Indicates if modeling regions are enabled. - - pcb_material_model : UpdatePcbModelingPropsRequestPcbMaterialModel + - pcb_material_model: UpdatePcbModelingPropsRequestPcbMaterialModel The PCB modeling PCB model type. - - pcb_max_materials : int + - pcb_max_materials: Optional[int] The number of PCB materials for Uniform Elements and Layered Elements PCB model types. Not applicable if PCB model is Uniform or Layered. - - pcb_elem_order : ElementOrder + - pcb_elem_order: ElementOrder The element order for PCB elements. - - pcb_max_edge_length : float + - pcb_max_edge_length: float The maximum mesh size for PCB elements. - - pcb_max_edge_length_units : str + - pcb_max_edge_length_units: str The length units for the maximum mesh size. - - pcb_max_vertical : float + - pcb_max_vertical: float The maximum vertical mesh size for PCB elements. - - pcb_max_vertical_units : str + - pcb_max_vertical_units: str The length units for the maximum vertical mesh size. - - quads_preferred : bool + - quads_preferred: bool Indicates that the meshing engine should attempt to generate quad-shaped elements when creating the mesh. @@ -1729,42 +1756,48 @@ def update_pcb_modeling_props(self, project, cca_names, analyses): raise SherlockUpdatePcbModelingPropsError(message="CCA names are invalid.") if not analyses: raise SherlockUpdatePcbModelingPropsError(message="Analysis input(s) are invalid.") - if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + except SherlockUpdatePcbModelingPropsError as e: + LOG.error(str(e)) + raise e - request = SherlockAnalysisService_pb2.UpdatePcbModelingPropsRequest( - project=project, - ccaNames=cca_names, - ) + if not self._is_connection_up(): + raise SherlockNoGrpcConnectionException() + + request = SherlockAnalysisService_pb2.UpdatePcbModelingPropsRequest( + project=project, + ccaNames=cca_names, + ) - """Add PCB Modeling Props to Request""" - uniform = SherlockAnalysisService_pb2.UpdatePcbModelingPropsRequest.Analysis.Uniform - layered = SherlockAnalysisService_pb2.UpdatePcbModelingPropsRequest.Analysis.Layered - for a in analyses: - analysis = request.analyses.add() - analysis.type = a[0] - analysis.modelType = a[1] - analysis.modelingRegionEnabled = a[2] - analysis.pcbMaterialModel = a[3] - if analysis.pcbMaterialModel == uniform or analysis.pcbMaterialModel == layered: - analysis.pcbElemOrder = a[4] - analysis.pcbMaxEdgeLength = a[5] - analysis.pcbMaxEdgeLengthUnits = a[6] - analysis.pcbMaxVertical = a[7] - analysis.pcbMaxVerticalUnits = a[8] - analysis.quadsPreferred = a[9] - else: - analysis.pcbMaxMaterials = a[4] - analysis.pcbElemOrder = a[5] - analysis.pcbMaxEdgeLength = a[6] - analysis.pcbMaxEdgeLengthUnits = a[7] - analysis.pcbMaxVertical = a[8] - analysis.pcbMaxVerticalUnits = a[9] - analysis.quadsPreferred = a[10] - - response = self.stub.updatePcbModelingProps(request) + """Add PCB Modeling Props to Request""" + _analysis = SherlockAnalysisService_pb2.UpdatePcbModelingPropsRequest.Analysis + uniform = _analysis.PcbMaterialModel.Uniform + layered = _analysis.PcbMaterialModel.Layered + for a in analyses: + analysis = request.analyses.add() + analysis.type = a[0] + analysis.modelType = a[1] + analysis.modelingRegionEnabled = a[2] + analysis.pcbMaterialModel = a[3] + if analysis.pcbMaterialModel == uniform or analysis.pcbMaterialModel == layered: + analysis.pcbElemOrder = a[4] + analysis.pcbMaxEdgeLength = a[5] + analysis.pcbMaxEdgeLengthUnits = a[6] + analysis.pcbMaxVertical = a[7] + analysis.pcbMaxVerticalUnits = a[8] + analysis.quadsPreferred = a[9] + else: + analysis.pcbMaxMaterials = a[4] + analysis.pcbElemOrder = a[5] + analysis.pcbMaxEdgeLength = a[6] + analysis.pcbMaxEdgeLengthUnits = a[7] + analysis.pcbMaxVertical = a[8] + analysis.pcbMaxVerticalUnits = a[9] + analysis.quadsPreferred = a[10] + + response = self.stub.updatePcbModelingProps(request) + + try: if response.value == -1: raise SherlockUpdatePcbModelingPropsError(response.message) return response.value @@ -1773,39 +1806,41 @@ def update_pcb_modeling_props(self, project, cca_names, analyses): raise e @require_version(241) - def update_part_modeling_props(self, project, part_modeling_props): + def update_part_modeling_props( + self, project: str, part_modeling_props: dict[str, bool | float | str] + ) -> int: """Update part modeling properties for a given project's CCA. Available Since: 2024R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - part_modeling_props : dict + part_modeling_props: dict[str, bool | float | str] Part modeling properties for a CCA consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - - part_enabled : bool + - part_enabled: bool Whether to enable part modeling. All other fields are ignored if disabled. - - part_min_size : float, optional + - part_min_size: float, optional Minimum part size. - - part_min_size_units : str, optional + - part_min_size_units: str, optional Minimum part size units. - - part_elem_order : str, optional + - part_elem_order: str, optional Part element order. Options are ``"First Order (Linear)"``, ``"Second Order (Quadratic)"``, or ``"Solid Shell"``. - - part_max_edge_length : float, optional + - part_max_edge_length: float, optional Part max edge length. - - part_max_edge_length_units : str, optional + - part_max_edge_length_units: str, optional Part max edge length units. - - part_max_vertical : float, optional + - part_max_vertical: float, optional Part max vertical. - - part_max_vertical_units : str, optional + - part_max_vertical_units: str, optional Part max vertical units. - - part_results_filtered : bool, optional + - part_results_filtered: bool, optional Whether to enable filtered part results. Returns @@ -1890,8 +1925,7 @@ def update_part_modeling_props(self, project, part_modeling_props): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.updatePartModelingProperties(request) @@ -1908,35 +1942,35 @@ def update_part_modeling_props(self, project, part_modeling_props): @require_version(251) def update_part_list_validation_analysis_props( self, - project, - properties_per_cca, - ): + project: str, + properties_per_cca: list[dict[str, bool | str]], + ) -> int: """Update properties for a Part List Validation analysis. Parameters ---------- - project : str + project: str Name of the Sherlock project. - properties_per_cca : list + properties_per_cca: list[dict[str, bool | str]] Part List Validation analysis properties for each CCA consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - - process_use_avl : bool + - process_use_avl: bool Whether to use AVL. - - process_use_wizard : bool + - process_use_wizard: bool Whether to use the wizard. - - process_check_confirmed_properties : bool + - process_check_confirmed_properties: bool Whether to check confirmed properties. - - process_check_part_numbers : bool + - process_check_part_numbers: bool Whether to check part numbers. - - matching_mode : str + - matching_mode: str Matching type. - - avl_require_internal_part_number : bool + - avl_require_internal_part_number: bool Whether to require an internal part number. - - avl_require_approved_description : bool + - avl_require_approved_description: bool Whether to require an approved description. - - avl_require_approved_manufacturer : bool + - avl_require_approved_manufacturer: bool Whether to require an approved manufacturer. Returns @@ -2031,8 +2065,7 @@ def update_part_list_validation_analysis_props( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.updatePartsListValidationProps(request) @@ -2051,41 +2084,41 @@ def get_parts_list_validation_analysis_props( self, project: str, cca_name: str, - ): + ) -> SherlockAnalysisService_pb2.PartsListValidationPropsResponse: """Get properties for a Part List Validation analysis. Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. Returns ------- PartsListValidationPropsResponse - - returnCode : ReturnCode - - value : int + - returnCode: ReturnCode + - value: int Status code of the response. 0 for success. - - message : str + - message: str indicates general errors that occurred while attempting to update parts - - partLibrary : str + - partLibrary: str Part library name - - processUseAVL : bool + - processUseAVL: bool Process option to use AVL - - processUseWizard : bool + - processUseWizard: bool Process option to use wizard - - processCheckConfirmedProperties : bool + - processCheckConfirmedProperties: bool Process option to check confirmed properties - - processCheckPartNumbers : bool + - processCheckPartNumbers: bool Process option to check part numbers - - matching : MatchingMode + - matching: MatchingMode Matching type - - avlRequireInternalPartNumber : bool + - avlRequireInternalPartNumber: bool AVL option to require internal part number - - avlRequireApprovedDescription : bool + - avlRequireApprovedDescription: bool AVL option to require approved description - - avlRequireApprovedManufacturer : bool + - avlRequireApprovedManufacturer: bool AVL option to require approved manufacturer Examples @@ -2101,7 +2134,7 @@ def get_parts_list_validation_analysis_props( project="Test", cca_name="Card", ) - >>> response = sherlock.analysis.get_parts_list_validation_analysis_props( + >>> analysis_props = sherlock.analysis.get_parts_list_validation_analysis_props( "Test", "Card" ) """ @@ -2120,8 +2153,7 @@ def get_parts_list_validation_analysis_props( ) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.getPartsListValidationProps(request) diff --git a/src/ansys/sherlock/core/common.py b/src/ansys/sherlock/core/common.py index f0f7ba7e..1d18ca07 100644 --- a/src/ansys/sherlock/core/common.py +++ b/src/ansys/sherlock/core/common.py @@ -1,6 +1,11 @@ # Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module for running the gRPC APIs in the Sherlock Common service.""" + +import grpc + +from ansys.sherlock.core.types.common_types import ListUnitsRequestUnitType + try: import SherlockCommonService_pb2 import SherlockCommonService_pb2_grpc @@ -9,7 +14,7 @@ from ansys.api.sherlock.v0 import SherlockCommonService_pb2_grpc from ansys.sherlock.core import LOG -from ansys.sherlock.core.errors import SherlockCommonServiceError +from ansys.sherlock.core.errors import SherlockCommonServiceError, SherlockNoGrpcConnectionException from ansys.sherlock.core.grpc_stub import GrpcStub from ansys.sherlock.core.utils.version_check import require_version @@ -17,20 +22,19 @@ class Common(GrpcStub): """Contains methods from the Sherlock Common service.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize a gRPC stub for the Sherlock Common service.""" super().__init__(channel, server_version) self.stub = SherlockCommonService_pb2_grpc.SherlockCommonServiceStub(channel) @require_version() - def check(self): + def check(self) -> bool: """Perform a health check on the gRPC connection. Returns ------- bool Whether the Sherlock client is connected via gRPC. - """ if not self._is_connection_up(): LOG.error("Health check failed.") @@ -40,7 +44,7 @@ def check(self): return True @require_version() - def is_sherlock_client_loading(self): + def is_sherlock_client_loading(self) -> bool: """Check if the Sherlock client is opened and done initializing. Available Since: 2023R2 @@ -49,11 +53,9 @@ def is_sherlock_client_loading(self): ------- bool Whether the Sherlock client is opened and done initializing. - """ if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() message = SherlockCommonService_pb2.IsSherlockClientLoadingRequest() response = self.stub.isSherlockClientLoading(message) @@ -66,7 +68,7 @@ def is_sherlock_client_loading(self): return False @require_version() - def exit(self, close_sherlock_client=False): + def exit(self, close_sherlock_client: bool = False): """Close the gRPC connection. Available Since: 2023R1 @@ -79,8 +81,7 @@ def exit(self, close_sherlock_client=False): is closed. """ if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() try: exit_message = SherlockCommonService_pb2.ExitRequest() @@ -91,14 +92,14 @@ def exit(self, close_sherlock_client=False): LOG.error("Exit error: ", str(err)) @require_version() - def list_units(self, unitType): + def list_units(self, unit_type: ListUnitsRequestUnitType) -> str: """List units for a unit type. Available Since: 2023R2 Parameters ---------- - unitType : ListUnitsRequestUnitType + unit_type : ListUnitsRequestUnitType Unit type. Returns @@ -106,14 +107,13 @@ def list_units(self, unitType): str Units for the unit type. """ - if unitType == "": + if unit_type == "": raise SherlockCommonServiceError(message="Unit type is missing.") if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return "" + raise SherlockNoGrpcConnectionException() - request = SherlockCommonService_pb2.ListUnitsRequest(unitType=unitType) + request = SherlockCommonService_pb2.ListUnitsRequest(unitType=unit_type) try: response = self.stub.listUnits(request) @@ -126,15 +126,15 @@ def list_units(self, unitType): return response.units @require_version() - def list_solder_materials(self): + def list_solder_materials(self) -> list[str]: """List valid solders. Available Since: 2024R1 Returns ------- - list - List of valid solder names. + list[str] + Valid solder names. Examples -------- @@ -143,8 +143,7 @@ def list_solder_materials(self): >>> sherlock.common.list_solder_materials() """ if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockCommonService_pb2.GetSoldersRequest() response = self.stub.getSolders(request) @@ -170,8 +169,7 @@ def get_sherlock_info(self) -> str: >>> is_single_project = sherlock.common.get_sherlock_info().isSingleProjectMode """ if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - raise RuntimeError("Not connected to a gRPC service.") + raise SherlockNoGrpcConnectionException() request = SherlockCommonService_pb2.SherlockInfoRequest() response = self.stub.getSherlockInfo(request) diff --git a/src/ansys/sherlock/core/errors.py b/src/ansys/sherlock/core/errors.py index b205ecfd..61bfc3eb 100644 --- a/src/ansys/sherlock/core/errors.py +++ b/src/ansys/sherlock/core/errors.py @@ -3,15 +3,28 @@ """pysherlock specific errors.""" from builtins import Exception +from typing import Optional LOCALHOST = "127.0.0.1" SHERLOCK_DEFAULT_PORT = 9090 +class SherlockNoGrpcConnectionException(Exception): + """Contains the error raised when the Sherlock gRPC channel has not been established.""" + + def __init__(self): + """Initialize error message.""" + self.message = "No connection to Sherlock gRPC server." + + def __str__(self): + """Format error message.""" + return self.message + + class SherlockCannotUsePortError(Exception): """Contains the error raised when the specified gRPC port cannot be used.""" - def __init__(self, port, error): + def __init__(self, port: int, error: str): """Initialize error message.""" self.port = port self.error = error @@ -24,7 +37,7 @@ def __str__(self): class SherlockConnectionError(Exception): """Contains the error raised when the Sherlock gRPC channel has not been established.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -36,7 +49,7 @@ def __str__(self): class SherlockDeleteProjectError(Exception): """Contains the error raised when a project cannot be deleted.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -48,7 +61,7 @@ def __str__(self): class SherlockImportODBError(Exception): """Contains the error raised when an ODB archive cannot be imported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -60,7 +73,7 @@ def __str__(self): class SherlockImportIpc2581Error(Exception): """Contains the error raised when an IPC2581 archive cannot be imported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -72,7 +85,7 @@ def __str__(self): class SherlockListCCAsError(Exception): """Contains the errors raised when a project's CCAs results cannot be listed.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -89,7 +102,7 @@ def str_itr(self): class SherlockListConductorLayersError(Exception): """Contains the error raised when a project's conductor layers cannot be listed.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -101,7 +114,7 @@ def __str__(self): class SherlockListLaminateLayersError(Exception): """Contains the error raised when a project's laminate layers cannot be listed.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -113,7 +126,7 @@ def __str__(self): class SherlockGetStackupPropsError(Exception): """Contains the error raised when getting stackup properties.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -125,7 +138,7 @@ def __str__(self): class SherlockGetLayerCountError(Exception): """Contains the error raised when getting layer count.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -137,7 +150,7 @@ def __str__(self): class SherlockGetTotalConductorThicknessError(Exception): """Contains the error raised when getting total conductor thickness.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -149,7 +162,7 @@ def __str__(self): class SherlockAddStrainMapsError(Exception): """Contains the errors raised when strain maps cannot be added to the project.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -166,7 +179,7 @@ def str_itr(self): class SherlockListStrainMapsError(Exception): """Contains the errors raised when strain maps for a project cannot be listed.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -183,7 +196,7 @@ def str_itr(self): class SherlockGenerateProjectReportError(Exception): """Contains the error raised when project report cannot be generated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -195,7 +208,7 @@ def __str__(self): class SherlockCreateLifePhaseError(Exception): """Contains the errors raised when a life phase cannot be created.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -212,7 +225,7 @@ def str_itr(self): class SherlockAddRandomVibeEventError(Exception): """Contains the errors raised when a random vibe event cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -229,7 +242,7 @@ def str_itr(self): class SherlockAddRandomVibeProfilesError(Exception): """Contains the errors raised when random vibe profiles cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -246,7 +259,7 @@ def str_itr(self): class SherlockAddThermalEventError(Exception): """Contains the errors raised when a thermal event cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -263,7 +276,7 @@ def str_itr(self): class SherlockAddThermalProfilesError(Exception): """Creates the errors raised when thermal profiles cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -280,7 +293,7 @@ def str_itr(self): class SherlockAddHarmonicEventError(Exception): """Contains the errors raised when a harmonic event cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -297,7 +310,7 @@ def str_itr(self): class SherlockAddHarmonicVibeProfilesError(Exception): """Contains the errors raised when harmonic vibe profiles cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -314,7 +327,7 @@ def str_itr(self): class SherlockAddShockEventError(Exception): """Contains the errors raised when a shock event cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -331,7 +344,7 @@ def str_itr(self): class SherlockAddShockProfilesError(Exception): """Contains the errors raised when shock profiles cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -348,7 +361,7 @@ def str_itr(self): class SherlockLoadRandomVibeProfileError(Exception): """Contains the error raised when loading random vibe properties.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -365,7 +378,7 @@ def str_itr(self): class SherlockLoadHarmonicProfileError(Exception): """Contains the error raised when loading a harmonic profile.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -382,7 +395,7 @@ def str_itr(self): class SherlockUpdateMountPointsByFileError(Exception): """Contains the errors raised when mount points cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -399,7 +412,7 @@ def str_itr(self): class SherlockGenStackupError(Exception): """Contains the error raised when a stackup cannot be generated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -411,7 +424,7 @@ def __str__(self): class SherlockUpdateConductorLayerError(Exception): """Contains the error raised when a conductor layer cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -423,7 +436,7 @@ def __str__(self): class SherlockUpdateLaminateLayerError(Exception): """Contains the error raised when a laminate layer cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -435,7 +448,7 @@ def __str__(self): class SherlockUpdatePartsListError(Exception): """Contains the errors raised when a parts list cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -452,7 +465,7 @@ def str_itr(self): class SherlockUpdatePartsLocationsError(Exception): """Contains the errors raised when part locations cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -469,7 +482,7 @@ def str_itr(self): class SherlockUpdatePartsLocationsByFileError(Exception): """Contains the errors raised when part locations cannot be updated by file results.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -486,7 +499,7 @@ def str_itr(self): class SherlockImportPartsListError(Exception): """Contains the error raised when a parts list cannot be imported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -498,7 +511,7 @@ def __str__(self): class SherlockExportPartsListError(Exception): """Contains the error raised when a parts list cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -510,7 +523,7 @@ def __str__(self): class SherlockEnableLeadModelingError(Exception): """Contains the error raised when lead modeling cannot be enabled.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -522,7 +535,7 @@ def __str__(self): class SherlockGetPartLocationError(Exception): """Contains the error raised when getting part location results in an error.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -534,7 +547,7 @@ def __str__(self): class SherlockLoadThermalProfileError(Exception): """Contains the error raised when loading thermal profile.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -551,7 +564,7 @@ def str_itr(self): class SherlockRunAnalysisError(Exception): """Contains the error raised when an analysis cannot be run.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -563,7 +576,7 @@ def __str__(self): class SherlockRunStrainMapAnalysisError(Exception): """Contains the error raised when a strain map analysis cannot be run.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -575,7 +588,7 @@ def __str__(self): class SherlockUpdateRandomVibePropsError(Exception): """Contains the error raised when properties for random vibe results cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -587,7 +600,7 @@ def __str__(self): class SherlockLoadShockProfileDatasetError(Exception): """Contains the error raised when loading shock profile dataset results in an error.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -604,7 +617,7 @@ def str_itr(self): class SherlockUpdateNaturalFrequencyPropsError(Exception): """Contains the error raised when properties for natural frequency results cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -616,7 +629,7 @@ def __str__(self): class SherlockCommonServiceError(Exception): """Contains the error raised when an API in the common service cannot be executed.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -628,7 +641,7 @@ def __str__(self): class SherlockModelServiceError(Exception): """Contains the error raised when an API in the model service cannot be executed.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -640,7 +653,7 @@ def __str__(self): class SherlockExportAEDBError(Exception): """Contains the error raised when an Electronics Desktop model cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -652,7 +665,7 @@ def __str__(self): class SherlockInvalidLoadDirectionError(Exception): """Contains the error raised when the load direction string is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -664,7 +677,7 @@ def __str__(self): class SherlockInvalidOrientationError(Exception): """Contains the error raised when an orientation string is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -676,7 +689,7 @@ def __str__(self): class SherlockInvalidRandomVibeProfileEntriesError(Exception): """Contains the error raised when a random vibe profile is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -688,7 +701,7 @@ def __str__(self): class SherlockInvalidThermalProfileEntriesError(Exception): """Contains the error raised when a thermal profile entry is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -700,7 +713,7 @@ def __str__(self): class SherlockInvalidHarmonicProfileEntriesError(Exception): """Contains the error raised when a harmonic profile entry is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -712,7 +725,7 @@ def __str__(self): class SherlockInvalidShockProfileEntriesError(Exception): """Contains the error raised when a shock profile entry is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -724,7 +737,7 @@ def __str__(self): class SherlockInvalidLayerIDError(Exception): """Contains the error raised when a layer ID is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -736,7 +749,7 @@ def __str__(self): class SherlockInvalidMaterialError(Exception): """Contains the error raised when a manufacturer/grade/material combination is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -748,7 +761,7 @@ def __str__(self): class SherlockInvalidConductorPercentError(Exception): """Contains the error raised when a conductor percent is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -760,7 +773,7 @@ def __str__(self): class SherlockInvalidThicknessArgumentError(Exception): """Contains the error raised when the thickness is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -772,7 +785,7 @@ def __str__(self): class SherlockInvalidGlassConstructionError(Exception): """Contains the error raised when the glass construction is invalid.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -784,7 +797,7 @@ def __str__(self): class SherlockLoadShockProfilePulsesError(Exception): """Contains the error raised when loading shock profile pulses.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -801,7 +814,7 @@ def str_itr(self): class SherlockUpdatePcbModelingPropsError(Exception): """Contains the error raised when updating pcb modeling properties results in an error.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -813,7 +826,7 @@ def __str__(self): class SherlockUpdateHarmonicVibePropsError(Exception): """Contains the error raised when properties for harmonic vibe analysis cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -825,7 +838,7 @@ def __str__(self): class SherlockUpdateICTAnalysisPropsError(Exception): """Contains the error raised when properties for ICT analysis cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -837,7 +850,7 @@ def __str__(self): class SherlockUpdateMechanicalShockPropsError(Exception): """Contains the error raised when properties for mechanical shock analysis cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -849,7 +862,7 @@ def __str__(self): class SherlockUpdatePartListValidationAnalysisPropsError(Exception): """Contains the error raised when part list validation analysis properties cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -861,7 +874,7 @@ def __str__(self): class SherlockUpdateSolderFatiguePropsError(Exception): """Contains the error raised when properties for solder fatigue analysis cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -873,7 +886,7 @@ def __str__(self): class SherlockAddProjectError(Exception): """Contains the error raised when Project cannot be added.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -885,7 +898,7 @@ def __str__(self): class SherlockAddCCAError(Exception): """Contains the error raised when CCA cannot be added.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -897,7 +910,7 @@ def __str__(self): class SherlockAddPottingRegionError(Exception): """Contains the error raised when a potting region cannot be added.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -909,7 +922,7 @@ def __str__(self): class SherlockUpdatePartModelingPropsError(Exception): """Contains the error raised when part modeling properties cannot be updated.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -921,7 +934,7 @@ def __str__(self): class SherlockUpdatePartsFromAVLError(Exception): """Contains the error raised when parts list cannot be updated by AVL.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -938,7 +951,7 @@ def str_itr(self): class SherlockListThermalMapsError(Exception): """Contains the errors raised when thermal map files for a project cannot be listed.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -955,7 +968,7 @@ def str_itr(self): class SherlockUpdateThermalMapsError(Exception): """Contains the errors raised when thermal map files for a project cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -972,7 +985,7 @@ def str_itr(self): class SherlockAddThermalMapsError(Exception): """Contains the errors raised when thermal map files for a project cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -989,7 +1002,7 @@ def str_itr(self): class SherlockImportProjectZipArchiveError(Exception): """Contains the error raised when a .zip project archive cannot be imported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1001,7 +1014,7 @@ def __str__(self): class SherlockImportProjectZipArchiveSingleModeError(Exception): """Contains the error raised when a .zip project archive cannot be imported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1013,7 +1026,7 @@ def __str__(self): class SherlockUpdatePartsListPropertiesError(Exception): """Contains the errors raised when a parts list properties cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -1030,7 +1043,7 @@ def str_itr(self): class SherlockExportNetListError(Exception): """Contains the error raised when a net list cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1042,7 +1055,7 @@ def __str__(self): class SherlockExportProjectError(Exception): """Contains the error raised when a project cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1054,7 +1067,7 @@ def __str__(self): class SherlockDeleteAllMountPointsError(Exception): """Contains the error raised when the mount points cannot be deleted.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1066,7 +1079,7 @@ def __str__(self): class SherlockDeleteAllICTFixturesError(Exception): """Contains the error raised when the ICT fixtures cannot be deleted.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1078,7 +1091,7 @@ def __str__(self): class SherlockDeleteAllTestPointsError(Exception): """Contains the error raised when the test points cannot be deleted.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1090,7 +1103,7 @@ def __str__(self): class SherlockUpdateTestPointsByFileError(Exception): """Contains the errors raised when test points cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -1107,7 +1120,7 @@ def str_itr(self): class SherlockUpdateTestFixturesByFileError(Exception): """Contains the errors raised when test fixtures cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -1124,7 +1137,7 @@ def str_itr(self): class SherlockExportAllTestPointsError(Exception): """Contains the errors raised when test points cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1136,7 +1149,7 @@ def __str__(self): class SherlockExportAllTestFixtures(Exception): """Contains the errors raised when test fixtures cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1148,7 +1161,7 @@ def __str__(self): class SherlockExportAllMountPoints(Exception): """Contains the errors raised when mount points cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1160,7 +1173,7 @@ def __str__(self): class SherlockCreateCCAFromModelingRegionError(Exception): """Contains the error raised when a CCA cannot be created from a modeling region.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1172,7 +1185,7 @@ def __str__(self): class SherlockExportFEAModelError(Exception): """Contains the error raised when a FEA model cannot be exported.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1184,7 +1197,7 @@ def __str__(self): class SherlockAddModelingRegionError(Exception): """Contains the errors raised when modeling regions for a project cannot be added.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -1201,7 +1214,7 @@ def str_itr(self): class SherlockUpdateModelingRegionError(Exception): """Contains the errors raised when modeling regions for a project cannot be updated.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -1218,7 +1231,7 @@ def str_itr(self): class SherlockCopyModelingRegionError(Exception): """Contains the errors raised when modeling regions for a project cannot be copied.""" - def __init__(self, message=None, error_array=None): + def __init__(self, message: Optional[str] = None, error_array: Optional[list[str]] = None): """Initialize error message.""" self.message = message self.error_array = error_array @@ -1235,7 +1248,7 @@ def str_itr(self): class SherlockGetPartsListValidationAnalysisPropsError(Exception): """Contains the error raised when getting parts list validation properties.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1247,7 +1260,7 @@ def __str__(self): class SherlockDeleteModelingRegionError(Exception): """Contains the error raised when the modeling regions cannot be deleted.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message @@ -1259,7 +1272,7 @@ def __str__(self): class SherlockVersionError(Exception): """Contains the error raised when an incompatible Sherlock version is being used.""" - def __init__(self, message): + def __init__(self, message: str): """Initialize error message.""" self.message = message diff --git a/src/ansys/sherlock/core/grpc_stub.py b/src/ansys/sherlock/core/grpc_stub.py index 35361e2f..290515c3 100644 --- a/src/ansys/sherlock/core/grpc_stub.py +++ b/src/ansys/sherlock/core/grpc_stub.py @@ -13,7 +13,7 @@ class GrpcStub: """Provides the gRPC stub.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize the gRPC stub.""" self.channel = channel self._server_version = server_version diff --git a/src/ansys/sherlock/core/launcher.py b/src/ansys/sherlock/core/launcher.py index f7808147..b8cde32e 100644 --- a/src/ansys/sherlock/core/launcher.py +++ b/src/ansys/sherlock/core/launcher.py @@ -7,6 +7,7 @@ import socket import subprocess import time +from typing import Optional import grpc @@ -20,7 +21,7 @@ sherlock_cmd_args = [] -def _is_port_available(host=LOCALHOST, port=SHERLOCK_DEFAULT_PORT): +def _is_port_available(host: str = LOCALHOST, port: int = SHERLOCK_DEFAULT_PORT): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: try: sock.bind((host, port)) @@ -36,27 +37,27 @@ def launch_sherlock( host: str = LOCALHOST, port: int = SHERLOCK_DEFAULT_PORT, single_project_path: str = "", - sherlock_cmd_args: str = "", - year: int = None, - release_number: int = None, + sherlock_command_args: str = "", + year: Optional[int] = None, + release_number: Optional[int] = None, ) -> Sherlock: r"""Launch Sherlock and start gRPC on a given host and port. Parameters ---------- - host : str, optional + host: str, optional IP address to start gRPC on. The default is ``"127.0.0.1"``, which is the IP address for the local host. - port : int, optional + port: int, optional Port number for the connection. single_project_path : str, optional Path to the Sherlock project if invoking Sherlock in the single-project mode. - sherlock_cmd_args : str, optional + sherlock_command_args : str, optional Additional command arguments for launching Sherlock. - year : int, optional + year: int, optional 4-digit year of the Sherlock release to launch. If not provided, the latest installed version of Sherlock will be launched. - release_number : int, optional + release_number: int, optional Release number of Sherlock to launch. If not provided, the latest installed version of Sherlock will be launched. @@ -82,7 +83,8 @@ def launch_sherlock( _is_port_available(host, port) except Exception as e: print(str(e)) - return None + raise e + _server_version = None try: sherlock_launch_cmd, _server_version = _get_sherlock_exe_path( @@ -92,8 +94,8 @@ def launch_sherlock( if single_project_path != "": args.append("-singleProject") args.append(single_project_path) - if sherlock_cmd_args != "": - args.append(f"{shlex.split(sherlock_cmd_args)}") + if sherlock_command_args != "": + args.append(f"{shlex.split(sherlock_command_args)}") print(args) subprocess.Popen(args) @@ -119,7 +121,7 @@ def launch_sherlock( LOG.error("Error encountered while starting or executing Sherlock, error = %s" + str(e)) -def connect_grpc_channel(port=SHERLOCK_DEFAULT_PORT, server_version=None): +def connect_grpc_channel(port: int = SHERLOCK_DEFAULT_PORT, server_version: Optional[int] = None): """Create a gRPC connection to a specified port and return the ``Sherlock`` connection object. The ``Sherlock`` connection object is used to invoke the APIs from their respective services. @@ -128,8 +130,11 @@ def connect_grpc_channel(port=SHERLOCK_DEFAULT_PORT, server_version=None): Parameters ---------- - port : int, optional - Port number for the connection. + port: int, optional + Port number for the connection. Default is ``SHERLOCK_DEFAULT_PORT``. + + server_version: int, optional + Version of Sherlock. Default is the newest version that is installed. Returns ------- @@ -142,7 +147,9 @@ def connect_grpc_channel(port=SHERLOCK_DEFAULT_PORT, server_version=None): return sherlock -def _get_base_ansys(year: int = None, release_number: int = None) -> tuple[str, int]: +def _get_base_ansys( + year: Optional[int] = None, release_number: Optional[int] = None +) -> tuple[str, int]: supported_installed_versions = { env_key: path for env_key, path in os.environ.items() @@ -172,17 +179,19 @@ def _get_base_ansys(year: int = None, release_number: int = None) -> tuple[str, raise ValueError("Could not find any installed version of Sherlock.") -def _get_ansys_version_from_awp_root(awp_root): +def _get_ansys_version_from_awp_root(awp_root: str): if awp_root.find("AWP_ROOT") >= 0: return int(awp_root.replace("AWP_ROOT", "")) return "" -def _get_sherlock_exe_path(year: int = None, release_number: int = None) -> str: +def _get_sherlock_exe_path( + year: Optional[int] = None, release_number: Optional[int] = None +) -> tuple[str, int]: ansys_base, sherlock_version = _get_base_ansys(year=year, release_number=release_number) if not ansys_base: - return "" + return "", 0 if os.name == "nt": sherlock_bin = os.path.join(ansys_base, "sherlock", "SherlockClient.exe") else: diff --git a/src/ansys/sherlock/core/layer.py b/src/ansys/sherlock/core/layer.py index c3920a52..b47ca971 100644 --- a/src/ansys/sherlock/core/layer.py +++ b/src/ansys/sherlock/core/layer.py @@ -1,6 +1,8 @@ # Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module containing all layer management capabilities.""" +import grpc + from ansys.sherlock.core.types.layer_types import ( CircularShape, CopyPottingRegionRequest, @@ -18,13 +20,11 @@ from SherlockLayerService_pb2 import ModelingRegion import SherlockLayerService_pb2_grpc except ModuleNotFoundError: + from ansys.api.sherlock.v0 import SherlockCommonService_pb2 from ansys.api.sherlock.v0 import SherlockLayerService_pb2 from ansys.api.sherlock.v0 import SherlockLayerService_pb2_grpc - from ansys.api.sherlock.v0 import SherlockCommonService_pb2 from ansys.api.sherlock.v0.SherlockLayerService_pb2 import ModelingRegion -from typing import Dict, List, Union - from ansys.sherlock.core import LOG from ansys.sherlock.core.errors import ( SherlockAddModelingRegionError, @@ -37,6 +37,7 @@ SherlockExportAllMountPoints, SherlockExportAllTestFixtures, SherlockExportAllTestPointsError, + SherlockNoGrpcConnectionException, SherlockUpdateModelingRegionError, SherlockUpdateMountPointsByFileError, SherlockUpdateTestFixturesByFileError, @@ -49,7 +50,7 @@ class Layer(GrpcStub): """Module containing all the layer management capabilities.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize a gRPC stub for SherlockLayerService.""" super().__init__(channel, server_version) self.stub = SherlockLayerService_pb2_grpc.SherlockLayerServiceStub(channel) @@ -57,19 +58,31 @@ def __init__(self, channel, server_version): @require_version(241) def add_potting_region( self, - project, - potting_regions, - ): + project: str, + potting_regions: list[ + dict[ + str, + float + | str + | PolygonalShape + | RectangularShape + | SlotShape + | CircularShape + | PCBShape, + ] + ], + ) -> int: """Add one or more potting regions to a given project. Available Since: 2024R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - potting_regions : list - List of potting region properties consisting of these properties: + potting_regions: list[dict[str, float | str | PolygonalShape | RectangularShape | SlotShape\ + | CircularShape | PCBShape]] + Potting region properties consisting of these properties: - cca_name: str Name of the CCA. @@ -229,8 +242,7 @@ def add_potting_region( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.addPottingRegion(request) @@ -306,7 +318,7 @@ def update_potting_region( update_request1, update_request2 ] - >>> responses = sherlock.layer.update_potting_region(request) + >>> return_codes = sherlock.layer.update_potting_region(request) """ update_request = request._convert_to_grpc() @@ -414,21 +426,21 @@ def delete_potting_region( @require_version() def update_mount_points_by_file( self, - project, - cca_name, - file_path, - ): + project: str, + cca_name: str, + file_path: str, + ) -> int: """Update mount point properties of a CCA from a CSV file. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - file_path : str + file_path: str Path for the CSV file with the mount point properties. Returns @@ -452,7 +464,7 @@ def update_mount_points_by_file( >>> sherlock.layer.update_mount_points_by_file( "Test", "Card", - "MountPointImport.csv", + "MountPointImport.csv" ) """ try: @@ -468,8 +480,7 @@ def update_mount_points_by_file( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.UpdateMountPointsByFileRequest( project=project, @@ -496,16 +507,16 @@ def update_mount_points_by_file( raise e @require_version(222) - def delete_all_mount_points(self, project, cca_name): + def delete_all_mount_points(self, project: str, cca_name: str) -> int: """Delete all mount points for a CCA. Available Since: 2022R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. Returns @@ -540,8 +551,7 @@ def delete_all_mount_points(self, project, cca_name): raise SherlockDeleteAllMountPointsError(message="CCA name is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.DeleteAllMountPointsRequest( project=project, @@ -560,16 +570,16 @@ def delete_all_mount_points(self, project, cca_name): return response.value @require_version(231) - def delete_all_ict_fixtures(self, project, cca_name): + def delete_all_ict_fixtures(self, project: str, cca_name: str) -> int: """Delete all ICT fixtures for a CCA. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. Returns @@ -604,8 +614,7 @@ def delete_all_ict_fixtures(self, project, cca_name): raise SherlockDeleteAllICTFixturesError(message="CCA name is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.DeleteAllICTFixturesRequest( project=project, @@ -624,16 +633,16 @@ def delete_all_ict_fixtures(self, project, cca_name): return response.value @require_version(231) - def delete_all_test_points(self, project, cca_name): + def delete_all_test_points(self, project: str, cca_name: str) -> int: """Delete all test points for a CCA. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. Returns @@ -668,8 +677,7 @@ def delete_all_test_points(self, project, cca_name): raise SherlockDeleteAllTestPointsError(message="CCA name is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.DeleteAllTestPointsRequest( project=project, @@ -690,21 +698,21 @@ def delete_all_test_points(self, project, cca_name): @require_version(231) def update_test_points_by_file( self, - project, - cca_name, - file_path, - ): + project: str, + cca_name: str, + file_path: str, + ) -> int: """Update test point properties of a CCA from a CSV file. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - file_path : str + file_path: str Path for the CSV file with the test point properties. Returns @@ -728,7 +736,7 @@ def update_test_points_by_file( >>> sherlock.layer.update_test_points_by_file( "Test", "Card", - "TestPointsImport.csv", + "TestPointsImport.csv" ) """ try: @@ -740,8 +748,7 @@ def update_test_points_by_file( raise SherlockUpdateTestPointsByFileError(message="File path is required.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.UpdateTestPointsByFileRequest( project=project, @@ -771,21 +778,21 @@ def update_test_points_by_file( @require_version(231) def update_test_fixtures_by_file( self, - project, - cca_name, - file_path, - ): + project: str, + cca_name: str, + file_path: str, + ) -> int: """Update test fixture properties of a CCA from a CSV file. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - file_path : str + file_path: str Path for the CSV file with the test fixture properties. Returns @@ -809,7 +816,7 @@ def update_test_fixtures_by_file( >>> sherlock.layer.update_test_fixtures_by_file( "Test", "Card", - "TestFixturesImport.csv", + "TestFixturesImport.csv" ) """ try: @@ -821,8 +828,7 @@ def update_test_fixtures_by_file( raise SherlockUpdateTestFixturesByFileError(message="File path is required.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.UpdateICTFixturesByFileRequest( project=project, @@ -852,32 +858,32 @@ def update_test_fixtures_by_file( @require_version(231) def export_all_test_points( self, - project, - cca_name, - export_file, - length_units="DEFAULT", - displacement_units="DEFAULT", - force_units="DEFAULT", - ): + project: str, + cca_name: str, + export_file: str, + length_units: str = "DEFAULT", + displacement_units: str = "DEFAULT", + force_units: str = "DEFAULT", + ) -> int: """Export the test point properties for a CCA. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - export_file : str + export_file: str Full path for the CSV file to export the test points list to. - length_units : str, optional + length_units: str, optional Length units to use when exporting the test points. The default is ``DEFAULT``. - displacement_units : str, optional + displacement_units: str, optional Displacement units to use when exporting the test points. The default is ``DEFAULT``. - force_units : str, optional + force_units: str, optional Force units to use when exporting the test points. The default is ``DEFAULT``. @@ -905,7 +911,7 @@ def export_all_test_points( "TestPointsExport.csv", "DEFAULT", "DEFAULT", - "DEFAULT", + "DEFAULT" ) """ try: @@ -917,8 +923,7 @@ def export_all_test_points( raise SherlockExportAllTestPointsError(message="File path is required.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.ExportAllTestPointsRequest( project=project, @@ -943,22 +948,22 @@ def export_all_test_points( @require_version(231) def export_all_test_fixtures( self, - project, - cca_name, - export_file, - units="DEFAULT", - ): + project: str, + cca_name: str, + export_file: str, + units: str = "DEFAULT", + ) -> int: """Export the test fixture properties for a CCA. Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - export_file : str + export_file: str Full path for the CSV file to export the text fixtures list to. - units : str, optional + units: str, optional Units to use when exporting the test fixtures. The default is ``DEFAULT``. @@ -985,7 +990,7 @@ def export_all_test_fixtures( "Tutorial Project", "Card", "TestFixturesExport.csv", - "DEFAULT", + "DEFAULT" ) """ try: @@ -997,8 +1002,7 @@ def export_all_test_fixtures( raise SherlockExportAllTestFixtures(message="File path is required.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.ExportAllICTFixturesRequest( project=project, @@ -1021,22 +1025,22 @@ def export_all_test_fixtures( @require_version(222) def export_all_mount_points( self, - project, - cca_name, - export_file, - units="DEFAULT", - ): + project: str, + cca_name: str, + export_file: str, + units: str = "DEFAULT", + ) -> int: """Export the mount point properties for a CCA. Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - export_file : str + export_file: str Full path for the CSV file to export the mount points list to. - units : str, optional + units: str, optional Units to use when exporting the mount points. The default is ``DEFAULT``. @@ -1063,7 +1067,7 @@ def export_all_mount_points( "Tutorial Project", "Card", "MountPointsExport.csv", - "DEFAULT", + "DEFAULT" ) """ try: @@ -1075,8 +1079,7 @@ def export_all_mount_points( raise SherlockExportAllMountPoints(message="File path is required.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLayerService_pb2.ExportAllMountPointsRequest( project=project, @@ -1100,46 +1103,49 @@ def export_all_mount_points( def add_modeling_region( self, project: str, - modeling_regions: List[Dict[str, Union[str, float, bool, dict]]], - ): + modeling_regions: list[ + dict[str, bool | float | str | dict[str, bool | float | str] | dict[str, float | str]] + ], + ) -> int: """ Add one or more modeling regions to a specific project. Parameters ---------- - project : str + project: str Name of the Sherlock project. - modeling_regions : list of dict - List of modeling regions to add. Each dictionary should contain: + modeling_regions: list[dict[str, bool | float | str | dict[str, bool | float | str]\ + | dict[str, float | str]]] + Modeling regions to add. Each dictionary should contain: - - cca_name : str + - cca_name: str Name of the CCA. - - region_id : str + - region_id: str Unique region ID of the modeling region. - - region_units : str + - region_units: str Units of the modeling region. - - model_mode : str + - model_mode: str Mode that specifies how the region is used. Valid values are ``Enabled``, ``Disabled`` and ``Excluded``. - shape: PolygonalShape|RectangularShape|SlotShape|CircularShape|PCBShape The shape of the modeling region. - - pcb_model_props : list - List of the PCB model parameters consisting of these properties: + - pcb_model_props: dict[str, bool | float | str] + PCB model parameters consisting of these properties: - - export_model_type : str + - export_model_type: str The type of model to be generated for a given modeling region. Valid values are ``Default``, ``Sherlock``, ``Sweep`` and ``None``. - elem_order: str The type of 3D elements to be created for the PCB in the modeling region. Valid values are ``First_Order``, ``Second_Order`` and ``Solid_Shell``. - - max_mesh_size : float + - max_mesh_size: float The maximum size of the mesh to be used in the region. - - max_mesh_size_units : str + - max_mesh_size_units: str Units for the maximum mesh size. - - quads_preferred : bool + - quads_preferred: bool Whether to generate quad-shaped elements when creating the mesh if true. - - trace_model_props : list - List of the trace model parameters consisting of these properties: + - trace_model_props: dict[str, float | str] + Trace model parameters consisting of these properties: - trace_model_type : str The specification of whether trace modeling should be performed @@ -1264,8 +1270,7 @@ def add_modeling_region( raise SherlockAddModelingRegionError(message="Trace model type is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() add_modeling_region_request = SherlockLayerService_pb2.AddModelingRegionRequest() add_modeling_region_request.project = project @@ -1367,60 +1372,65 @@ def add_modeling_region( def update_modeling_region( self, project: str, - modeling_regions: List[Dict[str, Union[str, float, bool, dict]]], - ): + modeling_regions: list[ + dict[ + str, + bool | float | str | dict[str, bool | float | str] | dict[str, bool | float | str], + ] + ], + ) -> int: """ Update one or more modeling regions in a specific project. Parameters ---------- - project : str + project: str Name of the Sherlock project. - modeling_regions : list of dict - List of modeling regions to update. Each dictionary should contain: + modeling_regions : list[dict] + Modeling regions to update. Each dictionary should contain: - - cca_name : str + - cca_name: str Name of the CCA. - - region_id : str + - region_id: str Unique region ID of the modeling region. - - region_units : str + - region_units: str Units of the modeling region. - - model_mode : str + - model_mode: str Mode that specifies how the region is used. Valid values are ``Enabled``, ``Disabled`` and ``Excluded``. - shape: PolygonalShape|RectangularShape|SlotShape|CircularShape|PCBShape The shape of the modeling region. - - pcb_model_props : list - List of the PCB model parameters consisting of these properties: + - pcb_model_props: dict[str, bool | float | str] + PCB model parameters consisting of these properties: - - export_model_type : str + - export_model_type: str The type of model to be generated for a given modeling region. Valid values are ``Default``, ``Sherlock``, ``Sweep`` and ``None``. - elem_order: str The type of 3D elements to be created for the PCB in the modeling region. Valid values are ``First_Order``, ``Second_Order`` and ``Solid_Shell``. - - max_mesh_size : float + - max_mesh_size: float The maximum size of the mesh to be used in the region. - - max_mesh_size_units : str + - max_mesh_size_units: str Units for the maximum mesh size. - - quads_preferred : bool + - quads_preferred: bool Whether to generate quad-shaped elements when creating the mesh if true. - - trace_model_props : list - List of the trace model parameters consisting of these properties: + - trace_model_props: dict[str, float | str] + Trace model parameters consisting of these properties: - - trace_model_type : str + - trace_model_type: str The specification of whether trace modeling should be performed within the region. Valid values are ``Default``, ``Enabled`` and ``Disabled``. - elem_order: str, optional The type of 3D elements to be created for the PCB in the modeling region. Valid values are ``First_Order``, ``Second_Order`` and ``Solid_Shell``. - - trace_mesh_size : float, optional + - trace_mesh_size: float, optional The maximum mesh size to be used in the region when trace modeling is enabled. - trace_mesh_size_units: str, optional Units for the maximum mesh size when trace modeling is enabled. - - region_id_replacement : str, optional + - region_id_replacement: str, optional Represents a unique region id that will replace the existing regionId value during a modeling region update if a value exists. @@ -1532,8 +1542,7 @@ def update_modeling_region( ) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() update_modeling_region_request = SherlockLayerService_pb2.UpdateModelingRegionRequest() update_modeling_region_request.project = project @@ -1632,8 +1641,8 @@ def update_modeling_region( def copy_modeling_region( self, project: str, - copy_regions: List[Dict[str, Union[str, float]]], - ): + copy_regions: list[dict[str, float | str]], + ) -> int: """ Copy one or more modeling regions in a specific project. @@ -1641,8 +1650,8 @@ def copy_modeling_region( ---------- project : str Name of the Sherlock project. - copy_regions : list of dict - List of modeling regions to copy along with their corresponding "copy to" parameters. + copy_regions : list[dict[str, float | str]] + Modeling regions to copy along with their corresponding "copy to" parameters. Each dictionary should contain: - cca_name : str @@ -1676,7 +1685,7 @@ def copy_modeling_region( project="Tutorial Project", cca_name="Card", ) - >>> copy_regions = [ + >>> modeling_regions = [ >>> { >>> "cca_name": "Card", >>> "region_id": "Region001", @@ -1685,7 +1694,7 @@ def copy_modeling_region( >>> "center_y": 20.0, >>> } >>> ] - >>> result = sherlock.layer.copy_modeling_region("Tutorial Project", copy_regions) + >>> result = sherlock.layer.copy_modeling_region("Tutorial Project", modeling_regions) """ try: if not project: @@ -1707,8 +1716,7 @@ def copy_modeling_region( raise SherlockCopyModelingRegionError(message="Center Y coordinate is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() copy_regions_request = [] @@ -1742,17 +1750,17 @@ def copy_modeling_region( raise e @require_version(251) - def delete_modeling_region(self, project: str, delete_regions: List[Dict[str, str]]): + def delete_modeling_region(self, project: str, delete_regions: list[dict[str, str]]) -> int: """Delete one or more modeling regions for a specific project. Parameters ---------- - project : str + project: str Name of the Sherlock project. - delete_regions : list of dict - List of modeling regions to delete. Each dictionary should contain: - - "cca_name" : str, Name of the CCA. - - "region_id" : str, Unique region ID of the modeling region to delete. + delete_regions: list[dict[str, str]] + Modeling regions to delete. Each dictionary should contain: + - "cca_name": str, Name of the CCA. + - "region_id": str, Unique region ID of the modeling region to delete. Returns ------- @@ -1772,8 +1780,8 @@ def delete_modeling_region(self, project: str, delete_regions: List[Dict[str, st project="Test", cca_name="Card", ) - >>> delete_regions = [{"cca_name": "Card", "region_id": "12345"}] - >>> sherlock.layer.delete_modeling_region("Test", delete_regions) + >>> modeling_regions = [{"cca_name": "Card", "region_id": "12345"}] + >>> sherlock.layer.delete_modeling_region("Test", modeling_regions) """ try: if project == "": @@ -1794,8 +1802,7 @@ def delete_modeling_region(self, project: str, delete_regions: List[Dict[str, st raise SherlockDeleteModelingRegionError(message="Region ID is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() delete_regions_info = [ SherlockLayerService_pb2.DeleteModelingRegionRequest.DeleteModelingRegionInfo( diff --git a/src/ansys/sherlock/core/lifecycle.py b/src/ansys/sherlock/core/lifecycle.py index afe7104a..e57b4efb 100644 --- a/src/ansys/sherlock/core/lifecycle.py +++ b/src/ansys/sherlock/core/lifecycle.py @@ -1,7 +1,6 @@ # Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module containing all life cycle management capabilities.""" - try: import SherlockLifeCycleService_pb2 import SherlockLifeCycleService_pb2_grpc @@ -9,6 +8,8 @@ from ansys.api.sherlock.v0 import SherlockLifeCycleService_pb2 from ansys.api.sherlock.v0 import SherlockLifeCycleService_pb2_grpc +import grpc + from ansys.sherlock.core import LOG from ansys.sherlock.core.errors import ( SherlockAddHarmonicEventError, @@ -31,6 +32,7 @@ SherlockLoadShockProfileDatasetError, SherlockLoadShockProfilePulsesError, SherlockLoadThermalProfileError, + SherlockNoGrpcConnectionException, ) from ansys.sherlock.core.grpc_stub import GrpcStub from ansys.sherlock.core.utils.version_check import require_version @@ -39,7 +41,7 @@ class Lifecycle(GrpcStub): """Contains all life cycle management capabilities.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize a gRPC stub for the Sherlock Life Cycle service.""" super().__init__(channel, server_version) self.stub = SherlockLifeCycleService_pb2_grpc.SherlockLifeCycleServiceStub(channel) @@ -132,17 +134,17 @@ def _init_shock_shapes(self): self.SHOCK_SHAPE_LIST = shock_shape_response.shockPulse @staticmethod - def _check_load_direction_validity(input): + def _check_load_direction_validity(load_direction: str): """Check that the input string is a valid load.""" - directions = input.split(",") + directions = load_direction.split(",") if len(directions) != 3: raise SherlockInvalidLoadDirectionError("Number of direction coordinates is invalid.") try: nonzero = 0 - for dir in directions: - if float(dir) != 0: + for direction in directions: + if float(direction) != 0: nonzero += 1 if nonzero == 0: @@ -154,9 +156,9 @@ def _check_load_direction_validity(input): raise SherlockInvalidLoadDirectionError("Direction coordinates are invalid.") @staticmethod - def _check_orientation_validity(input): + def _check_orientation_validity(orientations: str): """Check input string if it is a valid orientation.""" - orientation = input.split(",") + orientation = orientations.split(",") if len(orientation) != 2: raise SherlockInvalidOrientationError("Number of spherical coordinates is invalid.") @@ -173,13 +175,14 @@ def _check_orientation_validity(input): raise SherlockInvalidOrientationError("Elevation value is invalid.") @staticmethod - def _check_random_vibe_profile_entries_validity(input): - """Check input array to see if all elements are valid for random vibe entries.""" - if not isinstance(input, list): + def _check_random_vibe_profile_entries_validity(profile_entries: list): + """Check input list to see if all elements are valid for random vibe entries.""" + if not isinstance(profile_entries, list): raise SherlockInvalidRandomVibeProfileEntriesError("Entries argument is invalid.") + i = 0 try: - for i, entry in enumerate(input): + for i, entry in enumerate(profile_entries): if len(entry) != 2: raise SherlockInvalidRandomVibeProfileEntriesError( f"Invalid entry {i}: Number of elements is wrong" @@ -197,13 +200,14 @@ def _check_random_vibe_profile_entries_validity(input): f"Invalid entry {i}: Frequency or amplitude is invalid" ) - def _check_thermal_profile_entries_validity(self, input): - """Check input array to see if all elements are valid for thermal entries.""" - if not isinstance(input, list): + def _check_thermal_profile_entries_validity(self, profile_entries: list): + """Check input list to see if all elements are valid for thermal entries.""" + if not isinstance(profile_entries, list): raise SherlockAddThermalProfilesError("Entries argument is invalid.") + i = 0 try: - for i, entry in enumerate(input): + for i, entry in enumerate(profile_entries): if len(entry) != 4: raise SherlockInvalidThermalProfileEntriesError( f"Invalid entry {i}: Number of elements is wrong" @@ -228,13 +232,14 @@ def _check_thermal_profile_entries_validity(self, input): raise SherlockInvalidThermalProfileEntriesError(f"Invalid entry {i}: Time is invalid") @staticmethod - def _check_harmonic_profile_entries_validity(input): - """Check input array if all elements are valid for harmonic entries.""" - if not isinstance(input, list): + def _check_harmonic_profile_entries_validity(profile_entries: list): + """Check input list if all elements are valid for harmonic entries.""" + if not isinstance(profile_entries, list): raise SherlockInvalidHarmonicProfileEntriesError(message="Entries argument is invalid.") + i = 0 try: - for i, entry in enumerate(input): + for i, entry in enumerate(profile_entries): if len(entry) != 2: raise SherlockInvalidHarmonicProfileEntriesError( message=f"Invalid entry {i}: Number of elements is wrong" @@ -252,13 +257,14 @@ def _check_harmonic_profile_entries_validity(input): message=f"Invalid entry {i}: Frequency or load is invalid" ) - def _check_shock_profile_entries_validity(self, input): - """Check input array to see if all elements are valid for shock entries.""" - if not isinstance(input, list): + def _check_shock_profile_entries_validity(self, profile_entries: list): + """Check input list to see if all elements are valid for shock entries.""" + if not isinstance(profile_entries, list): raise SherlockInvalidShockProfileEntriesError(message="Entries argument is invalid.") + i = 0 try: - for i, entry in enumerate(input): + for i, entry in enumerate(profile_entries): if len(entry) != 4: raise SherlockInvalidShockProfileEntriesError( message=f"Invalid entry {i}: Number of elements is wrong" @@ -292,13 +298,13 @@ def _check_shock_profile_entries_validity(self, input): @require_version() def create_life_phase( self, - project, - phase_name, - duration, - duration_units, - num_of_cycles, - cycle_type, - description=None, + project: str, + phase_name: str, + duration: float, + duration_units: str, + num_of_cycles: float, + cycle_type: str, + description: str = "", ): """Create a life phase. @@ -306,21 +312,21 @@ def create_life_phase( Parameters ---------- - project : str + project: str Name of the Sherlock project. - phase_name : str + phase_name: str Name of the life phase. - duration : double + duration: float Event duration length. - duration_units : str + duration_units: str Units for the event duration length. Options are ``"ms"``, ``"sec"``, and ``"min"``. - num_of_cycles : double + num_of_cycles: float Number of cycles for the life phase. - cycle_type : str + cycle_type: str Cycle type. Options include ``"COUNT"``, ``"DUTY CYCLE"``, ``"PER YEAR"``, and ``"PER HOUR"``. - description : str, optional + description: str, optional Description of the life phase. The default is ``""``. Returns @@ -346,7 +352,7 @@ def create_life_phase( 1.5, "sec", 4.0, - "COUNT", + "COUNT" ) """ if self.CYCLE_TYPE_LIST is None: @@ -371,11 +377,7 @@ def create_life_phase( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return - - if description is None: - description = "" + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.CreateLifePhaseRequest( project=project, @@ -408,48 +410,48 @@ def create_life_phase( @require_version() def add_random_vibe_event( self, - project, - phase_name, - event_name, - duration, - duration_units, - num_of_cycles, - cycle_type, - orientation, - profile_type, - load_direction, - description="", - ): + project: str, + phase_name: str, + event_name: str, + duration: float, + duration_units: str, + num_of_cycles: float, + cycle_type: str, + orientation: str, + profile_type: str, + load_direction: str, + description: str = "", + ) -> int: """Add a random vibe event to a life cycle phase. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - phase_name : str + phase_name: str Name of the life cycle phase to add the random vibe event to. - event_name : str + event_name: str Name of the random vibe event. - duration : double + duration: float Event duration length. - duration_units : str + duration_units: str Event duration units. Options are ``"ms"``, ``"sec"``, ``"min"``, ``"hr"``, ``"day"``, and ``"year"``. - num_of_cycles : double + num_of_cycles: float Number of cycles for the random vibe event. - cycle_type : str + cycle_type: str Cycle type. Options are ``"COUNT"``, ``"DUTY_CYCLE"``, ``"PER_YEAR"``, ``"PER_DAY"``, ``"PER_HOUR"``, ``"PER_MIN"``, and ``"PER_SEC"``. - orientation : str + orientation: str PCB orientation in the format of ``"azimuth, elevation"``. For example, ``"30,15"``. - profile_type : str + profile_type: str Random load profile type. The only option is ``"Uniaxial"``. - load_direction : str + load_direction: str Load direction in the format of ``"x,y,z"``. For example, ``"0,0,1"``. - description : str, optional + description: str, optional Description of the random vibe event. The default is ``""``. Returns @@ -487,7 +489,7 @@ def add_random_vibe_event( "PER MIN", "45,45", "Uniaxial", - "2,4,5", + "2,4,5" ) """ if self.CYCLE_TYPE_LIST is None: @@ -531,8 +533,7 @@ def add_random_vibe_event( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.AddRandomVibeEventRequest( project=project, @@ -567,8 +568,8 @@ def add_random_vibe_event( @require_version() def add_random_vibe_profiles( self, - project, - random_vibe_profiles, + project: str, + random_vibe_profiles: list[tuple[str, str, str, str, str, list[tuple[float, float]]]], ): """Add random vibe profiles to a life cycle phase. @@ -576,28 +577,28 @@ def add_random_vibe_profiles( Parameters ---------- - project : str + project: str Name of the Sherlock project. - random_vibe_profiles : list - List of random vibe profiles consisting of these properties: + random_vibe_profiles: list[tuple[str, str, str, str, str, list[tuple[float, float]]]] + Random vibe profiles consisting of these properties: - - phase_name : str + - phase_name: str Name of the life cycle phase to add the random vibe profile to. - - event_name : str + - event_name: str Name of the random vibe event. - - profile_name : str + - profile_name: str Name of the random vibe profile. - - freq_units : str + - freq_units: str Frequency units. Options are ``"HZ"``, ``"KHZ"``, ``"MHZ"``, and ``"GHZ"``. - - ampl_units : str + - ampl_units: str Amplitude units. Options are ``"G2/Hz"``, ``"m2/s4/Hz"``, ``"mm2/s4/Hz"``, \ ``"in2/s4/Hz"``, and ``"ft2/s4/Hz"``. - - random_vibe_profile_entries : list - List of random vibe profile entries consisting of these properties: + - random_vibe_profile_entries: list[tuple[float, float]] + Random vibe profile entries consisting of these properties: - - frequency : double + - frequency: float Frequency of the profile entry expressed in frequency units. - - amplitude : double + - amplitude: float Amplitude of the profile entry expressed in amplitude units. Returns @@ -700,8 +701,7 @@ def add_random_vibe_profiles( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.AddRandomVibeProfilesRequest(project=project) @@ -741,34 +741,34 @@ def add_random_vibe_profiles( @require_version() def add_thermal_event( self, - project, - phase_name, - event_name, - num_of_cycles, - cycle_type, - cycle_state, - description="", - ): + project: str, + phase_name: str, + event_name: str, + num_of_cycles: float, + cycle_type: str, + cycle_state: str, + description: str = "", + ) -> int: """Add a thermal event to a life cycle phase. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - phase_name : str + phase_name: str Name of the life cycle phase to add the thermal event to. - event_name : str + event_name: str Name of the thermal event. - num_of_cycles : float + num_of_cycles: float Number of cycles for the thermal event. - cycle_type : str + cycle_type: str Cycle type. Options are ``"COUNT"``, ``"DUTY_CYCLE"``, ``"PER_YEAR"``, ``"PER_DAY"``, ``"PER_HOUR"``, ``"PER_MIN"``, and ``"PER_SEC"``. - cycle_state : str + cycle_state: str Life cycle state. Options are ``"OPERATING"`` and ``"STORAGE"``. - description : str, optional + description: str, optional Description of the thermal event. The default is ``""``. Returns @@ -802,7 +802,7 @@ def add_thermal_event( "Event1", 4.0, "PER YEAR", - "STORAGE", + "STORAGE" ) """ if self.CYCLE_TYPE_LIST is None: @@ -861,41 +861,41 @@ def add_thermal_event( @require_version() def add_thermal_profiles( self, - project, - thermal_profiles, - ): + project: str, + thermal_profiles: list[tuple[str, str, str, str, str, list[tuple[str, str, float, float]]]], + ) -> int: """Add thermal profiles to a life cycle phase. Available Since: 2023R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - thermal_profiles : list - List of thermal profiles consisting of these properties: + thermal_profiles: list[tuple[str, str, str, str, str, list[tuple[str, str, float, float]]]] + Thermal profiles consisting of these properties: - - phase_name : str + - phase_name: str Name of the life cycle phase to add the thermal profile to. - - event_name : str + - event_name: str Name of the thermal event. - - profile_name : str + - profile_name: str Name of the thermal profile. - - time_units : str + - time_units: str Time units. Options are ``"ms"``, ``"sec"``, ``"min"``, ``"hr"``, ``"day"``, and ``"year"``. - - temp_units : str + - temp_units: str Temperature units. Options are ``"C"``, ``"F"``, and ``"K"``. - - thermal_profile_entries : list - List of thermal profile entries consisting of these properties: + - thermal_profile_entries: list[tuple[str, str, float, float]] + Thermal profile entries consisting of these properties: - - step : str + - step: str Name of the thermal step. - - type : str + - type: str Type of the thermal step. Options are ``"HOLD"`` and ``"RAMP"``. - - time : float + - time: float Duration of the thermal step expressed in time units. - - temperature : float + - temperature: float Temperature of the step expressed in temperature units. Returns @@ -987,8 +987,7 @@ def add_thermal_profiles( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.AddThermalProfilesRequest(project=project) @@ -1030,51 +1029,51 @@ def add_thermal_profiles( @require_version() def add_harmonic_event( self, - project, - phase_name, - event_name, - duration, - duration_units, - num_of_cycles, - cycle_type, - sweep_rate, - orientation, - profile_type, - load_direction, - description="", - ): + project: str, + phase_name: str, + event_name: str, + duration: float, + duration_units: str, + num_of_cycles: float, + cycle_type: str, + sweep_rate: float, + orientation: str, + profile_type: str, + load_direction: str, + description: str = "", + ) -> int: """Add a harmonic event to a life cycle phase. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - phase_name : str + phase_name: str Name of the life cycle phase to add the harmonic event to. - event_name : str + event_name: str Name of the harmonic event. - duration : float + duration: float Event duration length. - duration_units : str + duration_units: str Event duration units. Options are ``"ms"``, ``"sec"``, ``"min"``, ``"hr"``, ``"day"``, and ``"year"``. - num_of_cycles : float + num_of_cycles: float Number of cycles for the harmonic event. - cycle_type : str + cycle_type: str Cycle type. Options are ``"COUNT"``, ``"DUTY_CYCLE"``, ``"PER_YEAR"``, ``"PER_DAY"``, ``"PER_HOUR"``, ``"PER_MIN"``, and ``"PER_SEC"``. - sweep_rate : float + sweep_rate: float Sweep rate for the harmonic event. - orientation : str + orientation: str PCB orientation in the format of ``"azimuth, elevation"``. For example, ``"30,15"``. - profile_type : str + profile_type: str Profile type of the harmonic load. Options are ``"Uniaxial"`` and ``"Triaxial"``. load_direction: str Load direction in the format of ``"x,y,z"``. For example, ``"0,0,1"``. - description : str, optional + description: str, optional Description of the harmonic event. The default is ``""``. Returns @@ -1113,7 +1112,7 @@ def add_harmonic_event( 5, "45,45", "Uniaxial", - "2,4,5", + "2,4,5" ) """ if self.CYCLE_TYPE_LIST is None: @@ -1194,40 +1193,42 @@ def add_harmonic_event( @require_version() def add_harmonic_vibe_profiles( self, - project, - harmonic_vibe_profiles, - ): + project: str, + harmonic_vibe_profiles: list[ + tuple[str, str, str, str, str, list[tuple[float, float, str]]] + ], + ) -> int: """Add harmonic vibe profiles to a life cycle phase. Available Since: 2023R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - harmonic_vibe_profiles : list - List of harmonic vibe profiles consisting of these properties: + harmonic_vibe_profiles: list + Harmonic vibe profiles consisting of these properties: - - phase_name : str + - phase_name: str Name of the life cycle phase to add this harmonic vibe profile to. - - event_name : str + - event_name: str Name of the event. - - profile_name : str + - profile_name: str Name of the harmonic vibe profile. - - freq_units : str + - freq_units: str Frequency units. Options are ``"HZ"``, ``"KHZ"``, ``"MHZ"``, and ``"GHZ"``. - - load_units : str + - load_units: str Load units. Options are ``"G"``, ```"m/s2"``, ``"mm/s2"``, ``"in/s2"``, and ``"ft/s2"``. - - harmonic_profile_entries : list - List of harmonic profile entries consisting of these properties: + - harmonic_profile_entries: list[tuple[float, float, str]] + Harmonic profile entries consisting of these properties: - - frequency : float + - frequency: float Frequency of the harmonic profile expressed in frequency units. - - load : float + - load: float Load of the harmonic profile expressed in load units. - - triaxial_axis : str + - triaxial_axis: str Axis that this profile should be assigned to if the harmonic profile type is ``"Triaxial"``. Options are: ``"x"``, ``"y"``, and ``"z"``. @@ -1293,6 +1294,8 @@ def add_harmonic_vibe_profiles( if project == "": raise SherlockAddHarmonicVibeProfilesError(message="Project name is invalid.") + i = 0 + profile_entry = [] for i, profile_entry in enumerate(harmonic_vibe_profiles): if len(profile_entry) != 7: raise SherlockAddHarmonicVibeProfilesError( @@ -1332,8 +1335,7 @@ def add_harmonic_vibe_profiles( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.AddHarmonicVibeProfilesRequest(project=project) @@ -1375,45 +1377,45 @@ def add_harmonic_vibe_profiles( @require_version() def add_shock_event( self, - project, - phase_name, - event_name, - duration, - duration_units, - num_of_cycles, - cycle_type, - orientation, - load_direction, - description="", - ): + project: str, + phase_name: str, + event_name: str, + duration: float, + duration_units: str, + num_of_cycles: float, + cycle_type: str, + orientation: str, + load_direction: str, + description: str = "", + ) -> int: """Add a shock event to a life cycle phase. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - phase_name : str + phase_name: str Name of the life cycle phase to add this shock event to. - event_name : str + event_name: str Name of the shock event. - duration : float + duration: float Event duration length. - duration_units : str + duration_units: str Event duration units. Options are ``"ms"``, ``"sec"``, ``"min"``, ``"hr"``, ``"day"``, and ``"year"``. - num_of_cycles : float + num_of_cycles: float Number of cycles for the shock event. - cycle_type : str + cycle_type: str Cycle type. Options are ``"COUNT"``, ``"DUTY CYCLE"``, ``"PER YEAR"``, and ``"PER HOUR"``. - orientation : str + orientation: str PCB orientation in the format of ``"azimuth, elevation"``. For example, ``"30,15"``. - load_direction : str + load_direction: str Load direction in the format of ``"x,y,z"``. For example, ``"0,0,1"``. - description : str, optional + description: str, optional Description of the shock event. The default is ``""``. Returns @@ -1450,7 +1452,7 @@ def add_shock_event( 4.0, "PER MIN", "45,45", - "2,4,5", + "2,4,5" ) """ if self.CYCLE_TYPE_LIST is None: @@ -1514,53 +1516,66 @@ def add_shock_event( @require_version() def add_shock_profiles( self, - project, - shock_profiles, - ): + project: str, + shock_profiles: list[ + tuple[ + str, + str, + str, + float, + str, + float, + str, + str, + str, + list[tuple[str, float, float, float]], + ] + ], + ) -> int: """Add shock profiles to a life cycle phase. Available Since: 2023R2 Parameters ---------- - project : str + project: str Name of the Sherlock project - shock_profiles : list - List of shock profiles consisting of these properties: + shock_profiles: list + Shock profiles consisting of these properties: - - phase_name : str + - phase_name: str Name of the life cycle phase to add the shock profile to. - - event_name : str + - event_name: str Name of the shock event. - - profile_name : str + - profile_name: str Name of the shock profile. - - duration : float + - duration: float Pulse duration. - - duration_units : str + - duration_units: str Pulse duration units. Options are ``"ms"``, ``"sec"``, ``"min"``, ``"hr"``, ``"day"``, and ``"year"``. - - sample_rate : float + - sample_rate: float Sample rate. - - sample_rate_units : str + - sample_rate_units: str Sample rate units. Options are ``"ms"``, ``"sec"``, ``"min"``, ``"hr"``, ``"day"``, and ``"year"``. - - load_units : str + - load_units: str Load units. Options are: ``"G"``, ``"m/s2"``, ``"mm/s2"``, ``"in/s2"``, and ``"ft/s2"``. - - freq_units : str + - freq_units: str Frequency units. Options are ``"HZ"``, ``"KHZ"``, ``"MHZ"``, and ``"GHZ"``. - - shock_profile_entries : list - List of shock profile entries consisting of these properties: + - shock_profile_entries: list + Shock profile entries consisting of these properties: - - shape : str + - shape: str Shape of the shock profile entry. Options are ``"FullSine"``, ``"HalfSine"``, ``"Haversine"``, ``"Triangle"``, ``"Sawtooth"``, ``"FullSquare"``, and ``"HalfSquare"``. - - load : float + - load: float Load of the profile entry expressed in load units. - - freq : float + - freq: float Frequency of the profile entry expressed in frequency units. - - decay : float + - decay: float Decay value of the profile entry. Returns @@ -1622,6 +1637,8 @@ def add_shock_profiles( if project == "": raise SherlockAddShockProfilesError(message="Project name is invalid.") + i = 0 + profile_entry = [] for i, profile_entry in enumerate(shock_profiles): if len(profile_entry) != 10: raise SherlockAddShockProfilesError( @@ -1675,11 +1692,12 @@ def add_shock_profiles( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.AddShockProfilesRequest(project=project) + s = [] + profile = None for s in shock_profiles: profile = request.shockProfiles.add() profile.phaseName = s[0] @@ -1716,20 +1734,22 @@ def add_shock_profiles( raise e @require_version() - def load_random_vibe_profile(self, project, phase_name, event_name, file_path): + def load_random_vibe_profile( + self, project: str, phase_name: str, event_name: str, file_path: str + ) -> int: """Load random vibe profile from .csv or .dat file. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project - phase_name : str + phase_name: str Name of the lifecycle phase to add this event to. - event_name : str + event_name: str Name of the random vibe event. - file_path : str + file_path: str File path for thermal profile .dat or .csv file Returns @@ -1748,14 +1768,14 @@ def load_random_vibe_profile(self, project, phase_name, event_name, file_path): True, True, project="Test", - cca_name="Card", + cca_name="Card" ) >>> sherlock.lifecycle.load_random_vibe_profile( project="Tutorial", phase_name="Phase 1", event_name="Random Event", - file_path="TestProfile.dat", + file_path="TestProfile.dat" ) """ try: @@ -1768,8 +1788,8 @@ def load_random_vibe_profile(self, project, phase_name, event_name, file_path): if file_path == "": raise SherlockLoadRandomVibeProfileError(message="File path is invalid.") if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() + request = SherlockLifeCycleService_pb2.LoadRandomVibeProfileRequest( project=project, phaseName=phase_name, @@ -1790,20 +1810,22 @@ def load_random_vibe_profile(self, project, phase_name, event_name, file_path): raise e @require_version() - def load_thermal_profile(self, project, phase_name, event_name, file_path): + def load_thermal_profile( + self, project: str, phase_name: str, event_name: str, file_path: str + ) -> int: """Load a thermal profile from a .dat or .csv file. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project - phase_name : str + phase_name: str Name of the lifecycle phase to add this event to. - event_name : str + event_name: str Name of the random vibe event. - file_path : str + file_path: str File path for thermal profile .dat or .csv file Returns @@ -1841,8 +1863,7 @@ def load_thermal_profile(self, project, phase_name, event_name, file_path): if file_path == "": raise SherlockLoadThermalProfileError(message="File path is invalid.") if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.LoadThermalProfileRequest( project=project, @@ -1867,20 +1888,22 @@ def load_thermal_profile(self, project, phase_name, event_name, file_path): raise e @require_version() - def load_harmonic_profile(self, project, phase_name, event_name, file_path): + def load_harmonic_profile( + self, project: str, phase_name: str, event_name: str, file_path: str + ) -> int: """Load a harmonic profile from a DAT or CSV file to a life cycle phase. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project - phase_name : str + phase_name: str Name of the life cycle phase to add the harmonic profile to. - event_name : str + event_name: str Name of the harmonic event. - file_path : str + file_path: str Path for DAT or CSV file with the harmonic profile. Returns @@ -1899,7 +1922,7 @@ def load_harmonic_profile(self, project, phase_name, event_name, file_path): True, True, project="Test", - cca_name="Card", + cca_name="Card" ) >>> loaded = sherlock.lifecycle.load_harmonic_profile( @@ -1919,8 +1942,8 @@ def load_harmonic_profile(self, project, phase_name, event_name, file_path): if file_path == "": raise SherlockLoadHarmonicProfileError(message="File name is invalid.") if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() + request = SherlockLifeCycleService_pb2.LoadHarmonicProfileRequest( project=project, phaseName=phase_name, @@ -1942,20 +1965,22 @@ def load_harmonic_profile(self, project, phase_name, event_name, file_path): raise e @require_version() - def load_shock_profile_dataset(self, project, phase_name, event_name, file_path): + def load_shock_profile_dataset( + self, project: str, phase_name: str, event_name: str, file_path: str + ) -> int: """Load shock profile dataset from a .csv or .dat file. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project - phase_name : str + phase_name: str Name of the lifecycle phase to add this event to. - event_name : str + event_name: str Name of the random vibe event. - file_path : str + file_path: str File path for thermal profile .dat or .csv file Returns @@ -1974,7 +1999,7 @@ def load_shock_profile_dataset(self, project, phase_name, event_name, file_path) True, True, project="Test", - cca_name="Card", + cca_name="Card" ) """ @@ -1988,8 +2013,7 @@ def load_shock_profile_dataset(self, project, phase_name, event_name, file_path) if file_path == "": raise SherlockLoadShockProfileDatasetError(message="File path is invalid.") if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.LoadShockProfilePulsesRequest( project=project, @@ -2008,20 +2032,22 @@ def load_shock_profile_dataset(self, project, phase_name, event_name, file_path) raise e @require_version() - def load_shock_profile_pulses(self, project, phase_name, event_name, file_path): + def load_shock_profile_pulses( + self, project: str, phase_name: str, event_name: str, file_path: str + ) -> int: """Load shock profile pulses from a .csv .dat file. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project - phase_name : str + phase_name: str Name of the lifecycle phase to add this event to. - event_name : str + event_name: str Name of the random vibe event. - file_path : str + file_path: str Path for thermal profile .dat or .csv file Returns @@ -2046,7 +2072,7 @@ def load_shock_profile_pulses(self, project, phase_name, event_name, file_path): project="Tutorial", phase_name="Phase 1", event_name="Shock Event", - file_path="Test_Profile.dat", + file_path="Test_Profile.dat" ) """ @@ -2060,8 +2086,7 @@ def load_shock_profile_pulses(self, project, phase_name, event_name, file_path): if file_path == "": raise SherlockLoadShockProfilePulsesError(message="File path is invalid.") if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockLifeCycleService_pb2.LoadShockProfilePulsesRequest( project=project, diff --git a/src/ansys/sherlock/core/model.py b/src/ansys/sherlock/core/model.py index 0d39ac4c..63871050 100644 --- a/src/ansys/sherlock/core/model.py +++ b/src/ansys/sherlock/core/model.py @@ -3,22 +3,25 @@ """Module containing all model generation capabilities.""" import os.path +import grpc + +from ansys.sherlock.core.types.analysis_types import ElementOrder + try: - import SherlockAnalysisService_pb2 import SherlockModelService_pb2 + from SherlockModelService_pb2 import MeshType, TraceOutputType import SherlockModelService_pb2_grpc except ModuleNotFoundError: from ansys.api.sherlock.v0 import SherlockModelService_pb2 from ansys.api.sherlock.v0 import SherlockModelService_pb2_grpc - from ansys.api.sherlock.v0 import SherlockAnalysisService_pb2 - -from typing import List + from SherlockModelService_pb2 import MeshType, TraceOutputType from ansys.sherlock.core import LOG from ansys.sherlock.core.errors import ( SherlockExportAEDBError, SherlockExportFEAModelError, SherlockModelServiceError, + SherlockNoGrpcConnectionException, ) from ansys.sherlock.core.grpc_stub import GrpcStub from ansys.sherlock.core.types.common_types import Measurement @@ -28,7 +31,7 @@ class Model(GrpcStub): """Contains all model generation capabilities.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize a gRPC stub for the Sherlock Model service.""" super().__init__(channel, server_version) self.stub = SherlockModelService_pb2_grpc.SherlockModelServiceStub(channel) @@ -36,46 +39,46 @@ def __init__(self, channel, server_version): @require_version() def export_trace_reinforcement_model( self, - project_name, - cca_name, - export_file, - overwrite=True, - display_model=False, - generate_models_for_all_layers=False, - coordinate_units="mm", - trace_param_diameter_threshold_val=2, - trace_param_diameter_threshold_unit="mm", - trace_param_min_hole_diameter_val=0.25, - trace_param_min_hole_diameter_unit="mm", - trace_drill_hole_modeling="DISABLED", - trace_drill_hole_min_diameter_val=2, - trace_drill_hole_min_diameter_unit="mm", - trace_drill_hole_max_edge_val=1, - trace_drill_hole_max_edge_unit="mm", - ): + project_name: str, + cca_name: str, + export_file: str, + overwrite: bool = True, + display_model: bool = False, + generate_models_for_all_layers: bool = False, + coordinate_units: str = "mm", + trace_param_diameter_threshold_val: float = 2, + trace_param_diameter_threshold_unit: str = "mm", + trace_param_min_hole_diameter_val: float = 0.25, + trace_param_min_hole_diameter_unit: str = "mm", + trace_drill_hole_modeling: str = "DISABLED", + trace_drill_hole_min_diameter_val: float = 2, + trace_drill_hole_min_diameter_unit: str = "mm", + trace_drill_hole_max_edge_val: float = 1, + trace_drill_hole_max_edge_unit: str = "mm", + ) -> int: r"""Export a trace reinforcement model. Available Since: 2023R1 Parameters ---------- - project_name : str + project_name: str Name of the Sherlock project to generate the trace reinforcement model for. - cca_name : str + cca_name: str Name of the CCA to generate the trace reinforcement model from. - export_file : str - Path for saving exported files to. The file extension must be ``".wbjn"``. - overwrite : bool, optional + export_file: str + Path for saving exported files to. The file extension must be ``.wbjn``. + overwrite: bool, optional Whether to overwrite an existing file having the same file name. The default is ``True``. - display_model : bool, optional + display_model: bool, optional Whether to launch and display the exported model in Ansys Workbench Mechanical once the export finishes. The default is ``False``. - generate_models_for_all_layers : bool, optional + generate_models_for_all_layers: bool, optional Whether to generate and export trace models for not only the generated trace reinforcement layers but also all other layers. The default is ``False``, in which case only trace reinforcement layers are generated and exported. - coordinate_units : str, optional + coordinate_units: str, optional Units of the model coordinates to use when exporting a model. The default is ``"mm"``. trace_param_diameter_threshold_val: float, optional @@ -157,8 +160,7 @@ def export_trace_reinforcement_model( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() export_request = SherlockModelService_pb2.ExportTraceReinforcementModelRequest() export_request.project = project_name @@ -212,33 +214,33 @@ def export_trace_reinforcement_model( def generate_trace_model( self, project_name, - cca_name="", - copper_layer_name="", - max_arc_segment=0.0, - max_arc_segment_units="mm", - min_trace_area=0.0, - min_trace_area_units="mm2", - min_hole_area=0.0, - min_hole_area_units="mm2", - use_snapshot_for_non_image_layer=False, - ): + cca_name: str = "", + copper_layer_name: str = "", + max_arc_segment: float = 0.0, + max_arc_segment_units: str = "mm", + min_trace_area: float = 0.0, + min_trace_area_units: str = "mm2", + min_hole_area: float = 0.0, + min_hole_area_units: str = "mm2", + use_snapshot_for_non_image_layer: bool = False, + ) -> int: r"""Generate one or more trace models for a project. Available Since: 2023R2 Parameters ---------- - project_name : str + project_name: str Name of the Sherlock project to generate one or more trace models for. - cca_name : str, optional + cca_name: str, optional Name of the CCA to generate one or more trace models from. The default is ``""``, in which case trace models are generated for CCAs and all layers. - copper_layer_name : str, optional + copper_layer_name: str, optional Name of the copper layer to generate one or more trace models from. The default is ``""``, in which case trace models are generated either for the given CCA or for all layers. - max_arc_segment : float, optional + max_arc_segment: float, optional Maximum length of the segment to generate when Sherlock converts EDA arc drawing commands to line segments. The default is ``0.0``. Smaller values for the maximum arc segment result in smoother @@ -246,19 +248,19 @@ def generate_trace_model( larger number of shorter segments is higher. Such short segments cause the FEA tool to generate a larger number of smaller elements to represent the curved solid. - max_arc_segment_units : str, optional + max_arc_segment_units: str, optional Units for the maximum arc segment. The default is ``"mm"``. - min_trace_area : float, optional + min_trace_area: float, optional Minimum area of any trace polygon to include in the trace model. The default is ``0.0``, which turns off any area filtering. - min_trace_area_units : str, optional + min_trace_area_units: str, optional Units for the minimum trace area. The default is ``"mm2"``. - min_hole_area : float, optional + min_hole_area: float, optional Minimum area of any trace hole to include in the trace model. The default is ``0.0``, which turns off any hole filtering. - min_hole_area_units : str, optional + min_hole_area_units: str, optional Units for the minimum hole area. The default is ``"mm2"``. - use_snapshot_for_non_image_layer : bool, optional + use_snapshot_for_non_image_layer: bool, optional Whether to use an image to generate the trace model for layers that are not image layers. The default is ``False``. If ``True`` and a snapshot image for the layer exists, the snapshot image is used. Otherwise, an image is created @@ -288,8 +290,7 @@ def generate_trace_model( raise if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - raise + raise SherlockNoGrpcConnectionException() gen_request = SherlockModelService_pb2.GenerateTraceModelRequest() gen_request.project = project_name @@ -316,28 +317,28 @@ def generate_trace_model( @require_version(242) def export_aedb( self, - project_name, - cca_name, - export_file, - overwrite=True, - display_model=False, - ): + project_name: str, + cca_name: str, + export_file: str, + overwrite: bool = True, + display_model: bool = False, + ) -> int: r"""Export an Electronics Desktop model. Available Since: 2024R2 Parameters ---------- - project_name : str + project_name: str Name of the Sherlock project to generate the EDB model for. - cca_name : str + cca_name: str Name of the CCA to generate the EDB model from. - export_file : str + export_file: str Directory for saving exported model to. - overwrite : bool, optional + overwrite: bool, optional Whether to overwrite an existing file having the same file name. The default is ``True``. - display_model : bool, optional + display_model: bool, optional Whether to launch and display the exported model in Ansys Electronics Desktop once the export finishes. The default is ``False``. @@ -367,8 +368,7 @@ def export_aedb( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() export_request = SherlockModelService_pb2.ExportAEDBRequest() export_request.project = project_name @@ -388,14 +388,14 @@ def export_aedb( raise @require_version(242) - def exportTraceModel(self, layer_params): + def exportTraceModel(self, layer_params: list[bool | int | float | str]) -> int: r"""Export a trace model to a specified output file. Available Since: 2024R2 Parameters ---------- - layer_params : list + layer_params : list[bool | int | float | str] list of parameters for export a trace model of a single copper layer. Returns @@ -405,12 +405,12 @@ def exportTraceModel(self, layer_params): Examples -------- + >>> from ansys.sherlock.core.types.analysis_types import ElementOrder >>> from ansys.sherlock.core import launcher >>> from ansys.api.sherlock.v0 import SherlockModelService_pb2 - >>> from ansys.api.sherlock.v0 import SherlockAnalysisService_pb2 >>> sherlock = launcher.launch_sherlock() >>> list_of_params_for_layers = [] - >>> list_of_params_for_layers.add( + >>> list_of_params_for_layers.append( sherlock.model.createExportTraceCopperLayerParams( "Tutorial Project", "Main Board", @@ -424,7 +424,7 @@ def exportTraceModel(self, layer_params): SherlockModelService_pb2.MeshType.NONE, False, SherlockModelService_pb2.TraceOutputType.ALL_REGIONS, - SherlockAnalysisService_pb2.ElementOrder.Linear, + ElementOrder.LINEAR, 1.0, "mm". 1, @@ -438,8 +438,7 @@ def exportTraceModel(self, layer_params): """ try: if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - raise + raise SherlockNoGrpcConnectionException() request = SherlockModelService_pb2.ExportTraceModelRequest() request.traceModelExportParams.extend(layer_params) @@ -461,24 +460,24 @@ def createExportTraceCopperLayerParams( cca_name, output_file_path, copper_layer, - overwrite=False, - display_after=False, - clear_FEA_database=False, - use_FEA_model_ID=False, - coord_units="mm", - mesh_type=SherlockModelService_pb2.MeshType.NONE, - is_modeling_region_enabled=False, - trace_output_type=SherlockModelService_pb2.TraceOutputType.ALL_REGIONS, - element_order=SherlockAnalysisService_pb2.ElementOrder.Linear, - max_mesh_size=1.0, - max_mesh_size_units="mm", - max_holes_per_trace=2, - is_drill_hole_modeling_enabled=False, - drill_hole_min_diameter=1.0, - drill_hole_min_diameter_units="mm", - drill_hole_max_edge_length=1.0, - drill_hole_max_edge_length_units="mm", - ): + overwrite: bool = False, + display_after: bool = False, + clear_FEA_database: bool = False, + use_FEA_model_ID: bool = False, + coord_units: str = "mm", + mesh_type: int = MeshType.NONE, + is_modeling_region_enabled: bool = False, + trace_output_type: int = TraceOutputType.ALL_REGIONS, + element_order: ElementOrder = ElementOrder.LINEAR, + max_mesh_size: float = 1.0, + max_mesh_size_units: str = "mm", + max_holes_per_trace: int = 2, + is_drill_hole_modeling_enabled: bool = False, + drill_hole_min_diameter: float = 1.0, + drill_hole_min_diameter_units: str = "mm", + drill_hole_max_edge_length: float = 1.0, + drill_hole_max_edge_length_units: str = "mm", + ) -> SherlockModelService_pb2.TraceModelExportParams: r"""Create a set of parameters to be used to export a single copper layer. Creates TraceModelExportParams object that can be added to an export trace model request. @@ -542,7 +541,7 @@ def createExportTraceCopperLayerParams( Examples -------- >>> from ansys.sherlock.core import launcher - >>> from ansys.api.sherlock.v0 import SherlockAnalysisService_pb2 + >>> from ansys.sherlock.core.types.analysis_types import ElementOrder >>> from ansys.api.sherlock.v0 import SherlockModelService_pb2 >>> sherlock = launcher.launch_sherlock() >>> copper_1_layer = sherlock.model.createExportTraceCopperLayerParams( @@ -558,7 +557,7 @@ def createExportTraceCopperLayerParams( SherlockModelService_pb2.MeshType.NONE, False, SherlockModelService_pb2.TraceOutputType.ALL_REGIONS, - SherlockAnalysisService_pb2.ElementOrder.Linear, + ElementOrder.LINEAR, 1.0, "mm", 2, @@ -580,7 +579,7 @@ def createExportTraceCopperLayerParams( SherlockModelService_pb2.MeshType.NONE, False, SherlockModelService_pb2.TraceOutputType.ALL_REGIONS, - SherlockAnalysisService_pb2.ElementOrder.Linear, + ElementOrder.LINEAR, 1.0, "mm", 2, @@ -645,71 +644,71 @@ def export_FEA_model( cca_name: str, export_file: str, analysis: str, - drill_hole_parameters: List[dict], + drill_hole_parameters: list[dict[str, str | Measurement]], detect_lead_modeling: str, - lead_model_parameters: List[dict], + lead_model_parameters: list[dict[str, int | str | Measurement]], display_model: bool, clear_FEA_database: bool, use_FEA_model_id: bool, coordinate_units: str, - ): + ) -> int: """ Export a FEA model. Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - export_file : str - Full path for saving exported files to. The file extension must be ``".wbjn"``. - analysis : str + export_file: str + Full path for saving exported files to. The file extension must be ``.wbjn``. + analysis: str The type of analysis that is being exported. Valid values are ``NaturalFreq``, ``HarmonicVibe``, ``ICTAnalysis``, ``MechanicalShock`` or ``RandomVibe``. - drill_hole_parameters : list + drill_hole_parameters: list[dict[str, str | Measurement]] List of the drill hole parameters consisting of these properties: - - drill_hole_modeling : str + - drill_hole_modeling: str The status of the drill hole modeling feature. If enabled, automatically enable drill hole modeling. Valid values are ``ENABLED/enabled`` or ``DISABLED/disabled``. - - min_hole_diameter : MinHoleDiameter + - min_hole_diameter: MinHoleDiameter The properties of the minimum hole diameter. - - max_edge_length : MaxEdgeLength + - max_edge_length: MaxEdgeLength The properties of the maximum edge length. - detect_lead_modeling : str + detect_lead_modeling: str The status of the detect lead modeling feature. If enabled, automatically enable lead modeling if any part has lead geometry defined. Valid values are ``ENABLED`` or ``DISABLED``. - lead_model_parameters : list + lead_model_parameters: list[dict[str, int | str | Measurement]] List of the lead model parameters consisting of these properties: - - lead_modeling : str + - lead_modeling: str The status of the lead modeling feature. If enabled, automatically enable lead modeling. Valid values are ``ENABLED`` or ``DISABLED``. - - lead_element_order : str + - lead_element_order: str The type of the element order. Valid values are ``First Order (Linear)``, ``Second Order (Quadratic)``, or ``Solid Shell``. - - max_mesh_size : MaxMeshSize + - max_mesh_size: MaxMeshSize The properties of the maximum mesh size. - - vertical_mesh_size : VerticalMeshSize + - vertical_mesh_size: VerticalMeshSize The properties of the vertical mesh size. - - thicknessCount : int, optional + - thicknessCount: int, optional The number of elements through the lead thickness that will be created per lead. The default value is 3 and the maximum is 5. Only used when the advanced lead mesh setting is enabled. - - aspectRatio : int, optional + - aspectRatio: int, optional The aspect ratio is multiplied by the lead thickness divided by the through thickness count to give the lead element height. The default value is 2 and the maximum is 10. Only used when the advanced lead mesh setting is enabled. - display_model : bool + display_model: bool Whether to display the model after export. - clear_FEA_database : bool + clear_FEA_database: bool Whether to clear FEA database before defining model. - use_FEA_model_id : bool + use_FEA_model_id: bool Whether to use FEA model ID. - coordinate_units : str + coordinate_units: str Units of the model coordinates to use when exporting a model. @@ -788,8 +787,7 @@ def export_FEA_model( raise SherlockExportFEAModelError(message="Vertical mesh size is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() export_request = SherlockModelService_pb2.ExportFEAModelRequest() export_request.project = project diff --git a/src/ansys/sherlock/core/parts.py b/src/ansys/sherlock/core/parts.py index f260838c..64b60456 100644 --- a/src/ansys/sherlock/core/parts.py +++ b/src/ansys/sherlock/core/parts.py @@ -1,7 +1,6 @@ # Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module containing all parts management capabilities.""" - try: import SherlockPartsService_pb2 import SherlockPartsService_pb2_grpc @@ -16,6 +15,7 @@ SherlockExportPartsListError, SherlockGetPartLocationError, SherlockImportPartsListError, + SherlockNoGrpcConnectionException, SherlockUpdatePartsFromAVLError, SherlockUpdatePartsListError, SherlockUpdatePartsListPropertiesError, @@ -44,7 +44,10 @@ def __init__(self, channel, server_version): self.BOARD_SIDES = None @staticmethod - def _add_part_loc_request(request, parts): + def _add_part_loc_request( + request: SherlockPartsService_pb2.UpdatePartsLocationsRequest, + parts: list[tuple[str, str, str, str, str, str, str]], + ) -> None: """Add part locations to the request.""" for p in parts: part = request.partLoc.add() @@ -56,7 +59,9 @@ def _add_part_loc_request(request, parts): part.boardSide = p[5] part.mirrored = p[6] - def _check_part_loc_validity(self, part_locations): + def _check_part_loc_validity( + self, part_locations: list[tuple[str, str, str, str, str, str, str]] + ) -> None: """Check input to see if it is a valid part location list.""" if not isinstance(part_locations, list): raise SherlockUpdatePartsLocationsError(message="Part location argument is invalid.") @@ -152,27 +157,27 @@ def _init_board_sides(self): @require_version() def update_parts_list( self, - project, - cca_name, - part_library, - matching_mode, - duplication_mode, - ): + project: str, + cca_name: str, + part_library: str, + matching_mode: str, + duplication_mode: PartsListSearchDuplicationMode, + ) -> int: """Update a parts list based on matching and duplication preferences. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - part_library : str + part_library: str Name of the parts library. - matching_mode : str + matching_mode: str Matching mode for updates. - duplication_mode : PartsListSearchDuplicationMode + duplication_mode: PartsListSearchDuplicationMode How to handle duplication during the update. Returns @@ -198,7 +203,7 @@ def update_parts_list( "Card", "Sherlock Part Library", "Both", - PartsListSearchDuplicationMode.ERROR, + PartsListSearchDuplicationMode.ERROR ) """ try: @@ -214,8 +219,7 @@ def update_parts_list( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.UpdatePartsListRequest( project=project, @@ -241,34 +245,36 @@ def update_parts_list( raise e @require_version() - def update_parts_locations(self, project, cca_name, part_loc): + def update_parts_locations( + self, project: str, cca_name: str, part_loc: list[tuple[str, str, str, str, str, str, str]] + ) -> int: """Update one or more part locations. Available Since: 2022R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - part_loc : list + part_loc: list[tuple[str, str, str, str, str, str, str]] List defining the part locations. The list consists of these properties: - - refDes : str + - refDes: str Reference designator of the part. - - x : str + - x: str Value for the x coordinate. - - y : str + - y: str Value for the y coordinate. - rotation: str Rotation. - location_units: str Locations units. - - board_side : str + - board_side: str Board side. - - mirrored : str + - mirrored: str Mirrored. Returns @@ -315,8 +321,7 @@ def update_parts_locations(self, project, cca_name, part_loc): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.UpdatePartsLocationsRequest( project=project, @@ -344,20 +349,22 @@ def update_parts_locations(self, project, cca_name, part_loc): raise e @require_version() - def update_parts_locations_by_file(self, project, cca_name, file_path, numeric_format=""): + def update_parts_locations_by_file( + self, project: str, cca_name: str, file_path: str, numeric_format: str = "" + ) -> int: """Update one or more part locations using a CSV file. Available Since: 2023R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - file_path : str + file_path: str Full path to the file with the components and location properties. - numeric_format : str, optional + numeric_format: str, optional Numeric format for the file, which indicates whether commas or points are used as decimal markers. The default is ``""``, in which case ``"English (United States)"`` is the numeric format. This @@ -384,7 +391,7 @@ def update_parts_locations_by_file(self, project, cca_name, file_path, numeric_f >>> sherlock.parts.update_parts_locations_by_file( "Test", "Card", - "Parts Locations.csv", + "Parts Locations.csv" ) """ try: @@ -400,8 +407,7 @@ def update_parts_locations_by_file(self, project, cca_name, file_path, numeric_f raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.UpdatePartsLocationsByFileRequest( project=project, @@ -429,20 +435,22 @@ def update_parts_locations_by_file(self, project, cca_name, file_path, numeric_f raise e @require_version() - def import_parts_list(self, project, cca_name, import_file, import_as_user_src): + def import_parts_list( + self, project: str, cca_name: str, import_file: str, import_as_user_src: bool + ) -> int: """Import a parts list for a CCA. Available Since: 2021R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - import_file : str + import_file: str Full path to the CSV file with the parts list. - import_as_user_src : bool + import_as_user_src: bool Whether to set the data source of the properties to ``"User"``. Otherwise, the data source is set to the name of the CSV file. @@ -468,7 +476,7 @@ def import_parts_list(self, project, cca_name, import_file, import_as_user_src): "Test", "Card", "Parts List.csv", - False, + False ) """ try: @@ -483,8 +491,7 @@ def import_parts_list(self, project, cca_name, import_file, import_as_user_src): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.ImportPartsListRequest( project=project, @@ -506,18 +513,18 @@ def import_parts_list(self, project, cca_name, import_file, import_as_user_src): raise e @require_version() - def export_parts_list(self, project, cca_name, export_file): + def export_parts_list(self, project: str, cca_name: str, export_file: str) -> int: """Export a parts list for a CCA. Available Since: 2021R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - export_file : str + export_file: str Full path for the CSV file to export the parts list to. Returns @@ -541,7 +548,7 @@ def export_parts_list(self, project, cca_name, export_file): >>> sherlock.parts.export_parts_list( "Test", "Card", - "Parts List.csv", + "Parts List.csv" ) """ try: @@ -556,8 +563,7 @@ def export_parts_list(self, project, cca_name, export_file): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.ExportPartsListRequest( project=project, ccaName=cca_name, exportFile=export_file @@ -576,16 +582,16 @@ def export_parts_list(self, project, cca_name, export_file): raise e @require_version() - def enable_lead_modeling(self, project, cca_name): + def enable_lead_modeling(self, project: str, cca_name: str): """Enable lead modeling for leaded parts. Available Since: 2021R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. Returns @@ -608,7 +614,7 @@ def enable_lead_modeling(self, project, cca_name): ) >>> sherlock.parts.enable_lead_modeling( "Test", - "Card", + "Card" ) """ try: @@ -638,26 +644,28 @@ def enable_lead_modeling(self, project, cca_name): raise e @require_version() - def get_part_location(self, project, cca_name, ref_des, location_units): + def get_part_location( + self, project: str, cca_name: str, ref_des: str, location_units: str + ) -> list[PartLocation]: """Return the location properties for one or more part. Available Since: 2022R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - ref_des : str - Reference designator for specific part. + ref_des: str + Comma separated list of reference designators of parts to retrieve locations for. location_units: str Valid units for a part's location. Returns ------- - list - List of PartLocation objects. + list[PartLocation] + PartLocation for each part that corresponds to the reference designators. Examples -------- @@ -690,8 +698,7 @@ def get_part_location(self, project, cca_name, ref_des, location_units): if location_units == "": raise SherlockGetPartLocationError(message="Location unit is invalid.") if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.GetPartLocationRequest( project=project, @@ -729,9 +736,9 @@ def update_parts_from_AVL( Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. matching_mode: str Determines how parts are matched against the AVL @@ -745,14 +752,14 @@ def update_parts_from_AVL( Returns ------- UpdatePartsListFromAVLResponse - - returnCode : ReturnCode - - value : int + - returnCode: ReturnCode + - value: int Status code of the response. 0 for success. - - message : str + - message: str Indicates general errors that occurred while attempting to update parts - - numPartsUpdated : int + - numPartsUpdated: int Number of parts updated - - updateErrors : list + - updateErrors: list Errors found when updating part Examples @@ -798,8 +805,7 @@ def update_parts_from_AVL( ) if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() # Call method on server response = self.stub.updatePartsListFromAVL(request) @@ -817,7 +823,12 @@ def update_parts_from_AVL( raise e @require_version(242) - def update_parts_list_properties(self, project, cca_name, part_properties): + def update_parts_list_properties( + self, + project: str, + cca_name: str, + part_properties: list[dict[str, list[dict[str, str]] | list[str]]], + ) -> int: """ Update one or more properties of one or more parts in a parts list. @@ -825,22 +836,22 @@ def update_parts_list_properties(self, project, cca_name, part_properties): Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - part_properties : list - List of part properties consisting of these properties: + part_properties: list[dict[str, list[str] | list[dict[str, str]]]] + Part properties consisting of these properties: - - reference_designators : List of str, optional - List of the reference designator for each part to be updated. If not included, + - reference_designators: list[str], optional + Reference designator for each part to be updated. If not included, update properties for all parts in the CCA. - - properties : list - List of properties consisting of these properties: + - properties: list[dict[str, str]] + Part properties consisting of these properties: - - name : str + - name: str Name of property to be updated. - - value : str + - value: str Value to be applied to the chosen part property. Returns @@ -891,21 +902,20 @@ def update_parts_list_properties(self, project, cca_name, part_properties): ) properties = part_property["properties"] - for j, property in enumerate(properties): - if len(property) < 1 or len(property) > 2: + for j, prop in enumerate(properties): + if len(prop) < 1 or len(prop) > 2: raise SherlockUpdatePartsListPropertiesError( - f"Number of elements ({len(property)}) " f"is wrong for property {j}." + f"Number of elements ({len(prop)}) " f"is wrong for property {j}." ) - elif not isinstance(property["name"], str) or property["name"] == "": + elif not isinstance(prop["name"], str) or prop["name"] == "": raise SherlockUpdatePartsListPropertiesError( f"Name is required " f"for property {j}." ) - elif not isinstance(property["value"], str): + elif not isinstance(prop["value"], str): raise SherlockUpdatePartsListPropertiesError(message="Value is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.UpdatePartsListPropertiesRequest( project=project, ccaName=cca_name @@ -946,31 +956,31 @@ def update_parts_list_properties(self, project, cca_name, part_properties): @require_version(242) def export_net_list( self, - project, - cca_name, - output_file, - col_delimiter=TableDelimiter.COMMA, - overwrite_existing=False, - utf8_enabled=False, - ): + project: str, + cca_name: str, + output_file: str, + col_delimiter: str = TableDelimiter.COMMA, + overwrite_existing: bool = False, + utf8_enabled: bool = False, + ) -> int: """Export a net list to a delimited output file. Available Since: 2024R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - output_file : str + output_file: str Full path for the output file where the net list will be written. - col_delimiter : TableDelimiter, optional + col_delimiter: TableDelimiter, optional The delimiter character to be used. Defaults to TableDelimiter.COMMA. - overwrite_existing : bool, optional + overwrite_existing: bool, optional Flag to determine if existing .CSV files should be overwritten if they match the output_file. Defaults to False. - utf8_enabled : bool, optional + utf8_enabled: bool, optional Flag that specifies if UTF-8 will be used for .CSV files. Defaults to False. Returns @@ -1009,8 +1019,7 @@ def export_net_list( raise SherlockExportNetListError(message="Output file path is required.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockPartsService_pb2.ExportNetListRequest( project=project, diff --git a/src/ansys/sherlock/core/project.py b/src/ansys/sherlock/core/project.py index d80c911b..3aa2958f 100644 --- a/src/ansys/sherlock/core/project.py +++ b/src/ansys/sherlock/core/project.py @@ -2,6 +2,9 @@ """Module containing all project management capabilities.""" import os +from typing import Optional + +import grpc try: import SherlockProjectService_pb2 @@ -27,6 +30,7 @@ SherlockListCCAsError, SherlockListStrainMapsError, SherlockListThermalMapsError, + SherlockNoGrpcConnectionException, SherlockUpdateThermalMapsError, ) from ansys.sherlock.core.grpc_stub import GrpcStub @@ -38,6 +42,8 @@ ImageFile, LegendBounds, StrainMapsFileType, + ThermalBoardSide, + ThermalMapsFileType, ) from ansys.sherlock.core.utils.version_check import require_version @@ -45,20 +51,20 @@ class Project(GrpcStub): """Contains all project management capabilities.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize a gRPC stub for Sherlock Project service.""" super().__init__(channel, server_version) self.stub = SherlockProjectService_pb2_grpc.SherlockProjectServiceStub(channel) @require_version() - def delete_project(self, project): + def delete_project(self, project: str) -> int: """Delete a Sherlock project. Available Since: 2022R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. Returns @@ -80,8 +86,7 @@ def delete_project(self, project): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.DeleteProjectRequest(project=project) @@ -100,31 +105,31 @@ def delete_project(self, project): @require_version() def import_odb_archive( self, - archive_file, - process_layer_thickness, - include_other_layers, - process_cutout_file, - guess_part_properties, - ims_stackup=False, - project=None, - cca_name=None, - polyline_simplification=False, - polyline_tolerance=0.1, - polyline_tolerance_units="mm", - ): + archive_file: str, + process_layer_thickness: bool, + include_other_layers: bool, + process_cutout_file: bool, + guess_part_properties: bool, + ims_stackup: bool = False, + project: Optional[str] = None, + cca_name: Optional[str] = None, + polyline_simplification: bool = False, + polyline_tolerance: float = 0.1, + polyline_tolerance_units: str = "mm", + ) -> int: """Import an ODB++ archive file. Available Since: 2021R1 Parameters ---------- - archive_file : str + archive_file: str Full path to the ODB++ archive file. - process_layer_thickness : bool + process_layer_thickness: bool Whether to assign stackup thickness. - include_other_layers : bool + include_other_layers: bool Whether to include other layers. - process_cutout_file : bool + process_cutout_file: bool Whether to process cutouts. guess_part_properties: bool Whether to guess part properties. @@ -133,7 +138,7 @@ def import_odb_archive( project: str, optional Name of the Sherlock project. The default is ``None``, in which case the name of the ODB++ archive file is used for the project name. - cca_name : str, optional + cca_name: str, optional Name of the CCA name. The default is ``None``, in which case the name of the ODB++ archive file is used for the CCA name. polyline_simplification: bool, optional @@ -169,8 +174,7 @@ def import_odb_archive( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() if project is None: project = os.path.splitext(os.path.basename(archive_file))[0] @@ -206,31 +210,31 @@ def import_odb_archive( @require_version() def import_ipc2581_archive( self, - archive_file, - include_other_layers, - guess_part_properties, - project=None, - cca_name=None, - polyline_simplification=False, - polyline_tolerance=0.1, - polyline_tolerance_units="mm", - ): + archive_file: str, + include_other_layers: bool, + guess_part_properties: bool, + project: Optional[str] = None, + cca_name: Optional[str] = None, + polyline_simplification: bool = False, + polyline_tolerance: float = 0.1, + polyline_tolerance_units: str = "mm", + ) -> int: """Import an IPC-2581 archive file. Available Since: 2021R1 Parameters ---------- - archive_file : str + archive_file: str Full path to the IPC-2581 archive file. - include_other_layers : bool + include_other_layers: bool Whether to include other layers. guess_part_properties: bool Whether to guess part properties project: str, optional Name of the Sherlock project. The default is ``None``, in which case the name of the IPC-2581 archive file is used for the project name. - cca_name : str, optional + cca_name: str, optional Name of the CCA. The default is ``None``, in which case the name of the IPC-2581 archive file is used for the CCA name. polyline_simplification: bool, optional @@ -264,8 +268,7 @@ def import_ipc2581_archive( raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() if project is None: project = os.path.splitext(os.path.basename(archive_file))[0] @@ -296,18 +299,20 @@ def import_ipc2581_archive( raise e @require_version() - def generate_project_report(self, project, author, company, report_file): + def generate_project_report( + self, project: str, author: str, company: str, report_file: str + ) -> int: """Generate a project report. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. - author : str + author: str Name of the author who is generating the report. - company : str + company: str Name of the author's company. report_file: str Full path to where to create the report. @@ -329,7 +334,7 @@ def generate_project_report(self, project, author, company, report_file): "Tutorial", "John Doe", "Example", - "Project Report.pdf", + "Project Report.pdf" ) """ try: @@ -346,8 +351,7 @@ def generate_project_report(self, project, author, company, report_file): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.GenReportRequest( project=project, @@ -373,7 +377,9 @@ def generate_project_report(self, project, author, company, report_file): raise SherlockGenerateProjectReportError(str(e)) @require_version() - def list_ccas(self, project, cca_names=None): + def list_ccas( + self, project: str, cca_names: Optional[list[str]] = None + ) -> dict[str, str | dict[str, str]]: """List CCAs and subassembly CCAs assigned to each CCA or given CCAs. Available Since: 2023R2 @@ -382,8 +388,8 @@ def list_ccas(self, project, cca_names=None): ---------- project: str Name of the Sherlock project. - cca_names : List of str, optional - List of CCA names. The default is ``None``, in which case all CCAs + cca_names: list[str], optional + CCA names. The default is ``None``, in which case all CCAs in the project are returned. Returns @@ -395,7 +401,7 @@ def list_ccas(self, project, cca_names=None): -------- >>> from ansys.sherlock.core.launcher import launch_sherlock >>> sherlock = launch_sherlock() - >>> ccas = project.list_ccas("AssemblyTutorial",["Main Board"]) + >>> ccas = sherlock.project.list_ccas("AssemblyTutorial", ["Main Board"]) """ try: if project == "": @@ -405,8 +411,7 @@ def list_ccas(self, project, cca_names=None): raise SherlockListCCAsError(message="cca_names is not a list.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.ListCCAsRequest(project=project) @@ -432,21 +437,21 @@ def list_ccas(self, project, cca_names=None): return response.ccas @require_version(241) - def add_cca(self, project, cca_properties): + def add_cca(self, project: str, cca_properties: list[dict[str, bool | float | str]]) -> int: """Add one or more CCAs to a project. Available Since: 2023R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_properties : list + cca_properties: list[dict[str, bool | float | str]] List of CCAs to be added consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - - description : str + - description: str Description of the CCA. The default is ``None``. - default_solder_type: str The default solder type. The default is ``None``. @@ -549,8 +554,7 @@ def add_cca(self, project, cca_properties): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.addCCA(request) @@ -565,7 +569,11 @@ def add_cca(self, project, cca_properties): raise e @require_version() - def add_strain_maps(self, project, strain_maps): + def add_strain_maps( + self, + project: str, + strain_maps: list, + ) -> int: """Add strain map files to CCAs in a Sherlock project. Available Since: 2023R2 @@ -574,26 +582,26 @@ def add_strain_maps(self, project, strain_maps): ---------- project: str Name of the Sherlock project to add strain maps to. - strain_maps : list - List of strain maps consisting of these properties: + strain_maps: list + Strain maps consisting of these properties: - - strain_map_file : str + - strain_map_file: str Full path to the CSV file with the strain maps. - - file_comment : str + - file_comment: str Comment to associate with the file. - - file_type : StrainMapsFileType + - file_type: StrainMapsFileType Strain maps file type. Options are CSV, Excel, and Image. - - header_row_count : int + - header_row_count: int Number of rows before the file's column header. - - reference_id_column : str + - reference_id_column: str Name of the column in the file with reference IDs. - - strain_column : str + - strain_column: str Name of the column in the file with strain values. - - strain_units : str + - strain_units: str Strain units. Options are ``µε`` and ``ε``. - - image_file : StrainMapImageFile, optional + - image_file: StrainMapImageFile, optional The properties of the strain map file to add. - - ccas : list, optional + - ccas: list, optional List of CCA names to assign the file to. When no list is specified, the file is assigned to all CCAs in the project. @@ -630,7 +638,7 @@ def add_strain_maps(self, project, strain_maps): ) ] ) - >>> strain_map_image_properties = ( + >>> properties = ( BoardBounds([ (1.0, 2.0), (3.0, 4.0), @@ -652,7 +660,7 @@ def add_strain_maps(self, project, strain_maps): "StrainMap.jpg", "This is the strain map image for the project", StrainMapsFileType.IMAGE, - strain_map_image_properties, + properties, ["Main Board"] ) ] @@ -767,8 +775,7 @@ def add_strain_maps(self, project, strain_maps): ) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.AddStrainMapRequest(project=project) @@ -840,7 +847,9 @@ def add_strain_maps(self, project, strain_maps): raise e @require_version() - def list_strain_maps(self, project, cca_names=None): + def list_strain_maps( + self, project: str, cca_names: Optional[list[str]] = None + ) -> list[SherlockProjectService_pb2.ListStrainMapsResponse.CcaStrainMap]: """List the strain maps assigned to each CCA or given CCAs. Available Since: 2023R2 @@ -849,13 +858,13 @@ def list_strain_maps(self, project, cca_names=None): ---------- project: str Name of the Sherlock project. - cca_names : List of str, optional - List of CCA names to provide strain maps for. The default is ``None``, + cca_names: list[str], optional + CCA names to provide strain maps for. The default is ``None``, in which case all CCAs in the project are returned. Returns ------- - list + list[SherlockProjectService_pb2.ListStrainMapsResponse.CcaStrainMap] All strain maps or strain maps for the specified CCAs. Examples @@ -875,8 +884,7 @@ def list_strain_maps(self, project, cca_names=None): raise SherlockListStrainMapsError(message="cca_names is not a list.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.ListStrainMapsRequest(project=project) @@ -902,7 +910,9 @@ def list_strain_maps(self, project, cca_names=None): return response.ccaStrainMaps @require_version(241) - def add_project(self, project_name: str, project_category: str, project_description: str): + def add_project( + self, project_name: str, project_category: str, project_description: str + ) -> int: """Add a sherlock project to sherlock. Available Since: 2024R1 @@ -934,8 +944,7 @@ def add_project(self, project_name: str, project_category: str, project_descript raise SherlockAddProjectError("Project name cannot be blank") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.AddProjectRequest( project=project_name, category=project_category, description=project_description @@ -949,7 +958,7 @@ def add_project(self, project_name: str, project_category: str, project_descript return return_code.value @require_version(242) - def list_thermal_maps(self, project, cca_names=None): + def list_thermal_maps(self, project: str, cca_names: Optional[list[str]] = None) -> list: """List the thermal map files and their type assigned to each CCA of given CCAs. Available Since: 2024R2 @@ -958,7 +967,7 @@ def list_thermal_maps(self, project, cca_names=None): ---------- project: str Name of the Sherlock project. - cca_names : List of str, optional + cca_names: List of str, optional List of CCA names to provide thermal maps for. The default is ``None``, in which case all CCAs in the project are returned. @@ -984,8 +993,7 @@ def list_thermal_maps(self, project, cca_names=None): raise SherlockListThermalMapsError(message="cca_names is not a list.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.ListThermalMapsRequest(project=project) @@ -1010,7 +1018,22 @@ def list_thermal_maps(self, project, cca_names=None): return response.ccaThermalMaps @require_version(242) - def update_thermal_maps(self, project, thermal_map_files): + def update_thermal_maps( + self, + project: str, + thermal_map_files: list[ + dict[ + str, + str + | ThermalMapsFileType + | ThermalBoardSide + | CsvExcelFile + | IcepakFile + | ImageFile + | list[str], + ] + ], + ) -> int: """ Update thermal map files to a Sherlock project. @@ -1018,24 +1041,24 @@ def update_thermal_maps(self, project, thermal_map_files): Parameters ---------- - project : str + project: str Name of the Sherlock project to update thermal maps to. - thermal_map_files : list + thermal_map_files: list List of thermal map files consisting of these properties: - - file_name : str + - file_name: str Name of the thermal file to update. - - file_type : ThermalMapsFileType + - file_type: ThermalMapsFileType Thermal maps file type. - - file_comment : str, optional + - file_comment: str, optional Comment to associate with the file. - - thermal_board_side : ThermalBoardSide + - thermal_board_side: ThermalBoardSide Thermal board side. - - file_data : CsvExcelFile|IcepakFile|ImageFile + - file_data: CsvExcelFile|IcepakFile|ImageFile The properties of the thermal map file to update. - - thermal_profiles : List of str + - thermal_profiles: List of str List of thermal profiles. - - cca_names : List of str, optional + - cca_names: List of str, optional List of CCA names to provide thermal maps for. The default is ``None``, in which case all CCAs in the project are returned. @@ -1071,7 +1094,7 @@ def update_thermal_maps(self, project, thermal_map_files): min_temperature=20.0, min_temperature_units="C" ) - >>> thermal_map_files = [ + >>> files = [ { "file_name": "thermal_map_file.jpg", "file_type": ThermalMapsFileType.IMAGE, @@ -1082,7 +1105,7 @@ def update_thermal_maps(self, project, thermal_map_files): "cca_names": ["CCA1", "CCA2"] }, ] - >>> sherlock.project.update_thermal_maps("Tutorial Project", thermal_map_files) + >>> sherlock.project.update_thermal_maps("Tutorial Project", files) """ try: if project == "": @@ -1192,8 +1215,7 @@ def update_thermal_maps(self, project, thermal_map_files): ) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.UpdateThermalMapRequest(project=project) @@ -1297,7 +1319,28 @@ def update_thermal_maps(self, project, thermal_map_files): raise e @require_version(242) - def add_thermal_maps(self, project, add_thermal_map_files): + def add_thermal_maps( + self, + project: str, + add_thermal_map_files: list[ + dict[ + str, + list[ + dict[ + str, + str + | ThermalMapsFileType + | ThermalBoardSide + | CsvExcelFile + | IcepakFile + | ImageFile + | list[str], + ] + ] + | str, + ] + ], + ) -> int: """ Add thermal map files to a Sherlock project. @@ -1305,29 +1348,30 @@ def add_thermal_maps(self, project, add_thermal_map_files): Parameters ---------- - project : str + project: str Name of the Sherlock project to add thermal maps to. - add_thermal_map_files : list + add_thermal_map_files: list[dict[str, list[dict[str, str | ThermalMapsFileType\ + | ThermalBoardSide | CsvExcelFile | IcepakFile | ImageFile | list[str]]] | str]] List of thermal map files consisting of these properties: - - thermal_map_file : str + - thermal_map_file: str Full path to the thermal map file to add. - - thermal_map_file_properties : list + - thermal_map_file_properties: list List of thermal map properties consisting of these properties: - - file_name : str + - file_name: str Name of the thermal file to update. - - file_type : ThermalMapsFileType + - file_type: ThermalMapsFileType Thermal maps file type. - - file_comment : str, optional + - file_comment: str, optional Comment to associate with the file. - - thermal_board_side : ThermalBoardSide + - thermal_board_side: ThermalBoardSide Thermal board side. - - file_data : CsvExcelFile|IcepakFile|ImageFile + - file_data: CsvExcelFile | IcepakFile | ImageFile The properties of the thermal map file to update. - - thermal_profiles : List of str + - thermal_profiles: List of str List of thermal profiles. - - cca_names : List of str, optional + - cca_names: List of str, optional List of CCA names to provide thermal maps for. The default is ``None``, in which case all CCAs in the project are returned. @@ -1363,7 +1407,7 @@ def add_thermal_maps(self, project, add_thermal_map_files): max_temperature=50.0, max_temperature_units="C" ) - >>> add_thermal_map_files = [ + >>> files = [ { "thermal_map_file": "Thermal Image.jpg", "thermal_map_file_properties": [ @@ -1379,7 +1423,7 @@ def add_thermal_maps(self, project, add_thermal_map_files): ] } ] - >>> sherlock.project.add_thermal_maps("Tutorial Project", add_thermal_map_files) + >>> sherlock.project.add_thermal_maps("Tutorial Project", files) """ try: if project == "": @@ -1512,8 +1556,7 @@ def add_thermal_maps(self, project, add_thermal_map_files): ) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.AddThermalMapRequest(project=project) @@ -1607,7 +1650,7 @@ def add_thermal_maps(self, project, add_thermal_map_files): raise e @require_version(242) - def import_project_zip_archive(self, project, category, archive_file): + def import_project_zip_archive(self, project: str, category: str, archive_file: str) -> int: """ Import a zipped project archive -- multiple project mode. @@ -1615,16 +1658,18 @@ def import_project_zip_archive(self, project, category, archive_file): Parameters ---------- - project : str + project: str Name of the Sherlock project. - category : str + category: str Sherlock project category. - archive_file : str + archive_file: str Full path to the .zip archive file containing the project data. + Returns ------- int Status code of the response. 0 for success. + Examples -------- >>> from ansys.sherlock.core.launcher import launch_sherlock @@ -1643,8 +1688,7 @@ def import_project_zip_archive(self, project, category, archive_file): raise SherlockImportProjectZipArchiveError(message="Archive file path is invalid.") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.ImportProjectZipRequest( project=project, category=category, archiveFile=archive_file @@ -1663,7 +1707,7 @@ def import_project_zip_archive(self, project, category, archive_file): @require_version(242) def import_project_zip_archive_single_mode( - self, project, category, archive_file, destination_file_directory + self, project: str, category: str, archive_file: str, destination_file_directory: str ): """ Import a zipped project archive -- single project mode. @@ -1672,18 +1716,20 @@ def import_project_zip_archive_single_mode( Parameters ---------- - project : str + project: str Name of the Sherlock project. - category : str + category: str Sherlock project category. - archive_file : str + archive_file: str Full path to the .zip archive file containing the project data. - destination_file_directory : str + destination_file_directory: str Directory in which the Sherlock project folder will be created. + Returns ------- int Status code of the response. 0 for success. + Examples -------- >>> from ansys.sherlock.core.launcher import launch_sherlock @@ -1715,8 +1761,7 @@ def import_project_zip_archive_single_mode( ) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.ImportProjectZipSingleModeRequest( destFileDir=destination_file_directory @@ -1742,17 +1787,17 @@ def import_project_zip_archive_single_mode( @require_version(251) def export_project( self, - project_name, - export_design_files, - export_result_files, - export_archive_results, - export_user_files, - export_log_files, - export_system_data, - export_file_dir, - export_file_name, - overwrite_existing_file, - ): + project_name: str, + export_design_files: bool, + export_result_files: bool, + export_archive_results: bool, + export_user_files: bool, + export_log_files: bool, + export_system_data: bool, + export_file_dir: str, + export_file_name: str, + overwrite_existing_file: bool, + ) -> int: """ Export a sherlock project. @@ -1760,25 +1805,25 @@ def export_project( Parameters ---------- - project_name : str + project_name: str Name of the project being exported. - export_design_files : bool + export_design_files: bool Determines if design files should be exported. - export_result_files : bool + export_result_files: bool Determines if all analysis module result files should be exported. - export_archive_results : bool + export_archive_results: bool Determines if all archive result files should be exported. - export_user_files : bool + export_user_files: bool Determines if user properties and custom data files should be exported. - export_log_files : bool + export_log_files: bool Determines if Sherlock console and application log files should be exported. - export_system_data : bool + export_system_data: bool Determines if system technical data should be exported. - export_file_dir : str + export_file_dir: str Destination of export file. - export_file_name : str + export_file_name: str Name to be given to the exported file. - overwrite_existing_file : bool + overwrite_existing_file: bool Determines if exported file will overwrite a previously existing file. Returns @@ -1812,8 +1857,7 @@ def export_project( raise SherlockExportProjectError(message="Export file name is invalid") if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockProjectService_pb2.ExportProjectRequest( project=project_name, @@ -1840,22 +1884,23 @@ def export_project( return response.value @require_version(251) - def create_cca_from_modeling_region(self, project, cca_from_mr_properties): + def create_cca_from_modeling_region( + self, project: str, cca_from_mr_properties: list[dict[str, bool | float | str]] + ) -> int: """Create one or more CCAs from modeling regions in a given project. Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_from_mr_properties : list - List of CCAs to be to be created from modeling regions - consisting of these properties: + cca_from_mr_properties: list[dict[str, bool | float | str]] + CCAs to be created from modeling regions consisting of these properties: - - cca_name : str + - cca_name: str Name of the CCA. - - modeling_region_id : str + - modeling_region_id: str Name of the modeling region. - - description : str + - description: str Description of the CCA. - default_solder_type: str The default solder type. The default is ``None``. @@ -1891,7 +1936,7 @@ def create_cca_from_modeling_region(self, project, cca_from_mr_properties): project="Test", cca_name="Card", ) - >>> sherlock.project.create_cca_from_modeling_region() + >>> sherlock.project.create_cca_from_modeling_region( "Test", [{ 'cca_name': 'Card', @@ -1986,8 +2031,7 @@ def create_cca_from_modeling_region(self, project, cca_from_mr_properties): raise e if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() response = self.stub.createCCAFromModelingRegion(request) diff --git a/src/ansys/sherlock/core/pysherlock_logging.py b/src/ansys/sherlock/core/pysherlock_logging.py index 4d801558..f1f994e4 100644 --- a/src/ansys/sherlock/core/pysherlock_logging.py +++ b/src/ansys/sherlock/core/pysherlock_logging.py @@ -1,4 +1,4 @@ -# © 2023 ANSYS, Inc. All rights reserved +# © 2023-2024 ANSYS, Inc. All rights reserved """PySherlock logger.""" from datetime import datetime @@ -38,14 +38,10 @@ def _get_file_handler(): return file_handler -def __get_logger(logger_name): - return logging.get_logger(logger_name) - - class Logger: """Provides the PySherlock logger.""" - def __init__(self, logger_name, level=logging.WARN): + def __init__(self, logger_name: str): """Initialize logger.""" self.logger = logging.getLogger(logger_name) self.logger.setLevel(LOG_LEVEL) @@ -57,7 +53,3 @@ def __init__(self, logger_name, level=logging.WARN): self.error = self.logger.error self.critical = self.logger.critical self.log = self.logger.log - - def setLevel(self, level): - """Set the logging level.""" - self.logger.setLevel(level) diff --git a/src/ansys/sherlock/core/sherlock.py b/src/ansys/sherlock/core/sherlock.py index 66d7ec02..85e2028e 100644 --- a/src/ansys/sherlock/core/sherlock.py +++ b/src/ansys/sherlock/core/sherlock.py @@ -1,6 +1,9 @@ # Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module for the gRPC connection object.""" + +import grpc + from ansys.sherlock.core.analysis import Analysis from ansys.sherlock.core.common import Common from ansys.sherlock.core.layer import Layer @@ -14,7 +17,7 @@ class Sherlock: """Sherlock gRPC connection object.""" - def __init__(self, channel, server_version): + def __init__(self, channel: grpc.Channel, server_version: int): """Initialize Sherlock gRPC connection object.""" self.common = Common(channel, server_version) self.model = Model(channel, server_version) diff --git a/src/ansys/sherlock/core/stackup.py b/src/ansys/sherlock/core/stackup.py index 067493e1..4faf6c9e 100644 --- a/src/ansys/sherlock/core/stackup.py +++ b/src/ansys/sherlock/core/stackup.py @@ -1,6 +1,9 @@ # Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module containing all stackup management capabilities.""" +from typing import Optional + +from grpc import Channel try: import SherlockStackupService_pb2 @@ -22,6 +25,7 @@ SherlockInvalidThicknessArgumentError, SherlockListConductorLayersError, SherlockListLaminateLayersError, + SherlockNoGrpcConnectionException, SherlockUpdateConductorLayerError, SherlockUpdateLaminateLayerError, ) @@ -33,7 +37,7 @@ class Stackup(GrpcStub): """Contains all stackup management capabilities.""" - def __init__(self, channel, server_version): + def __init__(self, channel: Channel, server_version: int): """Initialize a gRPC stub for Sherlock Stackup service.""" super().__init__(channel, server_version) self.stub = SherlockStackupService_pb2_grpc.SherlockStackupServiceStub(channel) @@ -60,7 +64,7 @@ def _init_laminate_thickness_units(self): self.LAMINATE_THICKNESS_UNIT_LIST = laminate_thickness_unit_response.unit def _init_laminate_material_manufacturers(self): - """Initialize list of lamininate material manufacturers. + """Initialize list of laminate material manufacturers. Available Since: 2021R1 """ @@ -113,7 +117,7 @@ def _init_fiber_materials(self): if fiber_material_response.returnCode.value == 0: self.FIBER_MATERIAL_LIST = fiber_material_response.fiberMaterial - def _check_pcb_material_validity(self, manufacturer, grade, material): + def _check_pcb_material_validity(self, manufacturer: str, grade: str, material: str): """Check PCB arguments to see if they are valid. Available Since: 2021R1 @@ -141,15 +145,16 @@ def _check_pcb_material_validity(self, manufacturer, grade, material): raise SherlockInvalidMaterialError("Laminate grade is invalid.") @staticmethod - def _check_glass_construction_validity(input): + def _check_glass_construction_validity(glass_construction: list[tuple[str, float, float, str]]): """Check input to see if it is a valid glass construction argument.""" - if not isinstance(input, list): + if not isinstance(glass_construction, list): raise SherlockInvalidGlassConstructionError( message="glass_construction argument is invalid." ) + i = 0 try: - for i, layer in enumerate(input): + for i, layer in enumerate(glass_construction): if len(layer) != 4: raise SherlockInvalidGlassConstructionError( message=f"Invalid layer {i}: Number of elements is wrong." @@ -157,7 +162,11 @@ def _check_glass_construction_validity(input): except SherlockInvalidThicknessArgumentError as e: raise SherlockInvalidGlassConstructionError(message=f"Invalid layer {i}: {str(e)}") - def _add_glass_construction_layers(self, request, layers): + @staticmethod + def _add_glass_construction_layers( + request: SherlockStackupService_pb2.UpdateLaminateRequest, + layers: list[tuple[str, float, float, str]], + ): """Add the layers to the request.""" for l in layers: layer = request.glassConstruction.add() @@ -169,57 +178,57 @@ def _add_glass_construction_layers(self, request, layers): @require_version() def gen_stackup( self, - project, - cca_name, - board_thickness, - board_thickness_unit, - pcb_material_manufacturer, - pcb_material_grade, - pcb_material, - conductor_layers_cnt, - signal_layer_thickness, - signal_layer_thickness_unit, - min_laminate_thickness, - min_laminate_thickness_unit, - maintain_symmetry, - power_layer_thickness, - power_layer_thickness_unit, - ): + project: str, + cca_name: str, + board_thickness: float, + board_thickness_unit: str, + pcb_material_manufacturer: str, + pcb_material_grade: str, + pcb_material: str, + conductor_layers_cnt: int, + signal_layer_thickness: float, + signal_layer_thickness_unit: str, + min_laminate_thickness: float, + min_laminate_thickness_unit: str, + maintain_symmetry: bool, + power_layer_thickness: float, + power_layer_thickness_unit: str, + ) -> int: """Generate a new stackup from given properties. Available Since: 2021R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - board_thickness : float + board_thickness: float Board thickness. - board_thickness_unit : str + board_thickness_unit: str Units for the board thickness. - pcb_material_manufacturer : str + pcb_material_manufacturer: str Manufacturer for the PCB material. - pcb_material_grade : str + pcb_material_grade: str Grade for the PCB material. - pcb_material : str + pcb_material: str Material for the PCB. - conductor_layers_cnt : int32 + conductor_layers_cnt: int32 Number of conductor layers. - signal_layer_thickness : float + signal_layer_thickness: float Signal layer thickness. - signal_layer_thickness_unit : str + signal_layer_thickness_unit: str Units for the signal layer thickness. - min_laminate_thickness : float + min_laminate_thickness: float Minimum thickness of laminate layers. - min_laminate_thickness_unit : str + min_laminate_thickness_unit: str Units for the minimum thickness of laminate layers. - maintain_symmetry : bool + maintain_symmetry: bool Whether to maintain symmetry. - power_layer_thickness : float + power_layer_thickness: float Power layer thickness. - power_layer_thickness_unit : str + power_layer_thickness_unit: str Units for the power layer thickness. Returns @@ -255,7 +264,7 @@ def gen_stackup( "mil", False, 1.0, - "mil", + "mil" ) """ if self.LAMINATE_THICKNESS_UNIT_LIST is None: @@ -285,8 +294,7 @@ def gen_stackup( raise SherlockGenStackupError(message=str(e)) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockStackupService_pb2.GenStackupRequest( project=project, @@ -321,41 +329,41 @@ def gen_stackup( @require_version() def update_conductor_layer( self, - project, - cca_name, - layer, - type="", - material="", - thickness=0, - thickness_unit="", - conductor_percent="", - resin_material="", - ): + project: str, + cca_name: str, + layer: str, + layer_type: str = "", + material: str = "", + thickness: float = 0, + thickness_unit: str = "", + conductor_percent: str = "", + resin_material: str = "", + ) -> int: """Update a conductor layer with given properties. Available Since: 2021R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. - cca_name : str + cca_name: str Name of the CCA. - layer : str + layer: str Layer ID associated with the conductor layer. - type : str, optional + layer_type: str, optional Layer type. The default is ``""``. For example, ``"SIGNAL"``, ``"POWER"``, or ``"SUBSTRATE"``. - material : str, optional + material: str, optional Conductor material. The default is ``""``. - thickness : float, optional + thickness: float, optional Conductor layer thickness. The default is ``0``. - thickness_unit : str, optional + thickness_unit: str, optional Units for the conductor layer thickness. The default is ``""``. - conductor_percent : str, optional + conductor_percent: str, optional Conductor percentage. The default is ``""``. - resin_material : str, optional + resin_material: str, optional Resin material. The default is ``""``. Note @@ -389,7 +397,7 @@ def update_conductor_layer( 1.0, "oz", "94.2", - "Generic FR-4 Generic FR-4", + "Generic FR-4 Generic FR-4" ) """ if self.LAMINATE_THICKNESS_UNIT_LIST is None: @@ -402,7 +410,7 @@ def update_conductor_layer( raise SherlockUpdateConductorLayerError(message="Project name is invalid.") if cca_name == "": raise SherlockUpdateConductorLayerError(message="CCA name is invalid.") - if (type != "") and type not in self.LAYER_TYPE_LIST: + if (layer_type != "") and layer_type not in self.LAYER_TYPE_LIST: raise SherlockUpdateConductorLayerError( message=( "Conductor type is invalid. " @@ -428,14 +436,13 @@ def update_conductor_layer( raise SherlockUpdateConductorLayerError(message=str(e)) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockStackupService_pb2.UpdateConductorLayerRequest( project=project, ccaName=cca_name, layer=layer, - type=type, + type=layer_type, material=material, thickness=thickness, thicknessUnit=thickness_unit, @@ -461,17 +468,17 @@ def update_laminate_layer( project, cca_name, layer, - manufacturer="", - grade="", - material="", - thickness=0, - thickness_unit="", - construction_style="", - glass_construction=[], - fiber_material="", - conductor_material="", - conductor_percent="", - ): + manufacturer: str = "", + grade: str = "", + material: str = "", + thickness: float = 0, + thickness_unit: str = "", + construction_style: str = "", + glass_construction: Optional[list[tuple[str, float, float, str]]] = None, + fiber_material: str = "", + conductor_material: str = "", + conductor_percent: str = "", + ) -> int: """Update a laminate layer with given properties. Available Since: 2021R1 @@ -501,7 +508,7 @@ def update_laminate_layer( Units for the laminate thickness. The default is ``""``. construction_style : str, optional Construction style. The default is ``""``. - glass_construction : list, optional + glass_construction : list[tuple[str, float, float, str]], optional List representing a glass construction. This list consists of objects with these properties: @@ -559,7 +566,7 @@ def update_laminate_layer( ], "E-GLASS", "COPPER", - "0.0", + "0.0" ) """ if self.LAMINATE_THICKNESS_UNIT_LIST is None: @@ -572,6 +579,8 @@ def update_laminate_layer( self._init_fiber_materials() if self.CONDUCTOR_MATERIAL_LIST is None: self._init_conductor_materials() + if glass_construction is None: + glass_construction = [] try: if project == "": @@ -610,8 +619,7 @@ def update_laminate_layer( raise SherlockUpdateLaminateLayerError(message=str(e)) if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + raise SherlockNoGrpcConnectionException() request = SherlockStackupService_pb2.UpdateLaminateRequest( project=project, @@ -643,19 +651,21 @@ def update_laminate_layer( raise e @require_version() - def list_conductor_layers(self, project): + def list_conductor_layers( + self, project: str + ) -> list[SherlockStackupService_pb2.ListConductorLayersResponse.CCAConductorLayerProp]: """List CCA conductor layers. Available Since: 2021R2 Parameters ---------- - project : str + project: str Name of the Sherlock project. Returns ------- - list + list[SherlockStackupService_pb2.ListConductorLayersResponse.CCAConductorLayerProp] The conductor layers of all CCAs in the project. Example @@ -682,13 +692,13 @@ def list_conductor_layers(self, project): if self.CONDUCTOR_MATERIAL_LIST is None: self._init_conductor_materials() - try: - if project == "": - raise SherlockListConductorLayersError(message="Project name is invalid.") + if project == "": + raise SherlockListConductorLayersError(message="Project name is invalid.") - if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + if not self._is_connection_up(): + raise SherlockNoGrpcConnectionException() + + try: request = SherlockStackupService_pb2.ListConductorLayersRequest(project=project) response = self.stub.listConductorLayers(request) @@ -702,19 +712,21 @@ def list_conductor_layers(self, project): raise e @require_version() - def list_laminate_layers(self, project): + def list_laminate_layers( + self, project: str + ) -> list[SherlockStackupService_pb2.ListLaminatesResponse.CCALaminateProp]: """List all laminate layers and their properties. Available Since: 2021R1 Parameters ---------- - project : str + project: str Name of the Sherlock project. Returns ------- - list + list[SherlockStackupService_pb2.ListLaminatesResponse.CCALaminateProp] The laminate layers of all CCAs in the project. Example @@ -747,13 +759,12 @@ def list_laminate_layers(self, project): if self.CONDUCTOR_MATERIAL_LIST is None: self._init_conductor_materials() - try: - if project == "": - raise SherlockListLaminateLayersError(message="Project name is invalid.") - if not self._is_connection_up(): - LOG.error("There is no connection to a gRPC service.") - return + if project == "": + raise SherlockListLaminateLayersError(message="Project name is invalid.") + if not self._is_connection_up(): + raise SherlockNoGrpcConnectionException() + try: request = SherlockStackupService_pb2.ListLaminatesRequest(project=project) response = self.stub.listLaminates(request) if response.returnCode.value == -1: @@ -766,16 +777,16 @@ def list_laminate_layers(self, project): raise e @require_version() - def get_layer_count(self, project, cca_name): + def get_layer_count(self, project: str, cca_name: str) -> int: """Get the number of CCA layers in a stackup. Available Since: 2021R2 Parameters ---------- - project : str, required + project: str Name of the Sherlock project. - cca_name : str, required + cca_name: str Name of the CCA. Returns @@ -801,19 +812,16 @@ def get_layer_count(self, project, cca_name): >>> cca_name="Card") >>> print(f"{conductor_layer_count}") """ - try: - if project == "": - raise SherlockGetLayerCountError(message="Project name is invalid.") - if cca_name == "": - raise SherlockGetLayerCountError(message="CCA name is invalid.") - if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + if project == "": + raise SherlockGetLayerCountError(message="Project name is invalid.") + if cca_name == "": + raise SherlockGetLayerCountError(message="CCA name is invalid.") + if not self._is_connection_up(): + raise SherlockNoGrpcConnectionException() - request = SherlockStackupService_pb2.GetLayerCountRequest( - project=project, ccaName=cca_name - ) - response = self.stub.getLayerCount(request) + request = SherlockStackupService_pb2.GetLayerCountRequest(project=project, ccaName=cca_name) + response = self.stub.getLayerCount(request) + try: if response.returnCode.value == -1: raise SherlockGetLayerCountError(response.returnCode.message) @@ -823,16 +831,16 @@ def get_layer_count(self, project, cca_name): raise e @require_version() - def get_stackup_props(self, project, cca_name): + def get_stackup_props(self, project: str, cca_name: str) -> StackupProperties: """Get the stackup properties from a CCA. Available Since: 2021R2 Parameters ---------- - project : str, required + project: str Name of the Sherlock project. - cca_name : str, required + cca_name: str Name of the CCA. Returns @@ -859,19 +867,18 @@ def get_stackup_props(self, project, cca_name): ) >>> print(f"{stackup_props}") """ - try: - if project == "": - raise SherlockGetStackupPropsError(message="Project name is invalid.") - if cca_name == "": - raise SherlockGetStackupPropsError(message="CCA name is invalid.") - if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return + if project == "": + raise SherlockGetStackupPropsError(message="Project name is invalid.") + if cca_name == "": + raise SherlockGetStackupPropsError(message="CCA name is invalid.") + if not self._is_connection_up(): + raise SherlockNoGrpcConnectionException() - request = SherlockStackupService_pb2.GetStackupPropsRequest( - project=project, ccaName=cca_name - ) - response = self.stub.getStackupProps(request) + request = SherlockStackupService_pb2.GetStackupPropsRequest( + project=project, ccaName=cca_name + ) + response = self.stub.getStackupProps(request) + try: if response.returnCode.value == -1: raise SherlockGetLayerCountError(response.returnCode.message) @@ -881,18 +888,20 @@ def get_stackup_props(self, project, cca_name): raise e @require_version() - def get_total_conductor_thickness(self, project, cca_name, thickness_unit): + def get_total_conductor_thickness( + self, project: str, cca_name: str, thickness_unit: str + ) -> float: """Return the total conductor thickness. Available Since: 2021R2 Parameters ---------- - project : str, required + project: str Sherlock project name. - cca_name : str, required + cca_name: str The CCA name. - thickness_unit : str, optional + thickness_unit: str, optional Units for laminate thickness. Returns @@ -918,21 +927,21 @@ def get_total_conductor_thickness(self, project, cca_name, thickness_unit): thickness_unit="oz") >>>print(f"{total_thickness}") """ + if project == "": + raise SherlockGetTotalConductorThicknessError(message="Invalid project name") + if cca_name == "": + raise SherlockGetTotalConductorThicknessError(message="Invalid CCA name") + if thickness_unit == "": + raise SherlockGetTotalConductorThicknessError(message="Invalid thickness unit") + if not self._is_connection_up(): + raise SherlockNoGrpcConnectionException() + + request = SherlockStackupService_pb2.GetTotalConductorThicknessRequest( + project=project, ccaName=cca_name, thicknessUnit=thickness_unit + ) + response = self.stub.getTotalConductorThickness(request) + try: - if project == "": - raise SherlockGetTotalConductorThicknessError(message="Invalid project name") - if cca_name == "": - raise SherlockGetTotalConductorThicknessError(message="Invalid CCA name") - if thickness_unit == "": - raise SherlockGetTotalConductorThicknessError(message="Invalid thickness unit") - if not self._is_connection_up(): - LOG.error("Not connected to a gRPC service.") - return - - request = SherlockStackupService_pb2.GetTotalConductorThicknessRequest( - project=project, ccaName=cca_name, thicknessUnit=thickness_unit - ) - response = self.stub.getTotalConductorThickness(request) if response.returnCode.value == -1: raise SherlockGetTotalConductorThicknessError(response.returnCode.message) diff --git a/src/ansys/sherlock/core/types/analysis_types.py b/src/ansys/sherlock/core/types/analysis_types.py index cfbec61d..568f0260 100644 --- a/src/ansys/sherlock/core/types/analysis_types.py +++ b/src/ansys/sherlock/core/types/analysis_types.py @@ -1,5 +1,4 @@ -# © 2023 ANSYS, Inc. All rights reserved. - +# © 2023-2024 ANSYS, Inc. All rights reserved. """Module containing types for the Analysis Service.""" @@ -15,15 +14,20 @@ class ElementOrder: """Constants for Element Order.""" LINEAR = analysis_service.ElementOrder.Linear + "LINEAR" QUADRATIC = analysis_service.ElementOrder.Quadratic + "QUADRATIC" SOLID_SHELL = analysis_service.ElementOrder.SolidShell + "SOLID_SHELL" class ModelSource: """Constants for Model Source.""" GENERATED = analysis_service.ModelSource.GENERATED + "GENERATED" STRAIN_MAP = analysis_service.ModelSource.STRAIN_MAP + "STRAIN_MAP" class RunAnalysisRequestAnalysisType: @@ -31,25 +35,45 @@ class RunAnalysisRequestAnalysisType: __analysis_type = analysis_service.RunAnalysisRequest.Analysis.AnalysisType NATURAL_FREQ = __analysis_type.NaturalFreq + "NATURAL_FREQ" HARMONIC_VIBE = __analysis_type.HarmonicVibe + "HARMONIC_VIBE" ICT = __analysis_type.ICTAnalysis + "ICT" MECHANICAL_SHOCK = __analysis_type.MechanicalShock + "MECHANICAL_SHOCK" RANDOM_VIBE = __analysis_type.RandomVibe + "RANDOM_VIBE" COMPONENT_FAILURE_MODE = __analysis_type.ComponentFailureMode + "COMPONENT_FAILURE_MODE" DFMEA = __analysis_type.DFMEAModule + "DFMEA" PTH_FATIQUE = __analysis_type.PTHFatigue + "PTH_FATIQUE" PART_VALIDATION = __analysis_type.PartValidation + "PART_VALIDATION" SEMICINDUCTOR_WEAROUT = __analysis_type.SemiconductorWearout + "SEMICINDUCTOR_WEAROUT" SOLDER_JOINT_FATIGUE = __analysis_type.SolderJointFatigue + "SOLDER_JOINT_FATIGUE" THERMAL_DERATING = __analysis_type.ThermalDerating + "THERMAL_DERATING" THERMAL_MECH = __analysis_type.ThermalMech + "THERMAL_MECH" class RunStrainMapAnalysisRequestAnalysisType: """Constants for type of analysis in the Run Strain Map Analysis request.""" __analysis_type = analysis_service.RunStrainMapAnalysisRequest.StrainMapAnalysis.AnalysisType + HARMONIC_VIBE = __analysis_type.HarmonicVibe + "HARMONIC_VIBE" + + MECHANICAL_SHOCK = __analysis_type.MechanicalShock + "MECHANICAL_SHOCK" + RANDOM_VIBE = __analysis_type.RandomVibe + "RANDOM_VIBE" class UpdatePcbModelingPropsRequestAnalysisType: @@ -57,11 +81,17 @@ class UpdatePcbModelingPropsRequestAnalysisType: __analysis_type = analysis_service.UpdatePcbModelingPropsRequest.Analysis.AnalysisType HARMONIC_VIBE = __analysis_type.HarmonicVibe + "HARMONIC_VIBE" ICT = __analysis_type.ICTAnalysis + "ICT" MECHANICAL_SHOCK = __analysis_type.MechanicalShock + "MECHANICAL_SHOCK" NATURAL_FREQUENCY = __analysis_type.NaturalFreq + "NATURAL_FREQUENCY" RANDOM_VIBE = __analysis_type.RandomVibe + "RANDOM_VIBE" THERMAL_MECH = __analysis_type.ThermalMech + "THERMAL_MECH" class UpdatePcbModelingPropsRequestPcbMaterialModel: @@ -69,9 +99,13 @@ class UpdatePcbModelingPropsRequestPcbMaterialModel: __material_model = analysis_service.UpdatePcbModelingPropsRequest.Analysis.PcbMaterialModel UNIFORM = __material_model.Uniform + "UNIFORM" LAYERED = __material_model.Layered + "LAYERED" UNIFORM_ELEMENTS = __material_model.UniformElements + "UNIFORM_ELEMENTS" LAYERED_ELEMENTS = __material_model.LayeredElements + "LAYERED_ELEMENTS" class UpdatePcbModelingPropsRequestPcbModelType: @@ -79,3 +113,4 @@ class UpdatePcbModelingPropsRequestPcbModelType: __model_type = analysis_service.UpdatePcbModelingPropsRequest.Analysis.PcbModelType BONDED = __model_type.Bonded + "BONDED" diff --git a/src/ansys/sherlock/core/types/common_types.py b/src/ansys/sherlock/core/types/common_types.py index 2bea1b6b..2a9874ea 100644 --- a/src/ansys/sherlock/core/types/common_types.py +++ b/src/ansys/sherlock/core/types/common_types.py @@ -18,83 +18,86 @@ def basic_str_validator(value: str, field_name: str): class ListUnitsRequestUnitType: """Constants for Unit Type in the List Units request.""" - ACCEL_DENSITY = SherlockCommonService_pb2.ListUnitsRequest.UnitType.ACCEL_DENSITY + __unit_type = SherlockCommonService_pb2.ListUnitsRequest.UnitType + ACCEL_DENSITY = __unit_type.ACCEL_DENSITY "ACCEL_DENSITY" - ACCELERATION = SherlockCommonService_pb2.ListUnitsRequest.UnitType.ACCELERATION + ACCELERATION = __unit_type.ACCELERATION "ACCELERATION" - AREA = SherlockCommonService_pb2.ListUnitsRequest.UnitType.AREA + AREA = __unit_type.AREA "AREA" - BANDWIDTH = SherlockCommonService_pb2.ListUnitsRequest.UnitType.BANDWIDTH + BANDWIDTH = __unit_type.BANDWIDTH "BANDWIDTH" - CAPACITANCE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.CAPACITANCE + CAPACITANCE = __unit_type.CAPACITANCE "CAPACITANCE" - CTE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.CTE + CTE = __unit_type.CTE "CTE" - CURRENT = SherlockCommonService_pb2.ListUnitsRequest.UnitType.CURRENT + CURRENT = __unit_type.CURRENT "CURRENT" - DENSITY = SherlockCommonService_pb2.ListUnitsRequest.UnitType.DENSITY + DENSITY = __unit_type.DENSITY "DENSITY" - DISP_DENSITY = SherlockCommonService_pb2.ListUnitsRequest.UnitType.DISP_DENSITY + DISP_DENSITY = __unit_type.DISP_DENSITY "DISP_DENSITY" - FORCE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.FORCE + FORCE = __unit_type.FORCE "FORCE" - FREQUENCY = SherlockCommonService_pb2.ListUnitsRequest.UnitType.FREQUENCY + FREQUENCY = __unit_type.FREQUENCY "FREQUENCY" - INDUCTANCE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.INDUCTANCE + INDUCTANCE = __unit_type.INDUCTANCE "INDUCTANCE" - LENGTH = SherlockCommonService_pb2.ListUnitsRequest.UnitType.LENGTH + LENGTH = __unit_type.LENGTH "LENGTH" - POWER = SherlockCommonService_pb2.ListUnitsRequest.UnitType.POWER + POWER = __unit_type.POWER "POWER" - RESISTANCE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.RESISTANCE + RESISTANCE = __unit_type.RESISTANCE "RESISTANCE" - SIZE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.SIZE + SIZE = __unit_type.SIZE "SIZE" - SPECIFIC_HEAT = SherlockCommonService_pb2.ListUnitsRequest.UnitType.SPECIFIC_HEAT + SPECIFIC_HEAT = __unit_type.SPECIFIC_HEAT "SPECIFIC_HEAT" - STRAIN = SherlockCommonService_pb2.ListUnitsRequest.UnitType.STRAIN + STRAIN = __unit_type.STRAIN "STRAIN" - STRESS = SherlockCommonService_pb2.ListUnitsRequest.UnitType.STRESS + STRESS = __unit_type.STRESS "STRESS" - TEMPERATURE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.TEMPERATURE + TEMPERATURE = __unit_type.TEMPERATURE "TEMPERATURE" - THERMAL_CONDUCTIVITY = SherlockCommonService_pb2.ListUnitsRequest.UnitType.THERMAL_CONDUCTIVITY + THERMAL_CONDUCTIVITY = __unit_type.THERMAL_CONDUCTIVITY "THERMAL_CONDUCTIVITY" - THERMAL_RESISTANCE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.THERMAL_RESISTANCE + THERMAL_RESISTANCE = __unit_type.THERMAL_RESISTANCE "THERMAL_RESISTANCE" - TIME = SherlockCommonService_pb2.ListUnitsRequest.UnitType.TIME + TIME = __unit_type.TIME "TIME" - VELOCITY = SherlockCommonService_pb2.ListUnitsRequest.UnitType.VELOCITY + VELOCITY = __unit_type.VELOCITY "VELOCITY" - VELOCITY_DENSITY = SherlockCommonService_pb2.ListUnitsRequest.UnitType.VELOCITY_DENSITY + VELOCITY_DENSITY = __unit_type.VELOCITY_DENSITY "VELOCITY_DENSITY" - VOLTAGE = SherlockCommonService_pb2.ListUnitsRequest.UnitType.VOLTAGE + VOLTAGE = __unit_type.VOLTAGE "VOLTAGE" - VOLUME = SherlockCommonService_pb2.ListUnitsRequest.UnitType.VOLUME + VOLUME = __unit_type.VOLUME "VOLUME" - WEIGHT = SherlockCommonService_pb2.ListUnitsRequest.UnitType.WEIGHT + WEIGHT = __unit_type.WEIGHT "WEIGHT" class TableDelimiter: """Types of delimiters that can be used for exporting tables.""" - COMMA = SherlockCommonService_pb2.TableDelimiter.COMMA - """COMMA""" - SPACE = SherlockCommonService_pb2.TableDelimiter.SPACE - """SPACE""" - TAB = SherlockCommonService_pb2.TableDelimiter.TAB - """TAB""" - SEMICOLON = SherlockCommonService_pb2.TableDelimiter.SEMICOLON - """SEMICOLON""" + __table_delimiter = SherlockCommonService_pb2.TableDelimiter + + COMMA = __table_delimiter.COMMA + "COMMA" + SPACE = __table_delimiter.SPACE + "SPACE" + TAB = __table_delimiter.TAB + "TAB" + SEMICOLON = __table_delimiter.SEMICOLON + "SEMICOLON" class Measurement: """Contains the properties of the measurement.""" - def __init__(self, value, unit): + def __init__(self, value: float, unit: str): """Initialize the measurement properties.""" self.value = value - """value : float""" + """float: measurement value""" self.unit = unit - """unit : string""" + """str: measurement units""" diff --git a/src/ansys/sherlock/core/types/layer_types.py b/src/ansys/sherlock/core/types/layer_types.py index 1fe2b41f..5ed2bd2d 100644 --- a/src/ansys/sherlock/core/types/layer_types.py +++ b/src/ansys/sherlock/core/types/layer_types.py @@ -109,7 +109,8 @@ def _convert_to_grpc(self) -> SherlockLayerService_pb2.CircularShape: class PCBShape(BaseModel): """Contains the properties for a PCB shape.""" - def _convert_to_grpc(self) -> SherlockLayerService_pb2.PCBShape: + @staticmethod + def _convert_to_grpc() -> SherlockLayerService_pb2.PCBShape: return SherlockLayerService_pb2.PCBShape() diff --git a/src/ansys/sherlock/core/types/parts_types.py b/src/ansys/sherlock/core/types/parts_types.py index 46b8f5e2..4f476037 100644 --- a/src/ansys/sherlock/core/types/parts_types.py +++ b/src/ansys/sherlock/core/types/parts_types.py @@ -1,4 +1,4 @@ -# © 2023 ANSYS, Inc. All rights reserved. +# Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module containing types for the Parts Service.""" @@ -11,7 +11,7 @@ from ansys.api.sherlock.v0 import SherlockCommonService_pb2, SherlockPartsService_pb2 -def deprecation(cls): +def deprecation(cls: object): """Raise a DeprecationWarning when a deprecated class is used.""" # if str(cls).find("PartsListSearchMatchingMode") != -1: message = f"{cls} is deprecated. Use a string with the value of the constant name \ @@ -24,42 +24,44 @@ def deprecation(cls): class PartsListSearchMatchingMode: """DEPRECATED. Constants for Matching Mode in Update Parts List & Update Parts from AVL.""" - BOTH = SherlockCommonService_pb2.MatchingMode.Both + matching_mode = SherlockCommonService_pb2.MatchingMode + BOTH = matching_mode.Both """Both""" - PART = SherlockCommonService_pb2.MatchingMode.Part + PART = matching_mode.Part """Part""" class PartsListSearchDuplicationMode: """Constants for Duplication Mode in Update Parts List and Update Parts from AVL request.""" - FIRST = SherlockPartsService_pb2.DuplicationMode.First + duplication_mode = SherlockPartsService_pb2.DuplicationMode + FIRST = duplication_mode.First """First""" - ERROR = SherlockPartsService_pb2.DuplicationMode.Error + ERROR = duplication_mode.Error """Error""" - IGNORE = SherlockPartsService_pb2.DuplicationMode.Ignore + IGNORE = duplication_mode.Ignore """Ignore""" class AVLPartNum: """Constants for AVLPartNum in the Update Parts List from AVL request.""" - ASSIGN_INTERNAL_PART_NUM = SherlockPartsService_pb2.AVLPartNum.AssignInternalPartNum + avl_part_num = SherlockPartsService_pb2.AVLPartNum + ASSIGN_INTERNAL_PART_NUM = avl_part_num.AssignInternalPartNum """AssignInternalPartNum""" - ASSIGN_VENDOR_AND_PART_NUM = SherlockPartsService_pb2.AVLPartNum.AssignVendorAndPartNum + ASSIGN_VENDOR_AND_PART_NUM = avl_part_num.AssignVendorAndPartNum """AssignVendorAndPartNum""" - DO_NOT_CHANGE_VENDOR_OR_PART_NUM = ( - SherlockPartsService_pb2.AVLPartNum.DoNotChangeVendorOrPartNum - ) + DO_NOT_CHANGE_VENDOR_OR_PART_NUM = avl_part_num.DoNotChangeVendorOrPartNum """DoNotChangeVendorOrPartNum""" class AVLDescription: """Constants for AVLDescription in the Update Parts List from AVL request.""" - ASSIGN_APPROVED_DESCRIPTION = SherlockPartsService_pb2.AVLDescription.AssignApprovedDescription + avl_description = SherlockPartsService_pb2.AVLDescription + ASSIGN_APPROVED_DESCRIPTION = avl_description.AssignApprovedDescription """AssignApprovedDescription""" - DO_NOT_CHANGE_DESCRIPTION = SherlockPartsService_pb2.AVLDescription.DoNotChangeDescription + DO_NOT_CHANGE_DESCRIPTION = avl_description.DoNotChangeDescription """DoNotChangeDescription""" diff --git a/src/ansys/sherlock/core/types/project_types.py b/src/ansys/sherlock/core/types/project_types.py index b410be6d..86d80e66 100644 --- a/src/ansys/sherlock/core/types/project_types.py +++ b/src/ansys/sherlock/core/types/project_types.py @@ -1,4 +1,4 @@ -# © 2024 ANSYS, Inc. All rights reserved. +# Copyright (C) 2024 ANSYS, Inc. and/or its affiliates. """Module containing types for the Project Service.""" @@ -8,39 +8,41 @@ from ansys.api.sherlock.v0 import SherlockProjectService_pb2 project_service = SherlockProjectService_pb2 +thermal_map_file = project_service.ThermalMapFile +add_strain_map_request = project_service.AddStrainMapRequest class BoardBounds: """Contains the properties of the board bounds.""" - def __init__(self, bounds): + def __init__(self, bounds: list[tuple[float, float]]): """Initialize the board bounds.""" self.bounds = bounds - """bounds (two tuples of the form (x, y) : list[tuple[float, float]]""" + """list[tuple[float, float]]: bounds (two tuples of the form (x, y)""" class CsvExcelFile: - """Contains the properties for a thermal map csv or excel file.""" + """Contains the properties for a thermal map, CSV, or Excel file.""" def __init__( self, - header_row_count, - numeric_format, - reference_id_column, - temperature_column, - temperature_units, + header_row_count: int, + numeric_format: str, + reference_id_column: str, + temperature_column: str, + temperature_units: str, ): - """Initialize the thermal map csv or excel file properties.""" + """Initialize the thermal map, CSV or Excel file properties.""" self.header_row_count = header_row_count - """header_row_count: int""" + """int: header_row_count""" self.numeric_format = numeric_format - """numeric_format: string""" + """str: numeric_format""" self.reference_id_column = reference_id_column - """reference_id_column: string""" + """str: reference_id_column""" self.temperature_column = temperature_column - """temperature_column: string""" + """str: temperature_column""" self.temperature_units = temperature_units - """temperature_units: string""" + """str: temperature_units""" class IcepakFile: @@ -50,16 +52,16 @@ class IcepakFile: class ImageBounds: """Contains the properties of the image bounds.""" - def __init__(self, image_x, image_y, height, width): + def __init__(self, image_x: float, image_y: float, height: float, width: float): """Initialize the image bounds properties.""" self.image_x = image_x - """x coordinate of the upper left corner : float""" + """float: x coordinate of the upper left corner""" self.image_y = image_y - """y coordinate of the upper left corner : float""" + """float: y coordinate of the upper left corner""" self.height = height - """height of the image : float""" + """float: height of the image""" self.width = width - """width of the image : float""" + """float: width of the image""" class ImageFile: @@ -67,56 +69,56 @@ class ImageFile: def __init__( self, - board_bounds, - coordinate_units, - image_bounds, - legend_bounds, - legend_orientation, - max_temperature, - max_temperature_units, - min_temperature, - min_temperature_units, + board_bounds: BoardBounds, + coordinate_units: str, + image_bounds: ImageBounds, + legend_bounds: "LegendBounds", + legend_orientation: "LegendOrientation", + max_temperature: float, + max_temperature_units: str, + min_temperature: float, + min_temperature_units: str, ): """Initialize the thermal image file properties.""" self.board_bounds = board_bounds - """board_bounds : BoardBounds""" + """BoardBounds: board_bounds""" self.coordinate_units = coordinate_units - """coordinate_units : string""" + """str: coordinate_units""" self.image_bounds = image_bounds - """image_bounds : ImageBounds""" + """ImageBounds: image_bounds""" self.legend_bounds = legend_bounds - """legend_bounds : LegendBounds""" + """LegendBounds: legend_bounds""" self.legend_orientation = legend_orientation - """legend_orientation : LegendOrientation""" + """LegendOrientation: legend_orientation""" self.max_temperature = max_temperature - """max_temperature : float""" + """float: max_temperature""" self.max_temperature_units = max_temperature_units - """max_temperature_units : string""" + """str: max_temperature_units""" self.min_temperature = min_temperature - """min_temperature : float""" + """float: min_temperature""" self.min_temperature_units = min_temperature_units - """min_temperature_units : string""" + """str: min_temperature_units""" class LegendBounds: """Contains the properties of the legend bounds.""" - def __init__(self, legend_x, legend_y, height, width): + def __init__(self, legend_x: float, legend_y: float, height: float, width: float): """Initialize the legend bounds properties.""" self.legend_x = legend_x - """x coordinate of the upper left corner : float""" + """float: x coordinate of the upper left corner""" self.legend_y = legend_y - """y coordinate of the upper left corner : float""" + """float: y coordinate of the upper left corner""" self.height = height - """height of the legend : float""" + """float: height of the legend""" self.width = width - """width of the legend : float""" + """float: width of the legend""" class LegendOrientation: """Constants for legend orientation in the update thermal maps request.""" - __legend_orientation = project_service.ThermalMapFile.ImageFile.LegendOrientation + __legend_orientation = thermal_map_file.ImageFile.LegendOrientation HORIZONTAL = __legend_orientation.Horizontal "Horizontal" VERTICAL = __legend_orientation.Vertical @@ -126,47 +128,42 @@ class LegendOrientation: class ThermalBoardSide: """Constants for thermal board side in the update thermal maps request.""" - __thermal_board_side = project_service.ThermalMapFile.ThermalBoardSide - BOTTOM = __thermal_board_side.Bottom + BOTTOM = thermal_map_file.ThermalBoardSide.Bottom "Bottom" - BOTH = __thermal_board_side.Both + BOTH = thermal_map_file.ThermalBoardSide.Both "Both" - TOP = __thermal_board_side.Top + TOP = thermal_map_file.ThermalBoardSide.Top "Top" class ThermalMapsFileType: """Constants for File Type in the Update Thermal Maps request.""" - __file_type = project_service.ThermalMapFile.FileType - CSV = __file_type.CSV + CSV = thermal_map_file.FileType.CSV "CSV" - EXCEL = __file_type.Excel + EXCEL = thermal_map_file.FileType.Excel "Excel" - IMAGE = __file_type.Image + IMAGE = thermal_map_file.FileType.Image "Image" - TMAP = __file_type.TMAP + TMAP = thermal_map_file.FileType.TMAP "Icepak Thermal Map (.TMAP)" class StrainMapsFileType: """Constants for File Type in the Add Strain Maps request.""" - __file_type = project_service.AddStrainMapRequest.StrainMapFile.FileType - CSV = __file_type.CSV + CSV = add_strain_map_request.StrainMapFile.FileType.CSV "CSV" - EXCEL = __file_type.Excel + EXCEL = add_strain_map_request.StrainMapFile.FileType.Excel "Excel" - IMAGE = __file_type.Image + IMAGE = add_strain_map_request.StrainMapFile.FileType.Image "Image" class StrainMapLegendOrientation: """Constants for legend orientation in the add strain maps request.""" - __legend_orientation = ( - project_service.AddStrainMapRequest.StrainMapFile.StrainMapImageFile.LegendOrientation - ) + __legend_orientation = add_strain_map_request.StrainMapFile.StrainMapImageFile.LegendOrientation HORIZONTAL = __legend_orientation.Horizontal "Horizontal" VERTICAL = __legend_orientation.Vertical diff --git a/src/ansys/sherlock/core/types/stackup_types.py b/src/ansys/sherlock/core/types/stackup_types.py index 0cac19f6..fa8315d4 100644 --- a/src/ansys/sherlock/core/types/stackup_types.py +++ b/src/ansys/sherlock/core/types/stackup_types.py @@ -1,12 +1,16 @@ -# © 2023 ANSYS, Inc. All rights reserved. +# Copyright (C) 2023-2024 ANSYS, Inc. and/or its affiliates. """Module containing types for the Stackup Service.""" +try: + import SherlockStackupService_pb2 +except ModuleNotFoundError: + from ansys.api.sherlock.v0 import SherlockStackupService_pb2 class StackupProperties: """Stackup property values.""" - def __init__(self, properties): + def __init__(self, properties: SherlockStackupService_pb2.GetStackupPropsResponse): """Initialize members from the properties.""" self.board_dimension = properties.boardDimension self.board_thickness = properties.boardThickness diff --git a/src/ansys/sherlock/core/utils/version_check.py b/src/ansys/sherlock/core/utils/version_check.py index dcefc209..09fe9bb5 100644 --- a/src/ansys/sherlock/core/utils/version_check.py +++ b/src/ansys/sherlock/core/utils/version_check.py @@ -1,4 +1,4 @@ -# © 2024 ANSYS, Inc. All rights reserved. +# Copyright (C) 2024 ANSYS, Inc. and/or its affiliates. """Module for version check done on api methods.""" import functools @@ -21,12 +21,12 @@ def require_version(min_version: int = _EARLIEST_SUPPORTED_VERSION, max_version: int = None): """Check version of server against expected version.""" - def decorate(func): + def decorate(func) -> callable: """Return wrapped function.""" @functools.wraps(func) # Use functools to keep the doc string associated with the wrapped function, for Sphinx. - def wrapper(self, *args, **kwargs): + def wrapper(self, *args, **kwargs) -> callable: """Wrap outer function.""" if not hasattr(self, "_server_version") or self._server_version is None: raise SherlockVersionError( diff --git a/tests/test_analysis.py b/tests/test_analysis.py index 32588988..57ea06eb 100644 --- a/tests/test_analysis.py +++ b/tests/test_analysis.py @@ -29,6 +29,7 @@ ElementOrder, ModelSource, RunAnalysisRequestAnalysisType, + RunStrainMapAnalysisRequestAnalysisType, UpdatePcbModelingPropsRequestAnalysisType, UpdatePcbModelingPropsRequestPcbMaterialModel, UpdatePcbModelingPropsRequestPcbModelType, @@ -63,7 +64,7 @@ def test_all(): helper_test_get_parts_list_validation_analysis_props(analysis) -def helper_test_run_analysis(analysis): +def helper_test_run_analysis(analysis: Analysis): """Test run_analysis API.""" natural_frequency_analysis_type = RunAnalysisRequestAnalysisType.NATURAL_FREQ @@ -119,12 +120,8 @@ def helper_test_run_analysis(analysis): assert str(e) == "Run analysis error: One or more analyses are missing." -def helper_test_run_strain_map_analysis(analysis): +def helper_test_run_strain_map_analysis(analysis: Analysis): """Test run_strain_map_analysis API.""" - analysis_type_enum = ( - SherlockAnalysisService_pb2.RunStrainMapAnalysisRequest.StrainMapAnalysis.AnalysisType - ) - random_vibe_analysis_type = analysis_type_enum.RandomVibe if analysis._is_connection_up(): try: analysis.run_strain_map_analysis( @@ -132,7 +129,7 @@ def helper_test_run_strain_map_analysis(analysis): "Invalid CCA", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -157,7 +154,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -182,7 +179,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - analysis_type_enum.HarmonicVibe, + RunStrainMapAnalysisRequestAnalysisType.HARMONIC_VIBE, [ ["Phase 1", "Harmonic Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Harmonic Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -207,7 +204,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -226,7 +223,7 @@ def helper_test_run_strain_map_analysis(analysis): "", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -315,7 +312,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, event_strain_maps, ] ], @@ -334,7 +331,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, event_strain_maps, ] ], @@ -352,7 +349,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM"], @@ -374,7 +371,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -396,7 +393,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -418,7 +415,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -426,7 +423,7 @@ def helper_test_run_strain_map_analysis(analysis): ], ], [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -449,7 +446,7 @@ def helper_test_run_strain_map_analysis(analysis): "Main Board", [ [ - random_vibe_analysis_type, + RunStrainMapAnalysisRequestAnalysisType.RANDOM_VIBE, [ ["Phase 1", "Random Vibe", "TOP", "MainBoardStrain - Top"], ["Phase 1", "Random Vibe", "BOTTOM", "MainBoardStrain - Bottom"], @@ -466,7 +463,7 @@ def helper_test_run_strain_map_analysis(analysis): ) -def helper_test_get_harmonic_vibe_input_fields(analysis): +def helper_test_get_harmonic_vibe_input_fields(analysis: Analysis): if analysis._is_connection_up(): fields = analysis.get_harmonic_vibe_input_fields() assert "harmonic_vibe_count" in fields @@ -483,7 +480,7 @@ def helper_test_get_harmonic_vibe_input_fields(analysis): assert "require_material_assignment_enabled" in fields -def helper_test_get_ict_analysis_input_fields(analysis): +def helper_test_get_ict_analysis_input_fields(analysis: Analysis): if analysis._is_connection_up(): fields = analysis.get_ict_analysis_input_fields() assert "ict_application_time" in fields @@ -493,7 +490,7 @@ def helper_test_get_ict_analysis_input_fields(analysis): assert "model_source" not in fields -def helper_test_get_mechanical_shock_input_fields(analysis): +def helper_test_get_mechanical_shock_input_fields(analysis: Analysis): if analysis._is_connection_up(): fields = analysis.get_mechanical_shock_input_fields() assert "shock_result_count" in fields @@ -520,7 +517,7 @@ def helper_test_get_mechanical_shock_input_fields(analysis): assert "natural_freq_max_units" in fields -def helper_test_get_solder_fatigue_input_fields(analysis): +def helper_test_get_solder_fatigue_input_fields(analysis: Analysis): if analysis._is_connection_up(): fields = analysis.get_solder_fatigue_input_fields() assert "solder_material" in fields @@ -530,7 +527,7 @@ def helper_test_get_solder_fatigue_input_fields(analysis): assert "part_validation_enabled" in fields -def helper_test_get_random_vibe_input_fields(analysis): +def helper_test_get_random_vibe_input_fields(analysis: Analysis): if analysis._is_connection_up(): fields = analysis.get_random_vibe_input_fields() assert "part_validation_enabled" in fields @@ -552,7 +549,7 @@ def helper_test_get_random_vibe_input_fields(analysis): assert "strain_map_natural_freqs" in fields -def helper_test_translate_field_names(analysis): +def helper_test_translate_field_names(analysis: Analysis): """Test translating the analysis field names.""" results = analysis._translate_field_names( @@ -614,7 +611,7 @@ def helper_test_translate_field_names(analysis): assert results == expected -def helper_test_update_harmonic_vibe_props(analysis): +def helper_test_update_harmonic_vibe_props(analysis: Analysis): try: analysis.update_harmonic_vibe_props( "", @@ -820,7 +817,7 @@ def helper_test_update_harmonic_vibe_props(analysis): pytest.fail(str(e)) -def helper_test_set_update_harmonic_vibe_props_request_properties(analysis): +def helper_test_set_update_harmonic_vibe_props_request_properties(analysis: Analysis): properties = [ { "cca_name": "Main Board", @@ -841,31 +838,31 @@ def helper_test_set_update_harmonic_vibe_props_request_properties(analysis): "strain_map_natural_freq": 222.45, }, ] - mockRequest = Mock() - mockHvProperties = Mock() - mockRequest.harmonicVibeProperties.add.return_value = mockHvProperties - - analysis._set_update_harmonic_vibe_props_request_properties(mockRequest, properties) - - assert mockHvProperties.ccaName == "Main Board" - assert mockHvProperties.modelSource == ModelSource.STRAIN_MAP - assert mockHvProperties.harmonicVibeCount == 4 - assert mockHvProperties.harmonicVibeDamping == "0.015, 0.025" - assert mockHvProperties.partValidationEnabled == True - assert mockHvProperties.requireMaterialAssignmentEnabled == True - assert mockHvProperties.analysisTemp == 30 - assert mockHvProperties.analysisTempUnits == "F" - assert mockHvProperties.forceModelRebuild == "FORCE" - assert mockHvProperties.filterByEventFrequency == True - assert mockHvProperties.naturalFreqMin == 50 - assert mockHvProperties.naturalFreqMinUnits == "Hz" - assert mockHvProperties.naturalFreqMax == 1000 - assert mockHvProperties.naturalFreqMaxUnits == "Hz" - assert mockHvProperties.reuseModalAnalysis == True - assert mockHvProperties.strainMapNaturalFreq == 222.45 - - -def helper_test_update_ict_analysis_props(analysis): + mock_request = Mock() + mock_hv_properties = Mock() + mock_request.harmonicVibeProperties.add.return_value = mock_hv_properties + + analysis._set_update_harmonic_vibe_props_request_properties(mock_request, properties) + + assert mock_hv_properties.ccaName == "Main Board" + assert mock_hv_properties.modelSource == ModelSource.STRAIN_MAP + assert mock_hv_properties.harmonicVibeCount == 4 + assert mock_hv_properties.harmonicVibeDamping == "0.015, 0.025" + assert mock_hv_properties.partValidationEnabled == True + assert mock_hv_properties.requireMaterialAssignmentEnabled == True + assert mock_hv_properties.analysisTemp == 30 + assert mock_hv_properties.analysisTempUnits == "F" + assert mock_hv_properties.forceModelRebuild == "FORCE" + assert mock_hv_properties.filterByEventFrequency == True + assert mock_hv_properties.naturalFreqMin == 50 + assert mock_hv_properties.naturalFreqMinUnits == "Hz" + assert mock_hv_properties.naturalFreqMax == 1000 + assert mock_hv_properties.naturalFreqMaxUnits == "Hz" + assert mock_hv_properties.reuseModalAnalysis == True + assert mock_hv_properties.strainMapNaturalFreq == 222.45 + + +def helper_test_update_ict_analysis_props(analysis: Analysis): try: analysis.update_ict_analysis_props( "", @@ -994,7 +991,7 @@ def helper_test_update_ict_analysis_props(analysis): pytest.fail(str(e)) -def helper_test_update_mechanical_shock_props(analysis): +def helper_test_update_mechanical_shock_props(analysis: Analysis): try: analysis.update_mechanical_shock_props( "", @@ -1158,7 +1155,7 @@ def helper_test_update_mechanical_shock_props(analysis): pytest.fail(str(e)) -def helper_test_update_solder_fatigue_props(analysis): +def helper_test_update_solder_fatigue_props(analysis: Analysis): try: analysis.update_solder_fatigue_props( "", @@ -1285,7 +1282,7 @@ def helper_test_update_solder_fatigue_props(analysis): pytest.fail(str(e)) -def helper_test_update_random_vibe_props(analysis): +def helper_test_update_random_vibe_props(analysis: Analysis): try: analysis.update_random_vibe_props( "", "Card", random_vibe_damping="0.01, 0.05", analysis_temp=20, analysis_temp_units="C" @@ -1353,7 +1350,7 @@ def helper_test_update_random_vibe_props(analysis): pytest.fail(e.message) -def helper_test_get_natural_frequency_input_fields(analysis): +def helper_test_get_natural_frequency_input_fields(analysis: Analysis): if analysis._is_connection_up(): fields = analysis.get_natural_frequency_input_fields() assert "natural_freq_count" in fields @@ -1365,7 +1362,7 @@ def helper_test_get_natural_frequency_input_fields(analysis): assert "require_material_assignment_enabled" in fields -def helper_test_update_natural_frequency_props(analysis): +def helper_test_update_natural_frequency_props(analysis: Analysis): try: analysis.update_natural_frequency_props( "", @@ -1437,21 +1434,21 @@ def helper_test_update_natural_frequency_props(analysis): pytest.fail(e.message) -def helper_test_update_pcb_modeling_props(analysis): +def helper_test_update_pcb_modeling_props(analysis: Analysis): try: analysis.update_pcb_modeling_props( "", ["Main Board"], [ ( - "NaturalFreq", - "Bonded", + UpdatePcbModelingPropsRequestAnalysisType.NATURAL_FREQUENCY, + UpdatePcbModelingPropsRequestPcbModelType.BONDED, True, - "Uniform", - "SolidShell", - 6, + UpdatePcbModelingPropsRequestPcbMaterialModel.UNIFORM, + ElementOrder.SOLID_SHELL, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1472,9 +1469,9 @@ def helper_test_update_pcb_modeling_props(analysis): True, "Uniform", "SolidShell", - 6, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1506,9 +1503,9 @@ def helper_test_update_pcb_modeling_props(analysis): True, UpdatePcbModelingPropsRequestPcbMaterialModel.LAYERED, ElementOrder.SOLID_SHELL, - 6, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1530,9 +1527,9 @@ def helper_test_update_pcb_modeling_props(analysis): True, UpdatePcbModelingPropsRequestPcbMaterialModel.UNIFORM, ElementOrder.SOLID_SHELL, - 6, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1553,9 +1550,9 @@ def helper_test_update_pcb_modeling_props(analysis): True, UpdatePcbModelingPropsRequestPcbMaterialModel.UNIFORM, ElementOrder.SOLID_SHELL, - 6, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1576,9 +1573,9 @@ def helper_test_update_pcb_modeling_props(analysis): True, UpdatePcbModelingPropsRequestPcbMaterialModel.LAYERED, ElementOrder.SOLID_SHELL, - 6, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1600,9 +1597,9 @@ def helper_test_update_pcb_modeling_props(analysis): UpdatePcbModelingPropsRequestPcbMaterialModel.UNIFORM_ELEMENTS, 94, ElementOrder.SOLID_SHELL, - 6, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1624,9 +1621,9 @@ def helper_test_update_pcb_modeling_props(analysis): UpdatePcbModelingPropsRequestPcbMaterialModel.LAYERED_ELEMENTS, 94, ElementOrder.SOLID_SHELL, - 6, + 6.5, "mm", - 3, + 3.2, "mm", True, ) @@ -1637,7 +1634,7 @@ def helper_test_update_pcb_modeling_props(analysis): assert pytest.fail(e.message) -def helper_test_update_part_modeling_props(analysis): +def helper_test_update_part_modeling_props(analysis: Analysis): try: analysis.update_part_modeling_props( "", @@ -1781,7 +1778,7 @@ def helper_test_update_part_modeling_props(analysis): pytest.fail(str(e)) -def helper_test_update_parts_list_validation_props(analysis): +def helper_test_update_parts_list_validation_props(analysis: Analysis): try: analysis.update_part_list_validation_analysis_props("Tutorial Project", "Main Board") pytest.fail("No exception raised when using an invalid parameter") @@ -1906,7 +1903,7 @@ def helper_test_update_parts_list_validation_props(analysis): pytest.fail(str(e)) -def helper_test_get_parts_list_validation_analysis_props(analysis): +def helper_test_get_parts_list_validation_analysis_props(analysis: Analysis): try: analysis.get_parts_list_validation_analysis_props("", "Main Board") pytest.fail("No exception raised when using an invalid parameter") diff --git a/tests/test_common.py b/tests/test_common.py index cf444111..9c25bc0c 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -1,4 +1,4 @@ -# © 2023 ANSYS, Inc. All rights reserved +# © 2023-2024 ANSYS, Inc. All rights reserved import grpc import pytest @@ -18,7 +18,7 @@ def test_all(): helper_test_get_solders(common) -def helper_test_list_units(common): +def helper_test_list_units(common: Common): """Test list_units API""" if common._is_connection_up(): @@ -35,7 +35,7 @@ def helper_test_list_units(common): pytest.fail(str(e)) -def helper_test_get_solders(common): +def helper_test_get_solders(common: Common): """Test get_solders API""" if common._is_connection_up(): @@ -46,7 +46,7 @@ def helper_test_get_solders(common): pytest.fail(str(e)) -def helper_test_get_sherlock_info(common): +def helper_test_get_sherlock_info(common: Common): """Test get_sherlock_info API""" if common._is_connection_up(): diff --git a/tests/test_layer.py b/tests/test_layer.py index c9064c62..f7fd5b70 100644 --- a/tests/test_layer.py +++ b/tests/test_layer.py @@ -67,7 +67,7 @@ def test_all(): helper_test_delete_modeling_region(layer, region_id) -def helper_test_add_potting_region(layer): +def helper_test_add_potting_region(layer: Layer): """Test add_potting_region API.""" try: shape = PCBShape() @@ -239,7 +239,7 @@ def helper_test_add_potting_region(layer): pytest.fail(str(e)) -def helper_test_update_potting_region(layer): +def helper_test_update_potting_region(layer: Layer): """Test update potting region API.""" project = "Tutorial Project" @@ -336,7 +336,7 @@ def helper_test_update_potting_region(layer): assert return_code.message == "" -def helper_test_copy_potting_regions(layer): +def helper_test_copy_potting_regions(layer: Layer): project = "Tutorial Project" cca_name = "Main Board" @@ -442,7 +442,7 @@ def helper_test_copy_potting_regions(layer): assert return_code.message == "" -def helper_test_delete_potting_regions(layer): +def helper_test_delete_potting_regions(layer: Layer): project = "Tutorial Project" cca_name = "Main Board" @@ -528,7 +528,7 @@ def helper_test_update_mount_points_by_file(layer): assert type(e) == SherlockUpdateMountPointsByFileError -def helper_test_delete_all_mount_points(layer): +def helper_test_delete_all_mount_points(layer: Layer): """Test delete_all_mount_points API.""" try: layer.delete_all_mount_points( @@ -569,7 +569,7 @@ def helper_test_delete_all_mount_points(layer): pytest.fail(e.message) -def helper_test_delete_all_ict_fixtures(layer): +def helper_test_delete_all_ict_fixtures(layer: Layer): """Test delete_all_ict_fixtures API.""" try: layer.delete_all_ict_fixtures( @@ -610,7 +610,7 @@ def helper_test_delete_all_ict_fixtures(layer): pytest.fail(e.message) -def helper_test_delete_all_test_points(layer): +def helper_test_delete_all_test_points(layer: Layer): """Test delete_all_test_points API.""" try: layer.delete_all_test_points( @@ -651,7 +651,7 @@ def helper_test_delete_all_test_points(layer): pytest.fail(e.message) -def helper_test_update_test_points_by_file(layer): +def helper_test_update_test_points_by_file(layer: Layer): """Test update_test_points_by_file API.""" try: layer.update_test_points_by_file( @@ -695,7 +695,7 @@ def helper_test_update_test_points_by_file(layer): assert type(e) == SherlockUpdateTestPointsByFileError -def helper_test_update_test_fixtures_by_file(layer): +def helper_test_update_test_fixtures_by_file(layer: Layer): """Test update_test_fixtures_by_file API.""" try: layer.update_test_fixtures_by_file( @@ -739,7 +739,7 @@ def helper_test_update_test_fixtures_by_file(layer): assert type(e) == SherlockUpdateTestFixturesByFileError -def helper_test_export_all_test_points(layer): +def helper_test_export_all_test_points(layer: Layer): """Tests export_all_test_points API.""" try: layer.export_all_test_points( @@ -801,7 +801,7 @@ def helper_test_export_all_test_points(layer): pytest.fail(str(e)) -def helper_test_export_all_test_fixtures(layer): +def helper_test_export_all_test_fixtures(layer: Layer): """Tests export_all_test_fixtures API.""" try: layer.export_all_test_fixtures( @@ -863,7 +863,7 @@ def helper_test_export_all_test_fixtures(layer): pytest.fail(str(e)) -def helper_test_export_all_mount_points(layer): +def helper_test_export_all_mount_points(layer: Layer): """Tests export_all_mount_points API.""" try: layer.export_all_mount_points( @@ -925,7 +925,7 @@ def helper_test_export_all_mount_points(layer): pytest.fail(e.message) -def helper_test_add_modeling_region(layer): +def helper_test_add_modeling_region(layer: Layer) -> str: modeling_region = [ { "cca_name": "Card", @@ -1117,7 +1117,7 @@ def helper_test_add_modeling_region(layer): return valid_region_id -def helper_test_update_modeling_region(layer, region_id): +def helper_test_update_modeling_region(layer: Layer, region_id: str) -> str: updated_region_id = f"UpdatedRegion{uuid.uuid4()}" modeling_region = [ { @@ -1309,7 +1309,7 @@ def helper_test_update_modeling_region(layer, region_id): pytest.fail(str(e)) -def helper_test_copy_modeling_region(layer, region_id): +def helper_test_copy_modeling_region(layer: Layer, region_id: str): region_id_copy = f"RegionCopy{uuid.uuid4()}" copy_region_example = [ { @@ -1398,7 +1398,7 @@ def helper_test_copy_modeling_region(layer, region_id): pytest.fail(e.str_itr()) -def helper_test_delete_modeling_region(layer, region_id): +def helper_test_delete_modeling_region(layer: Layer, region_id: str): # Invalid project name try: diff --git a/tests/test_lifecycle.py b/tests/test_lifecycle.py index 293cf94e..06a16742 100644 --- a/tests/test_lifecycle.py +++ b/tests/test_lifecycle.py @@ -46,7 +46,7 @@ def test_all(): helper_test_load_shock_profile_pulses(lifecycle) -def helper_test_create_life_phase(lifecycle): +def helper_test_create_life_phase(lifecycle: Lifecycle): """Test create_life_phase API""" try: @@ -116,7 +116,7 @@ def helper_test_create_life_phase(lifecycle): return phase_name -def helper_test_add_random_vibe_event(lifecycle, phase_name): +def helper_test_add_random_vibe_event(lifecycle: Lifecycle, phase_name: str) -> str: """Test add_random_vibe_event API""" try: @@ -318,7 +318,7 @@ def helper_test_add_random_vibe_event(lifecycle, phase_name): return event_name -def helper_test_add_random_vibe_profiles(lifecycle, event_name, phase_name): +def helper_test_add_random_vibe_profiles(lifecycle: Lifecycle, event_name: str, phase_name: str): """Test the add_random_vibe_profiles API""" try: @@ -464,7 +464,7 @@ def helper_test_add_random_vibe_profiles(lifecycle, event_name, phase_name): assert type(e) == SherlockAddRandomVibeProfilesError -def helper_test_add_thermal_event(lifecycle, phase_name): +def helper_test_add_thermal_event(lifecycle: Lifecycle, phase_name: str) -> str: """Test add_thermal_event API""" try: @@ -550,7 +550,7 @@ def helper_test_add_thermal_event(lifecycle, phase_name): return event_name -def helper_test_add_thermal_profiles(lifecycle, phase_name, event_name): +def helper_test_add_thermal_profiles(lifecycle: Lifecycle, phase_name: str, event_name: str): """Test add_thermal_profiles API.""" try: @@ -780,7 +780,7 @@ def helper_test_add_thermal_profiles(lifecycle, phase_name, event_name): pytest.fail(str(e.str_itr())) -def helper_test_add_harmonic_event(lifecycle, phase_name): +def helper_test_add_harmonic_event(lifecycle: Lifecycle, phase_name: str) -> str: """Test add_harmonic_event API""" try: @@ -1034,7 +1034,9 @@ def helper_test_add_harmonic_event(lifecycle, phase_name): return event_name -def helper_test_add_harmonic_vibe_profile(lifecycle, phase_name, harmonic_vibe_event_name): +def helper_test_add_harmonic_vibe_profile( + lifecycle: Lifecycle, phase_name: str, harmonic_vibe_event_name: str +): """Test add_harmonic_profiles API.""" try: @@ -1281,7 +1283,7 @@ def helper_test_add_harmonic_vibe_profile(lifecycle, phase_name, harmonic_vibe_e pytest.fail(str(e.str_itr())) -def helper_test_add_shock_event(lifecycle, phase_name): +def helper_test_add_shock_event(lifecycle: Lifecycle, phase_name: str) -> str: """Test add_shock_event API.""" try: @@ -1461,7 +1463,7 @@ def helper_test_add_shock_event(lifecycle, phase_name): return event_name -def helper_test_add_shock_profile(lifecycle, phase_name, shock_event_name): +def helper_test_add_shock_profile(lifecycle: Lifecycle, phase_name: str, shock_event_name: str): """Test add_shock_profiles API.""" try: @@ -1761,7 +1763,7 @@ def helper_test_add_shock_profile(lifecycle, phase_name, shock_event_name): pytest.fail(str(e.str_itr())) -def helper_test_load_random_vibe_profile(lifecycle): +def helper_test_load_random_vibe_profile(lifecycle: Lifecycle): """Test load_random_vibe_profile.""" try: @@ -1822,7 +1824,7 @@ def helper_test_load_random_vibe_profile(lifecycle): assert type(e) == SherlockLoadRandomVibeProfileError -def helper_test_load_harmonic_profile(lifecycle): +def helper_test_load_harmonic_profile(lifecycle: Lifecycle): """Test load_harmonic_profile API.""" try: @@ -1863,7 +1865,7 @@ def helper_test_load_harmonic_profile(lifecycle): assert type(e) == SherlockLoadHarmonicProfileError -def helper_test_load_thermal_profile(lifecycle): +def helper_test_load_thermal_profile(lifecycle: Lifecycle): """Test load_thermal_profile API""" try: @@ -1924,7 +1926,7 @@ def helper_test_load_thermal_profile(lifecycle): assert type(e) == SherlockLoadThermalProfileError -def helper_test_load_shock_profile_dataset(lifecycle): +def helper_test_load_shock_profile_dataset(lifecycle: Lifecycle): """Test load_shock_profile_dataset API""" try: @@ -1985,7 +1987,7 @@ def helper_test_load_shock_profile_dataset(lifecycle): assert type(e) == SherlockLoadShockProfileDatasetError -def helper_test_load_shock_profile_pulses(lifecycle): +def helper_test_load_shock_profile_pulses(lifecycle: Lifecycle): """Test load_shock_profile_pulses API""" try: lifecycle.load_shock_profile_pulses( diff --git a/tests/test_parts.py b/tests/test_parts.py index 78c37278..70e71758 100644 --- a/tests/test_parts.py +++ b/tests/test_parts.py @@ -46,7 +46,7 @@ def test_all(): helper_test_get_part_location(parts) -def helper_test_update_parts_list(parts): +def helper_test_update_parts_list(parts: Parts): """Test update_parts_list API.""" if parts._is_connection_up(): @@ -111,7 +111,7 @@ def helper_test_update_parts_list(parts): assert str(e.str_itr()) == "['Update parts list error: Parts library is invalid.']" -def helper_test_update_parts_from_AVL(parts): +def helper_test_update_parts_from_AVL(parts: Parts): try: parts.update_parts_from_AVL( project="", @@ -154,7 +154,7 @@ def helper_test_update_parts_from_AVL(parts): pytest.fail(e.message) -def helper_test_update_parts_locations(parts): +def helper_test_update_parts_locations(parts: Parts): """Test update_parts_locations API.""" if parts._is_connection_up(): @@ -407,7 +407,7 @@ def helper_test_update_parts_locations(parts): ) -def helper_test_update_parts_locations_by_file(parts): +def helper_test_update_parts_locations_by_file(parts: Parts): """Test update_parts_locations_by_file API.""" if parts._is_connection_up(): @@ -445,7 +445,7 @@ def helper_test_update_parts_locations_by_file(parts): assert str(e.str_itr()) == "['Update parts locations by file error: CCA name is invalid.']" -def helper_test_import_parts_list(parts): +def helper_test_import_parts_list(parts: Parts): """Tests import_parts_list API.""" if parts._is_connection_up(): # happy path test missing because needs valid file @@ -483,7 +483,7 @@ def helper_test_import_parts_list(parts): assert str(e) == "Import parts list error: CCA name is invalid." -def helper_test_export_parts_list(parts): +def helper_test_export_parts_list(parts: Parts): """Tests export_parts_list API.""" try: parts.export_parts_list( @@ -550,7 +550,7 @@ def helper_test_export_parts_list(parts): assert type(e) == SherlockExportPartsListError -def helper_test_enable_lead_modeling(parts): +def helper_test_enable_lead_modeling(parts: Parts): """Test enable_lead_modelign API.""" if parts._is_connection_up(): try: @@ -590,7 +590,7 @@ def helper_test_enable_lead_modeling(parts): assert str(e) == "Enable lead modeling error: CCA name is invalid." -def helper_test_get_part_location(parts): +def helper_test_get_part_location(parts: Parts): """Test get_part_location API""" if parts._is_connection_up(): @@ -680,7 +680,7 @@ def helper_test_get_part_location(parts): assert str(e) == "Get part location error: Location unit is invalid." -def helper_test_update_parts_list_properties(parts): +def helper_test_update_parts_list_properties(parts: Parts): """Test update_parts_list_properties API""" try: parts.update_parts_list_properties( @@ -835,7 +835,7 @@ def helper_test_update_parts_list_properties(parts): pytest.fail(e.message) -def helper_test_export_net_list(parts): +def helper_test_export_net_list(parts: Parts): """Test export_net_list API""" try: diff --git a/tests/test_project.py b/tests/test_project.py index 49aa592d..67f1a2c0 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -73,7 +73,7 @@ def test_all(): helper_test_export_project(project) -def helper_test_delete_project(project): +def helper_test_delete_project(project: Project): """Test delete_project API""" try: project.delete_project("") @@ -90,7 +90,7 @@ def helper_test_delete_project(project): assert type(e) == SherlockDeleteProjectError -def helper_test_import_odb_archive(project): +def helper_test_import_odb_archive(project: Project): """Test import_odb_archive API""" try: project.import_odb_archive("", True, True, True, True) @@ -107,7 +107,7 @@ def helper_test_import_odb_archive(project): assert type(e) == SherlockImportODBError -def helper_test_import_ipc2581_archive(project): +def helper_test_import_ipc2581_archive(project: Project): """Test import_ipc2581_archive API""" try: project.import_ipc2581_archive("", True, True) @@ -123,7 +123,7 @@ def helper_test_import_ipc2581_archive(project): assert type(e) == SherlockImportIpc2581Error -def helper_test_generate_project_report(project): +def helper_test_generate_project_report(project: Project): """Test generate_project_report API.""" try: project.generate_project_report("", "John Doe", "Generic Co.", "C:/report.pdf") @@ -172,7 +172,7 @@ def helper_test_generate_project_report(project): assert type(e) == SherlockGenerateProjectReportError -def helper_test_list_ccas(project): +def helper_test_list_ccas(project: Project): """Test list_ccas API""" try: @@ -210,7 +210,7 @@ def helper_test_list_ccas(project): pytest.fail(str(e.str_itr())) -def helper_test_add_cca(project): +def helper_test_add_cca(project: Project): """Test add_cca API""" try: @@ -335,7 +335,7 @@ def helper_test_add_cca(project): pytest.fail(str(e)) -def helper_test_add_strain_maps(project): +def helper_test_add_strain_maps(project: Project): """Test add_strain_maps API""" try: @@ -1108,7 +1108,7 @@ def helper_test_add_strain_maps(project): assert type(e) == SherlockAddStrainMapsError -def helper_test_list_strain_maps(project): +def helper_test_list_strain_maps(project: Project): """Test list_strain_maps API""" try: @@ -1154,7 +1154,7 @@ def helper_test_list_strain_maps(project): pytest.fail(str(e.str_itr())) -def helper_test_add_project(project): +def helper_test_add_project(project: Project) -> str: """Test add_project API""" try: @@ -1180,7 +1180,7 @@ def helper_test_add_project(project): pytest.fail(str(e)) -def helper_test_list_thermal_maps(project): +def helper_test_list_thermal_maps(project: Project): """Test list_thermal_maps API""" expected_cca_name = "Main Board" @@ -1243,7 +1243,7 @@ def helper_test_list_thermal_maps(project): pytest.fail(str(e.str_itr())) -def helper_test_add_thermal_maps(project): +def helper_test_add_thermal_maps(project: Project): """Test add_thermal_maps API""" try: @@ -2162,7 +2162,7 @@ def helper_test_add_thermal_maps(project): assert type(e) == SherlockAddThermalMapsError -def helper_test_update_thermal_maps(project): +def helper_test_update_thermal_maps(project: Project): """Test update_thermal_maps API""" try: @@ -2896,7 +2896,7 @@ def helper_test_update_thermal_maps(project): pytest.fail(str(e.str_itr())) -def helper_test_import_project_zip_archive(project): +def helper_test_import_project_zip_archive(project: Project): """Test import_project_zip_archive API""" try: project.import_project_zip_archive("", "Demos", "Tutorial Project.zip") @@ -2926,7 +2926,7 @@ def helper_test_import_project_zip_archive(project): assert type(e) == SherlockImportProjectZipArchiveError -def helper_test_import_project_zip_archive_single_mode(project): +def helper_test_import_project_zip_archive_single_mode(project: Project): """Test import_project_zip_archive_single_mode API""" try: project.import_project_zip_archive_single_mode( @@ -2970,15 +2970,15 @@ def helper_test_import_project_zip_archive_single_mode(project): assert type(e) == SherlockImportProjectZipArchiveSingleModeError -def clean_up_after_add(project, project_name): +def clean_up_after_add(project: Project, project_name: str): if project_name is not None: project.delete_project(project_name) -def helper_test_export_project(project): +def helper_test_export_project(project: Project): """Test method for export project""" try: - result = project.export_project( + project.export_project( project_name="", export_design_files=True, export_result_files=True, @@ -2994,7 +2994,7 @@ def helper_test_export_project(project): assert str(e) == "Export project error : Project name is invalid" try: - result = project.export_project( + project.export_project( project_name="Tutorial Project", export_design_files=True, export_result_files=True, @@ -3010,7 +3010,7 @@ def helper_test_export_project(project): assert str(e) == "Export project error : Export directory is invalid" try: - result = project.export_project( + project.export_project( project_name="Tutorial Project", export_design_files=True, export_result_files=True, @@ -3027,7 +3027,7 @@ def helper_test_export_project(project): if project._is_connection_up(): try: - result = project.export_project( + project.export_project( project_name="", export_design_files=True, export_result_files=True, @@ -3069,7 +3069,7 @@ def helper_test_export_project(project): pytest.fail(str(e)) -def helper_test_create_cca_from_modeling_region(project): +def helper_test_create_cca_from_modeling_region(project: Project): """Test create_cca_from_modeling_region API""" try: project.create_cca_from_modeling_region( diff --git a/tests/test_stackup.py b/tests/test_stackup.py index 709f161d..85daa7f0 100644 --- a/tests/test_stackup.py +++ b/tests/test_stackup.py @@ -32,7 +32,7 @@ def test_all(): helper_test_get_total_conductor_thickness(stackup) -def helper_test_gen_stackup(stackup): +def helper_test_gen_stackup(stackup: Stackup): """Test gen_stackup API.""" try: stackup.gen_stackup( @@ -170,7 +170,7 @@ def helper_test_gen_stackup(stackup): pytest.fail(str(e)) -def helper_test_update_conductor_layer(stackup): +def helper_test_update_conductor_layer(stackup: Stackup): """Test update_conductor_layer API.""" try: stackup.update_conductor_layer( @@ -276,7 +276,7 @@ def helper_test_update_conductor_layer(stackup): pytest.fail(str(e)) -def helper_test_update_laminate_layer(stackup): +def helper_test_update_laminate_layer(stackup: Stackup): """Test update_laminate_layer API.""" try: @@ -465,7 +465,7 @@ def helper_test_update_laminate_layer(stackup): pytest.fail(str(e)) -def helper_test_list_conductor_layers(stackup): +def helper_test_list_conductor_layers(stackup: Stackup): """Test list_conductor_layers API""" try: stackup.list_conductor_layers("") @@ -494,7 +494,7 @@ def helper_test_list_conductor_layers(stackup): pytest.fail(str(e)) -def helper_test_list_laminate_layers(stackup): +def helper_test_list_laminate_layers(stackup: Stackup): """Test list_laminate_layers API""" try: stackup.list_laminate_layers("") @@ -522,7 +522,7 @@ def helper_test_list_laminate_layers(stackup): pytest.fail(str(e)) -def helper_test_get_layer_count(stackup): +def helper_test_get_layer_count(stackup: Stackup): """Test get_layer_count API""" try: stackup.get_layer_count(project="", cca_name="Card") @@ -623,7 +623,7 @@ def helper_test_get_stackup_props(stackup): pytest.fail(str(e)) -def helper_test_get_total_conductor_thickness(stackup): +def helper_test_get_total_conductor_thickness(stackup: Stackup): try: stackup.get_total_conductor_thickness(project="", cca_name="Card", thickness_unit="oz") pytest.fail("No exception raised when using an invalid parameter")