diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 16fc47895..92457aad8 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -83,7 +83,7 @@ jobs: - name: Install dependencies run: | source .venv/bin/activate - uv pip install ty==0.0.25 ansys-platform-instancemanagement + uv pip install ty==0.0.25 ansys-platform-instancemanagement ansys-speos-core[graphics] # NOTE: At the moment this will only run on ansys/aedt/core/speos.py which is working - name: Run Ty on selected files @@ -108,7 +108,6 @@ jobs: --exclude src/ansys/speos/core/simulation.py \ --exclude src/ansys/speos/core/sensor.py \ --exclude src/ansys/speos/core/__init__.py \ - --exclude src/ansys/speos/core/generic \ --exclude src/ansys/speos/core/kernel \ --exclude src/ansys/speos/core/workflow \ --exclude examples/core \ diff --git a/doc/changelog.d/911.maintenance.md b/doc/changelog.d/911.maintenance.md new file mode 100644 index 000000000..f76a6feff --- /dev/null +++ b/doc/changelog.d/911.maintenance.md @@ -0,0 +1 @@ +Improve typing generic diff --git a/src/ansys/speos/core/generic/file_transfer.py b/src/ansys/speos/core/generic/file_transfer.py index dfae046c4..26bfc76a9 100644 --- a/src/ansys/speos/core/generic/file_transfer.py +++ b/src/ansys/speos/core/generic/file_transfer.py @@ -31,7 +31,7 @@ import ansys.api.speos.file.v1.file_transfer_pb2 as file_transfer__v1__pb2 import ansys.api.speos.file.v1.file_transfer_pb2_grpc as file_transfer__v1__pb2_grpc -import grpc +from grpc import _channel from ansys.speos.core.generic.version_checker import server_version_checker from ansys.speos.core.kernel.client import SpeosClient @@ -69,7 +69,7 @@ def _file_to_chunks(self, file, file_name, chunk_size=4000000): if first_chunk: if self._is_gte_26r1: - chunk.file_name = file_name + chunk.file_name = file_name # ty: ignore first_chunk = False yield chunk @@ -95,7 +95,7 @@ def upload_file( Contains for example file uri and upload duration. """ if not file_path.exists() or not file_path.is_file(): - raise ValueError("Incorrect file_path : " + file_path) + raise ValueError("Incorrect file_path : " + str(file_path)) with file_path.open("rb") as file: chunk_iterator = self._file_to_chunks(file, file_path.name) @@ -109,7 +109,7 @@ def upload_file( try: return self._file_transfer_service_stub.Upload(chunk_iterator, metadata=metadata) - except grpc._channel._InactiveRpcError as e: + except _channel._InactiveRpcError as e: err = ( '"file_name" field in Chunk is missing or "reserved-file-uri"' + " key/value not provided in ClientContext's metadata" @@ -144,11 +144,11 @@ def upload_folder( Contains for example file uri and upload duration. """ if not folder_path.exists() or not folder_path.is_dir(): - raise ValueError("Incorrect folder_path : " + folder_path) + raise ValueError("Incorrect folder_path : " + str(folder_path)) main_file_path = folder_path / main_file_name if not main_file_path.exists() or not main_file_path.is_file(): - raise ValueError("Incorrect main_file_path : " + main_file_path) + raise ValueError("Incorrect main_file_path : " + str(main_file_path)) upload_responses = [] add_dependencies_request = file_transfer__v1__pb2.AddDependencies_Request() @@ -217,7 +217,7 @@ def download_file( """ start_time = datetime.datetime.now() if not download_location.exists() or not download_location.is_dir(): - raise ValueError("Incorrect download_location : " + download_location) + raise ValueError("Incorrect download_location : " + str(download_location)) chunks = self._file_transfer_service_stub.Download( file_transfer__v1__pb2.Download_Request(uri=file_uri) @@ -281,7 +281,7 @@ def download_folder( Contains for example file uri, file name, file size and download duration. """ if not download_location.exists() or not download_location.is_dir(): - raise ValueError("Incorrect download_location : " + download_location) + raise ValueError("Incorrect download_location : " + str(download_location)) response = [] diff --git a/src/ansys/speos/core/generic/general_methods.py b/src/ansys/speos/core/generic/general_methods.py index 9bfe26777..dd3a59689 100644 --- a/src/ansys/speos/core/generic/general_methods.py +++ b/src/ansys/speos/core/generic/general_methods.py @@ -31,7 +31,7 @@ from functools import lru_cache, wraps import os from pathlib import Path -from typing import List, Optional, Union, cast +from typing import List, Optional, Tuple, Union, cast import warnings from ansys.tools.common.path import get_available_ansys_installations @@ -184,7 +184,7 @@ def error_no_install(install_path: Union[Path, str], version: Union[int, str]) - Always raised to signal a missing Speos RPC installation. """ raise FileNotFoundError( - f"Ansys Speos RPC server installation not found at {install_path}. " + f"Ansys Speos RPC server installation not found at {str(install_path)}. " f"Please define AWP_ROOT{version} environment variable. " ) @@ -245,9 +245,11 @@ def retrieve_speos_install_dir( installations.get(int(version)) # dict keys are int or os.environ.get(f"AWP_ROOT{version}") # fallback: env var ) - if not ansys_loc: + if ansys_loc: + path = Path(ansys_loc) / "Optical Products" / "SPEOS_RPC" + else: error_no_install(speos_rpc_path or "", int(version)) - path = Path(ansys_loc) / "Optical Products" / "SPEOS_RPC" + path = Path() # for type checker; this line is never reached # --- verify executable exists ----------------------------------------- speos_exec = path / ("SpeosRPC_Server.exe" if os.name == "nt" else "SpeosRPC_Server.x") @@ -257,7 +259,7 @@ def retrieve_speos_install_dir( return path -def wavelength_to_rgb(wavelength: float, gamma: float = 0.8) -> [int, int, int, int]: +def wavelength_to_rgb(wavelength: float, gamma: float = 0.8) -> Tuple[int, int, int, int]: """Convert a given wavelength of light to an approximate RGB color value. The wavelength must be given in nanometers in the range from 380 nm to 750 nm. @@ -305,7 +307,7 @@ def wavelength_to_rgb(wavelength: float, gamma: float = 0.8) -> [int, int, int, r *= 255 g *= 255 b *= 255 - return [int(r), int(g), int(b), 255] + return (int(r), int(g), int(b), 255) def min_speos_version(major: int, minor: int, service_pack: int): diff --git a/src/ansys/speos/core/generic/parameters.py b/src/ansys/speos/core/generic/parameters.py index c9ca4a9f2..5da110bc5 100644 --- a/src/ansys/speos/core/generic/parameters.py +++ b/src/ansys/speos/core/generic/parameters.py @@ -26,7 +26,7 @@ import datetime from enum import Enum from pathlib import Path -from typing import Optional, Union +from typing import Literal, Optional, Union from ansys.speos.core.generic.constants import ORIGIN @@ -137,7 +137,7 @@ class LayerBySequenceParameters: maximum_nb_of_sequence: int = 10 """Maximum number of sequencese stored in Speos Result file""" - sequence_type: Union[SequenceTypes.by_face, SequenceTypes.by_geometry] = ( + sequence_type: Union[Literal[SequenceTypes.by_face], Literal[SequenceTypes.by_geometry]] = ( SequenceTypes.by_geometry ) """Defines how sequences are calculated""" @@ -160,7 +160,7 @@ class LayerByFaceParameters: geometries: Optional[list[GeometryLayerParameters]] = None """List of Geometry Layers""" sca_filtering_types: Union[ - SCAFilteringTypes.intersected_one_time, SCAFilteringTypes.last_impact + Literal[SCAFilteringTypes.intersected_one_time], Literal[SCAFilteringTypes.last_impact] ] = SCAFilteringTypes.last_impact """Defines how data result data is filtered""" @@ -218,8 +218,8 @@ class ColorParameters: """Color mode Camera Parameter.""" balance_mode: Union[ - ColorBalanceModeTypes.none, - ColorBalanceModeTypes.grey_world, + Literal[ColorBalanceModeTypes.none], + Literal[ColorBalanceModeTypes.grey_world], BalanceModeUserWhiteParameters, BalanceModeDisplayPrimariesParameters, ] = ColorBalanceModeTypes.none @@ -248,7 +248,7 @@ class PhotometricCameraParameters: default_factory=ColorParameters ) """Color mode of the Camera Sensor.""" - layer_type: Union[LayerTypes.none, LayerTypes.by_source] = LayerTypes.none + layer_type: Union[Literal[LayerTypes.none], Literal[LayerTypes.by_source]] = LayerTypes.none """Layer separation parameter.""" png_bits: PngBits = PngBits.png_16 """PNG bit resolution of the Camera Sensor.""" @@ -374,7 +374,10 @@ class IrradianceSensorParameters: axis_system: list[float] = field(default_factory=lambda: ORIGIN) """Position of the sensor.""" sensor_type: Union[ - SensorTypes.photometric, ColorimetricParameters, SpectralParameters, SensorTypes.radiometric + Literal[SensorTypes.photometric], + Literal[SensorTypes.radiometric], + ColorimetricParameters, + SpectralParameters, ] = SensorTypes.photometric """Type of the sensor.""" integration_type: IntegrationTypes = IntegrationTypes.planar @@ -384,9 +387,9 @@ class IrradianceSensorParameters: rayfile_type: Union[RayfileTypes] = RayfileTypes.none """Type of rayfile stored by the sensor.""" layer_type: Union[ - LayerTypes.none, - LayerTypes.by_source, - LayerTypes.by_polarization, + Literal[LayerTypes.none], + Literal[LayerTypes.by_source], + Literal[LayerTypes.by_polarization], LayerByFaceParameters, LayerBySequenceParameters, LayerByIncidenceAngleParameters, @@ -405,7 +408,10 @@ class RadianceSensorParameters: axis_system: list[float] = field(default_factory=lambda: ORIGIN) """Position of the sensor.""" sensor_type: Union[ - SensorTypes.photometric, ColorimetricParameters, SpectralParameters, SensorTypes.radiometric + Literal[SensorTypes.photometric], + Literal[SensorTypes.radiometric], + ColorimetricParameters, + SpectralParameters, ] = SensorTypes.photometric """Type of the sensor.""" focal_length: float = 250.0 @@ -416,8 +422,8 @@ class RadianceSensorParameters: observer: Union[None, list[float]] = None """The position of the observer point.""" layer_type: Union[ - LayerTypes.none, - LayerTypes.by_source, + Literal[LayerTypes.none], + Literal[LayerTypes.by_source], LayerByFaceParameters, LayerBySequenceParameters, ] = LayerTypes.none @@ -428,19 +434,19 @@ class RadianceSensorParameters: class Irradiance3DSensorParameters: """Parameters class for 3D Irradiance Sensor.""" - sensor_type: Union[SensorTypes.photometric, ColorimetricParameters, SensorTypes.radiometric] = ( - SensorTypes.photometric - ) + sensor_type: Union[ + Literal[SensorTypes.photometric], ColorimetricParameters, Literal[SensorTypes.radiometric] + ] = SensorTypes.photometric """Type of the sensor.""" measures: MeasuresParameters = field(default_factory=MeasuresParameters) """Measurement activation state.""" - integration_type: Union[IntegrationTypes.planar, IntegrationTypes.radial] = ( + integration_type: Union[Literal[IntegrationTypes.planar], Literal[IntegrationTypes.radial]] = ( IntegrationTypes.planar ) """Integration type.""" rayfile_type: Union[RayfileTypes] = RayfileTypes.none """Rayfile type stored.""" - layer_type: Union[LayerTypes.none, LayerTypes.by_source] = LayerTypes.none + layer_type: Union[Literal[LayerTypes.none], Literal[LayerTypes.by_source]] = LayerTypes.none """Layer separation type.""" geometries: Optional[list] = None """Sensor geometry.""" @@ -469,7 +475,10 @@ class IntensityXMPSensorParameters: axis_system: list[float] = field(default_factory=lambda: ORIGIN) """Position of the sensor.""" sensor_type: Union[ - SensorTypes.photometric, ColorimetricParameters, SpectralParameters, SensorTypes.radiometric + Literal[SensorTypes.photometric], + ColorimetricParameters, + SpectralParameters, + Literal[SensorTypes.radiometric], ] = SensorTypes.photometric """Type of the sensor.""" orientation: IntensitySensorOrientationTypes = IntensitySensorOrientationTypes.x_as_meridian @@ -477,8 +486,8 @@ class IntensityXMPSensorParameters: viewing_direction: IntensitySensorViewingTypes = IntensitySensorViewingTypes.from_source """Viewing Direction onto the result.""" layer_type: Union[ - LayerTypes.none, - LayerTypes.by_source, + Literal[LayerTypes.none], + Literal[LayerTypes.by_source], LayerByFaceParameters, LayerBySequenceParameters, ] = LayerTypes.none diff --git a/src/ansys/speos/core/generic/visualization_methods.py b/src/ansys/speos/core/generic/visualization_methods.py index a2df205c0..464fc7bf7 100644 --- a/src/ansys/speos/core/generic/visualization_methods.py +++ b/src/ansys/speos/core/generic/visualization_methods.py @@ -22,7 +22,7 @@ """Provides the ``VisualData`` class.""" -from typing import TYPE_CHECKING, List, Tuple, Union +from typing import TYPE_CHECKING, List, Tuple, Union, cast import numpy as np @@ -239,21 +239,25 @@ def __init__( raise ValueError( "line_vertices is expected to be composed of 2 vertices with 3 elements each." ) - line_vertices = np.array(line_vertices) + vertices_array = np.array(line_vertices) if arrow: self.__data = pv.Arrow( - start=line_vertices[0], - direction=line_vertices[1], + start=vertices_array[0], + direction=vertices_array[1], scale=1, tip_radius=0.05, shaft_radius=0.01, ) else: - self.__data = pv.Line(line_vertices[0], line_vertices[0] + line_vertices[1]) + self.__data = pv.Line(vertices_array[0], vertices_array[0] + vertices_array[1]) if all(value < 1 for value in color): - self.__color = color + (255,) + self.__color: Tuple[float, float, float, int] = cast( + Tuple[float, float, float, int], color + (255,) + ) else: - self.__color = tuple(value / 255 for value in color) + (255,) + self.__color = cast( + Tuple[float, float, float, int], tuple(value / 255 for value in color) + (255,) + ) @property def data(self) -> "pv.PolyData": @@ -269,13 +273,13 @@ def data(self) -> "pv.PolyData": return self.__data @property - def color(self) -> Tuple[float, float, float]: + def color(self) -> Tuple[float, float, float, int]: """ Returns the color property of _VisualArrow. Returns ------- - Tuple[float, float, float] + Tuple[float, float, float, int] The color tuple of _VisualArrow. """ @@ -334,7 +338,9 @@ def add_data_triangle(self, triangle_vertices: List[List[float]]) -> None: "triangle_vertices is expected to be composed of 3 vertices with 3 elements each." ) faces = [[3, 0, 1, 2]] - self._data = self._data.append_polydata(pv.PolyData(triangle_vertices, faces)) + self._data = cast("pv.PolyData", self._data).append_polydata( + pv.PolyData(triangle_vertices, faces) + ) def add_data_rectangle(self, rectangle_vertices: List[List[float]]) -> None: """ @@ -355,7 +361,9 @@ def add_data_rectangle(self, rectangle_vertices: List[List[float]]) -> None: raise ValueError( "rectangle_vertices is expected to be composed of 3 vertices with 3 elements each." ) - self._data = self._data.append_polydata(pv.Rectangle(rectangle_vertices)) + self._data = cast("pv.PolyData", self._data).append_polydata( + pv.Rectangle(rectangle_vertices) + ) def add_data_line(self, line: _VisualArrow) -> None: """ @@ -393,7 +401,7 @@ def add_data_mesh(self, vertices: np.ndarray, facets: np.ndarray) -> None: raise ValueError( "mesh vertices is expected to be composed of 3 elements each, and 4 for facets." ) - self._data = self._data.append_polydata(pv.PolyData(vertices, facets)) + self._data = cast("pv.PolyData", self._data).append_polydata(pv.PolyData(vertices, facets)) def local2absolute(local_vertice: np.ndarray, coordinates) -> np.ndarray: