diff --git a/pyproject.toml b/pyproject.toml index 1d67d8e908d..2686b5f4421 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,8 @@ dependencies = [ "Pillow>=9.3.0", "pypng>=0.0.20", "psutil>=5.9.2", + "usd-core>=24.8", + "pygltflib>=1.16.2", ] [project.optional-dependencies] @@ -44,8 +46,6 @@ dev = [ "ipdb>=0.9.4", "dill>=0.3.5.1", "pre-commit>=3.3.3", - "usd-core>=24.8", - "pygltflib>=1.16.2", ] tests = [ "pytest==8.3.2", @@ -55,8 +55,6 @@ tests = [ "urllib3==2.2.2", "requests>=2.28.2", "docker>=6.1.0", - "usd-core>=24.8", - "pygltflib>=1.16.2", ] doc = [ "Sphinx==8.0.2", diff --git a/src/ansys/pyensight/core/common.py b/src/ansys/pyensight/core/common.py index 9bd53c71a60..ef51c3dc838 100644 --- a/src/ansys/pyensight/core/common.py +++ b/src/ansys/pyensight/core/common.py @@ -69,7 +69,7 @@ def find_unused_ports(count: int, avoid: Optional[List[int]] = None) -> Optional if result != 0: ports.append(port) else: - sock.close() + sock.close() # pragma: no cover if len(ports) >= count: return ports # in case we failed... @@ -101,7 +101,7 @@ def get_host_port(uri: str) -> Tuple[str, int]: return (parse_results.host, port) -def get_file_service(pim_instance: Any) -> Optional[Any]: +def get_file_service(pim_instance: Any) -> Optional[Any]: # pragma: no cover """Get the file service object for the input pim instance. Parameters @@ -131,7 +131,7 @@ def get_file_service(pim_instance: Any) -> Optional[Any]: return None -def populate_service_host_port( +def populate_service_host_port( # pragma: no cover pim_instance: Any, service_host_port: Dict[str, Tuple[str, int]], webui: bool = False ) -> Dict[str, Tuple[str, int]]: """Populate the service host port dictionary with the services available in the PIM instance. @@ -183,9 +183,9 @@ def launch_enshell_interface( enshell: enshell_grpc.EnShellGRPC the enshell gRPC interface """ - if enshell_grpc_channel: - enshell = enshell_grpc.EnShellGRPC() - enshell.connect_existing_channel(enshell_grpc_channel) + if enshell_grpc_channel: # pragma: no cover + enshell = enshell_grpc.EnShellGRPC() # pragma: no cover + enshell.connect_existing_channel(enshell_grpc_channel) # pragma: no cover else: enshell = enshell_grpc.EnShellGRPC(port=grpc_port) time_start = time.time() diff --git a/src/ansys/pyensight/core/launch_ensight.py b/src/ansys/pyensight/core/launch_ensight.py index d8f66ec6c8b..313f96a4f5d 100644 --- a/src/ansys/pyensight/core/launch_ensight.py +++ b/src/ansys/pyensight/core/launch_ensight.py @@ -14,7 +14,6 @@ import logging from typing import Optional -from ansys.pyensight.core.libuserd import LibUserd from ansys.pyensight.core.locallauncher import LocalLauncher from ansys.pyensight.core.session import Session @@ -37,9 +36,9 @@ logging.debug(f"docker_is_available: {docker_is_available}\n") -if pim_is_available: +if pim_is_available: # pragma: no cover - def _prepare_pim( + def _prepare_pim( # pragma: no cover product_version: Optional[str] = None, ): """Create a PIM instance and gRPC channel for the input version of EnSight. @@ -66,7 +65,7 @@ def _prepare_pim( ) return instance, channel - def _launch_ensight_with_pim( + def _launch_ensight_with_pim( # pragma: no cover product_version: Optional[str] = None, **kwargs, ) -> "Session": @@ -94,7 +93,11 @@ def _launch_ensight_with_pim( launcher = DockerLauncher(channel=channel, pim_instance=instance, **kwargs) return launcher.connect() - def _launch_libuserd_with_pim(product_version: Optional[str] = None, **kwargs): + def _launch_libuserd_with_pim( + product_version: Optional[str] = None, **kwargs + ): # pragma: no cover + from ansys.pyensight.core.libuserd import LibUserd + instance, channel = _prepare_pim(product_version=product_version) libuserd = LibUserd(channel=channel, pim_instance=instance, **kwargs) libuserd.initialize() @@ -192,7 +195,7 @@ def launch_ensight( return launcher.start() # pragma: no cover -def launch_libuserd( +def launch_libuserd( # pragma: no cover product_version: Optional[str] = None, use_pim: bool = True, use_docker: bool = True, @@ -248,6 +251,8 @@ def launch_libuserd( variety of error conditions """ + from ansys.pyensight.core.libuserd import LibUserd + logging.debug(f"pim_is_available: {pim_is_available} use_pim: {use_pim}\n") # pragma: no cover if pim_is_available and use_pim: # pragma: no cover if pypim.is_configured(): diff --git a/src/ansys/pyensight/core/libuserd.py b/src/ansys/pyensight/core/libuserd.py index 19060fdf8b9..40dbc3d86af 100644 --- a/src/ansys/pyensight/core/libuserd.py +++ b/src/ansys/pyensight/core/libuserd.py @@ -955,7 +955,6 @@ def __init__( self._security_file: Optional[str] = None # Docker attributes self._pull_image = pull_image_if_not_available - self._temporary_pyansys_dir: Optional[str] = None self._timeout = timeout self._product_version = product_version self._data_directory = data_directory @@ -1078,7 +1077,8 @@ def _launch_enshell(self) -> None: self._grpc_port = int(self._service_host_port["grpc_private"][1]) self._host = self._service_host_port["grpc_private"][0] else: - self._temporary_pyansys_dir = tempfile.mkdtemp(prefix="pyensight_") + if not self._data_directory: + self._data_directory = tempfile.mkdtemp(prefix="pyensight_") available = self._check_if_image_available() if not available and self._pull_image and not self._pim_instance: self._pull_docker_image() @@ -1120,11 +1120,8 @@ def _launch_container(self) -> None: container_env = { "ENSIGHT_SECURITY_TOKEN": self.security_token, } - # At runtime we don't know if a volume is available, so create one a priori - # where the downloaded PyAnsys data can be downloaded - data_volume = {self._temporary_pyansys_dir: {"bind": "/pyansys_data", "mode": "rw"}} - if self._data_directory: - data_volume.update({self._data_directory: {"bind": "/data", "mode": "rw"}}) + data_volume = {self._data_directory: {"bind": "/data", "mode": "rw"}} + if not self._docker_client: raise RuntimeError("Could not startup docker.") self._container = self._docker_client.containers.run( # pragma: no cover @@ -1132,7 +1129,6 @@ def _launch_container(self) -> None: command=enshell_cmd, volumes=data_volume, environment=container_env, - device_requests=[docker.types.DeviceRequest(count=-1)], ports=ports_to_map, tty=True, detach=True, @@ -1825,12 +1821,12 @@ def download_pyansys_example( uri = f"{base_uri}/{directory}/{filename}" # Local installs and PIM instances download_path = f"{os.getcwd()}/{filename}" - if self._temporary_pyansys_dir: + if self._container and self._data_directory: # Docker Image - download_path = os.path.join(self._temporary_pyansys_dir, filename) + download_path = os.path.join(self._data_directory, filename) self._download_files(uri, download_path, folder=folder) pathname = download_path - if self._temporary_pyansys_dir: + if self._container: # Convert local path to Docker mounted volume path - pathname = f"/pyansys_data/{filename}" + pathname = f"/data/{filename}" return pathname diff --git a/src/ansys/pyensight/core/utils/readers.py b/src/ansys/pyensight/core/utils/readers.py index 238f2315dbb..c5b006c45e8 100644 --- a/src/ansys/pyensight/core/utils/readers.py +++ b/src/ansys/pyensight/core/utils/readers.py @@ -10,8 +10,6 @@ from typing import Optional, Tuple, Union import uuid -from ansys.pyensight.core import LocalLauncher - try: import ensight except ImportError: @@ -105,15 +103,20 @@ def _find_dvs_port(self, tmp_name: Optional[str] = None): """Find the dvs port allocated from the input temporary name""" if not tmp_name: raise RuntimeError("Temporary name for dvs port file not available") - is_local = isinstance(self._ensight._session._launcher, LocalLauncher) - if is_local: - with open(tmp_name) as dvs_port_file: - self._dvs_port = int(dvs_port_file.read().strip()) - else: - log_content = self._ensight._session._launcher.enshell_log_contents() - dvs_port_match = re.search(r"\(0.0.0.0\):([0-9]{4,5})\n", log_content) - if dvs_port_match: - self._dvs_port = int(str(dvs_port_match.groups(1)[0]).strip()) + try_local = True + if self._ensight._session._launcher: + if hasattr(self._ensight._session._launcher, "_enshell"): + try_local = False + log_content = self._ensight._session._launcher.enshell_log_contents() + dvs_port_match = re.search(r"\(0.0.0.0\):([0-9]{4,5})\n", log_content) + if dvs_port_match: + self._dvs_port = int(str(dvs_port_match.groups(1)[0]).strip()) + if try_local: + try: + with open(tmp_name) as dvs_port_file: + self._dvs_port = int(dvs_port_file.read().strip()) + except Exception: + raise RuntimeError("Cannot retrieve DVS Port") @staticmethod def _launch_dvs_callback_in_ensight( diff --git a/tests/example_tests/test_libuserd.py b/tests/example_tests/test_libuserd.py new file mode 100644 index 00000000000..7e23b4f5d5d --- /dev/null +++ b/tests/example_tests/test_libuserd.py @@ -0,0 +1,32 @@ +from ansys.pyensight.core.libuserd import LibUserd +import pytest + + +def test_libuserd_basic(tmpdir, pytestconfig: pytest.Config): + data_dir = tmpdir.mkdir("datadir") + use_local = pytestconfig.getoption("use_local_launcher") + if use_local: + libuserd = LibUserd() + else: + libuserd = LibUserd(use_docker=True, use_dev=True, data_directory=data_dir) + libuserd.initialize() + libuserd.get_all_readers() + libuserd.ansys_release_number() + libuserd.ansys_release_string() + cas_file = libuserd.download_pyansys_example("mixing_elbow.cas.h5", "pyfluent/mixing_elbow") + dat_file = libuserd.download_pyansys_example("mixing_elbow.dat.h5", "pyfluent/mixing_elbow") + r = libuserd.query_format(cas_file, dat_file) + d = r[0].read_dataset(cas_file, dat_file) + + parts = d.parts() + p = [p for p in parts if p.name == "elbow-fluid"][0] + + vars = d.variables() + v = [v for v in vars if v.name == "Static_Pressure"][0] + + p.nodes() + p.num_elements() + p.element_conn(libuserd.ElementType.HEX08) + p.variable_values(v, libuserd.ElementType.HEX08) + + libuserd.shutdown()