From cdaa53a8addbbd67caba3f359233ba73f41db5bc Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Fri, 19 Sep 2025 14:23:26 +0000 Subject: [PATCH 1/9] Add type level support for passing Path instances to download_file --- src/ansys/fluent/core/examples/downloads.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ansys/fluent/core/examples/downloads.py b/src/ansys/fluent/core/examples/downloads.py index f41527e71ccd..ca03e01d18b5 100644 --- a/src/ansys/fluent/core/examples/downloads.py +++ b/src/ansys/fluent/core/examples/downloads.py @@ -28,6 +28,7 @@ import re import shutil import zipfile +from typing import TypeAlias import ansys.fluent.core as pyfluent from ansys.fluent.core.utils.networking import check_url_exists, get_url_content @@ -71,10 +72,12 @@ def _get_file_url(file_name: str, directory: str | None = None) -> str: return f"https://github.com/ansys/example-data/raw/main/{file_name}" +PathType: TypeAlias = "os.PathLike[str | bytes] | str | bytes" + def _retrieve_file( url: str, file_name: str, - save_path: str | None = None, + save_path: PathType | None = None, return_without_path: bool | None = False, ) -> str: """Download specified file from specified URL.""" @@ -121,7 +124,7 @@ def _retrieve_file( def download_file( file_name: str, directory: str | None = None, - save_path: str | None = None, + save_path: PathType | None = None, return_without_path: bool | None = None, ) -> str: """Download specified example file from the Ansys example data repository. From 6f7fba172cd1f702c9dfaac37ff503710d4634f2 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Fri, 19 Sep 2025 10:27:40 -0400 Subject: [PATCH 2/9] Pre-emptively fix isort --- src/ansys/fluent/core/examples/downloads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/fluent/core/examples/downloads.py b/src/ansys/fluent/core/examples/downloads.py index ca03e01d18b5..8b0d84cde265 100644 --- a/src/ansys/fluent/core/examples/downloads.py +++ b/src/ansys/fluent/core/examples/downloads.py @@ -27,8 +27,8 @@ from pathlib import Path import re import shutil -import zipfile from typing import TypeAlias +import zipfile import ansys.fluent.core as pyfluent from ansys.fluent.core.utils.networking import check_url_exists, get_url_content From 7747e88e41057f8cc6df3d4b916599e434cb155b Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Sat, 20 Sep 2025 01:12:51 +0100 Subject: [PATCH 3/9] Fix black --- src/ansys/fluent/core/examples/downloads.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/fluent/core/examples/downloads.py b/src/ansys/fluent/core/examples/downloads.py index 8b0d84cde265..b17c88f63e3e 100644 --- a/src/ansys/fluent/core/examples/downloads.py +++ b/src/ansys/fluent/core/examples/downloads.py @@ -74,6 +74,7 @@ def _get_file_url(file_name: str, directory: str | None = None) -> str: PathType: TypeAlias = "os.PathLike[str | bytes] | str | bytes" + def _retrieve_file( url: str, file_name: str, From 1bb30053e7bbc0b0333f9cfa75122eac5496ba87 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Tue, 23 Sep 2025 22:04:26 +0100 Subject: [PATCH 4/9] Add typing_extensions --- pyproject.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 432c1222bb4a..9e3cdfaf95ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,7 @@ dependencies = [ "pandas>=1.1.0,<3.0.0", "pyansys-tools-report>=0.8.1", "pyyaml>=6.0", + "typing-extensions>=4.12" ] dynamic = ["version"] @@ -233,3 +234,8 @@ skips = [ "B604", "B607", ] + +[tool.basedpyright] +reportUnknownMemberType = false +reportExplicitAny = false +reportPrivateUsage = false \ No newline at end of file From ce021aa3902547c02ec868f70e3930aa830d57f7 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Tue, 23 Sep 2025 22:08:53 +0100 Subject: [PATCH 5/9] Fix inheritance for Meshing --- src/ansys/fluent/core/session_meshing.py | 43 +----------- src/ansys/fluent/core/session_meshing.pyi | 53 -------------- src/ansys/fluent/core/session_pure_meshing.py | 48 +++++++++---- .../fluent/core/session_pure_meshing.pyi | 69 ------------------- src/ansys/fluent/core/session_solver.py | 30 +++++--- src/ansys/fluent/core/session_solver.pyi | 47 ------------- 6 files changed, 56 insertions(+), 234 deletions(-) delete mode 100644 src/ansys/fluent/core/session_meshing.pyi delete mode 100644 src/ansys/fluent/core/session_pure_meshing.pyi delete mode 100644 src/ansys/fluent/core/session_solver.pyi diff --git a/src/ansys/fluent/core/session_meshing.py b/src/ansys/fluent/core/session_meshing.py index 901d5a149a15..c2989d150b4b 100644 --- a/src/ansys/fluent/core/session_meshing.py +++ b/src/ansys/fluent/core/session_meshing.py @@ -95,49 +95,12 @@ def switch_to_solver(self) -> Any: return solver_session def __getattribute__(self, item: str): - if super(Meshing, self).__getattribute__( - "_fluent_connection" - ) is None and item not in [ + if super().__getattribute__("_fluent_connection") is None and item not in [ "is_active", "_fluent_connection", ]: raise AttributeError( - f"'{__class__.__name__}' object has no attribute '{item}'" + f"'{self.__class__.__name__}' object has no attribute '{item}'" ) - return super(Meshing, self).__getattribute__(item) - - @property - def tui(self): - """Meshing TUI root.""" - return super(Meshing, self).tui - - @property - def meshing(self): - """Meshing datamodel root.""" - return super(Meshing, self).meshing - - @property - def meshing_utilities(self): - """Meshing utilities datamodel root.""" - return super(Meshing, self).meshing_utilities - - @property - def workflow(self): - """Workflow datamodel root.""" - return super(Meshing, self).workflow - - @property - def PartManagement(self): - """Part management datamodel root.""" - return super(Meshing, self).PartManagement - - @property - def PMFileManagement(self): - """Part management file management datamodel root.""" - return super(Meshing, self).PMFileManagement - - @property - def preferences(self): - """Preferences datamodel root.""" - return super(Meshing, self).preferences + return super().__getattribute__(item) diff --git a/src/ansys/fluent/core/session_meshing.pyi b/src/ansys/fluent/core/session_meshing.pyi deleted file mode 100644 index 048bdf335c5d..000000000000 --- a/src/ansys/fluent/core/session_meshing.pyi +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from ansys.fluent.core.generated.datamodel_252.meshing import Root as meshing_root -from ansys.fluent.core.generated.datamodel_252.meshing_utilities import ( - Root as meshing_utilities_root, -) -from ansys.fluent.core.generated.datamodel_252.part_management import ( - Root as partmanagement_root, -) -from ansys.fluent.core.generated.datamodel_252.pm_file_management import ( - Root as pmfilemanagement_root, -) -from ansys.fluent.core.generated.datamodel_252.preferences import ( - Root as preferences_root, -) -from ansys.fluent.core.generated.datamodel_252.workflow import Root as workflow_root -from ansys.fluent.core.generated.meshing.tui_252 import main_menu - -class Meshing: - @property - def tui(self) -> main_menu: ... - @property - def meshing(self) -> meshing_root: ... - @property - def meshing_utilities(self) -> meshing_utilities_root: ... - @property - def workflow(self) -> workflow_root: ... - @property - def PartManagement(self) -> partmanagement_root: ... - @property - def PMFileManagement(self) -> pmfilemanagement_root: ... - @property - def preferences(self) -> preferences_root: ... diff --git a/src/ansys/fluent/core/session_pure_meshing.py b/src/ansys/fluent/core/session_pure_meshing.py index fd4c9b9e249e..60f104f802ba 100644 --- a/src/ansys/fluent/core/session_pure_meshing.py +++ b/src/ansys/fluent/core/session_pure_meshing.py @@ -23,7 +23,7 @@ """Module containing class encapsulating Fluent connection.""" import functools -from typing import Any, Dict +from typing import TYPE_CHECKING, Any, Dict, cast import ansys.fluent.core as pyfluent from ansys.fluent.core.data_model_cache import DataModelCache, NameKey @@ -37,6 +37,23 @@ from ansys.fluent.core.utils.data_transfer import transfer_case from ansys.fluent.core.utils.fluent_version import FluentVersion +if TYPE_CHECKING: + from ansys.fluent.core.generated.datamodel_252.meshing import Root as meshing_root + from ansys.fluent.core.generated.datamodel_252.meshing_utilities import ( + Root as meshing_utilities_root, + ) + from ansys.fluent.core.generated.datamodel_252.part_management import ( + Root as partmanagement_root, + ) + from ansys.fluent.core.generated.datamodel_252.pm_file_management import ( + Root as pmfilemanagement_root, + ) + from ansys.fluent.core.generated.datamodel_252.preferences import ( + Root as preferences_root, + ) + from ansys.fluent.core.generated.datamodel_252.workflow import Root as workflow_root + from ansys.fluent.core.generated.meshing.tui_252 import main_menu + class PureMeshing(BaseSession): """Encapsulates a Fluent meshing session. @@ -125,26 +142,27 @@ def __init__( self._fluent_connection.register_finalizer_cb(stream.stop) @property - def tui(self): + def tui(self) -> "main_menu": """Instance of ``main_menu`` on which Fluent's SolverTUI methods can be executed.""" - return self._base_meshing.tui + return cast("main_menu", self._base_meshing.tui) @property - def meshing(self): + def meshing(self) -> "meshing_root": """Datamodel root of meshing.""" - return self._base_meshing.meshing + return cast("meshing_root", self._base_meshing.meshing) @property - def meshing_utilities(self): + def meshing_utilities(self) -> "meshing_utilities_root | None": """Datamodel root of meshing_utilities.""" if self.get_fluent_version() >= FluentVersion.v242: - return self._base_meshing.meshing_utilities + return cast("meshing_utilities_root", self._base_meshing.meshing_utilities) + return None @property - def workflow(self): + def workflow(self) -> "workflow_root": """Datamodel root of workflow.""" - return self._base_meshing.workflow + return cast("workflow_root", self._base_meshing.workflow) def watertight(self): """Get a new watertight workflow.""" @@ -184,19 +202,19 @@ def topology_based(self): return self._base_meshing.topology_based_meshing_workflow() @property - def PartManagement(self): + def PartManagement(self) -> "partmanagement_root": """Datamodel root of PartManagement.""" - return self._base_meshing.PartManagement + return cast("partmanagement_root", self._base_meshing.PartManagement) @property - def PMFileManagement(self): + def PMFileManagement(self) -> "pmfilemanagement_root": """Datamodel root of PMFileManagement.""" - return self._base_meshing.PMFileManagement + return cast("pmfilemanagement_root", self._base_meshing.PMFileManagement) @property - def preferences(self): + def preferences(self) -> "preferences_root": """Datamodel root of preferences.""" - return self._base_meshing.preferences + return cast("preferences_root", self._base_meshing.preferences) def transfer_mesh_to_solvers( self, diff --git a/src/ansys/fluent/core/session_pure_meshing.pyi b/src/ansys/fluent/core/session_pure_meshing.pyi deleted file mode 100644 index d4bfea5052c7..000000000000 --- a/src/ansys/fluent/core/session_pure_meshing.pyi +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from ansys.fluent.core.generated.datamodel_252.meshing import Root as meshing_root -from ansys.fluent.core.generated.datamodel_252.meshing_utilities import ( - Root as meshing_utilities_root, -) -from ansys.fluent.core.generated.datamodel_252.part_management import ( - Root as partmanagement_root, -) -from ansys.fluent.core.generated.datamodel_252.pm_file_management import ( - Root as pmfilemanagement_root, -) -from ansys.fluent.core.generated.datamodel_252.preferences import ( - Root as preferences_root, -) -from ansys.fluent.core.generated.datamodel_252.workflow import Root as workflow_root -from ansys.fluent.core.generated.meshing.tui_252 import main_menu - -class PureMeshing: - @property - def tui(self) -> main_menu: ... - @property - def meshing(self) -> meshing_root: ... - @property - def meshing_utilities(self) -> meshing_utilities_root: ... - @property - def workflow(self) -> workflow_root: ... - def watertight(self): ... - def fault_tolerant(self): ... - def two_dimensional_meshing(self): ... - def topology_based(self): ... - def load_workflow(self, file_path: str): ... - def create_workflow(self): ... - @property - def PartManagement(self) -> partmanagement_root: ... - @property - def PMFileManagement(self) -> pmfilemanagement_root: ... - @property - def preferences(self) -> preferences_root: ... - def transfer_mesh_to_solvers( - self, - solvers, - file_type: str = ..., - file_name_stem: str = ..., - num_files_to_try: int = ..., - clean_up_mesh_file: bool = ..., - overwrite_previous: bool = ..., - ): ... - def enable_beta_features(self): ... diff --git a/src/ansys/fluent/core/session_solver.py b/src/ansys/fluent/core/session_solver.py index 364684d0c7ae..f84828469ecf 100644 --- a/src/ansys/fluent/core/session_solver.py +++ b/src/ansys/fluent/core/session_solver.py @@ -24,12 +24,14 @@ import logging import threading -from typing import Any, Dict import warnings import weakref +from typing import TYPE_CHECKING, Any, Dict, cast from ansys.api.fluent.v0 import svar_pb2 as SvarProtoModule + import ansys.fluent.core as pyfluent +import ansys.fluent.core.solver.function.reduction as reduction_old from ansys.fluent.core.exceptions import BetaFeaturesNotEnabled from ansys.fluent.core.pyfluent_warnings import PyFluentDeprecationWarning from ansys.fluent.core.services import SchemeEval, service_creator @@ -50,7 +52,6 @@ StateT, StateType, ) -import ansys.fluent.core.solver.function.reduction as reduction_old from ansys.fluent.core.streaming_services.events_streaming import SolverEvent from ansys.fluent.core.streaming_services.monitor_streaming import MonitorsManager from ansys.fluent.core.system_coupling import SystemCoupling @@ -60,6 +61,15 @@ ) from ansys.fluent.core.workflow import ClassicWorkflow +if TYPE_CHECKING: + import ansys.fluent.core.generated.solver.settings_252 as settings_root + from ansys.fluent.core.generated.solver.tui_252 import main_menu + + from ansys.fluent.core.generated.datamodel_252.preferences import ( + Root as preferences_root, + ) + + tui_logger = logging.getLogger("pyfluent.tui") datamodel_logger = logging.getLogger("pyfluent.datamodel") @@ -181,7 +191,7 @@ def _solution_variable_data(self) -> SolutionVariableData: ) @property - def settings(self): + def settings(self) -> "settings_root.root": """Settings root handle.""" if self._settings is None: #: Root settings object. @@ -192,7 +202,7 @@ def settings(self): file_transfer_service=self._file_transfer_service, scheme_eval=self.scheme.eval, ) - return self._settings + return cast("settings_root.root", self._settings) @property def svar_data(self): @@ -246,16 +256,16 @@ def _version(self): return self._fluent_version @property - def tui(self): + def tui(self) -> "main_menu": """Instance of ``main_menu`` on which Fluent's SolverTUI methods can be executed.""" if self._tui is None: self._tui = _make_tui_module(self, "solver") - return self._tui + return cast("main_menu", self._tui) @property - def workflow(self): + def workflow(self) -> ClassicWorkflow: """Datamodel root for workflow.""" if not self._workflow: self._workflow = ClassicWorkflow( @@ -277,18 +287,18 @@ def _interrupt(cls, command): command._root.solution.run_calculation.interrupt() @property - def system_coupling(self): + def system_coupling(self) -> SystemCoupling: """System coupling object.""" if self._system_coupling is None: self._system_coupling = SystemCoupling(self) return self._system_coupling @property - def preferences(self): + def preferences(self) -> "preferences_root": """Datamodel root of preferences.""" if self._preferences is None: self._preferences = _make_datamodel_module(self, "preferences") - return self._preferences + return cast("preferences_root", self._preferences) def _start_bg_session_and_sync(self, launcher_args): """Start a background session and sync it with the current session.""" diff --git a/src/ansys/fluent/core/session_solver.pyi b/src/ansys/fluent/core/session_solver.pyi deleted file mode 100644 index a834a1fd1611..000000000000 --- a/src/ansys/fluent/core/session_solver.pyi +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from ansys.fluent.core.generated.datamodel_252.preferences import ( - Root as preferences_root, -) -from ansys.fluent.core.generated.datamodel_252.workflow import Root as workflow_root -import ansys.fluent.core.generated.solver.settings_252 as settings_root -from ansys.fluent.core.generated.solver.tui_252 import main_menu -from ansys.fluent.core.system_coupling import SystemCoupling - -class Solver: - @property - def version(self): ... - @property - def tui(self) -> main_menu: ... - @property - def workflow(self) -> workflow_root: ... - @property - def system_coupling(self) -> SystemCoupling: ... - @property - def preferences(self) -> preferences_root: ... - def read_case_lightweight(self, file_name: str): ... - def read_case(self, file_name: str): ... - def write_case(self, file_name: str): ... - @property - def settings(self) -> settings_root.root: ... - def enable_beta_features(self): ... From 6b7576ce3d0e7b9e9ec702a6a0da9a1f681bbe81 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Tue, 23 Sep 2025 22:27:50 +0100 Subject: [PATCH 6/9] Fix create_launcher allowing None --- src/ansys/fluent/core/launcher/launcher.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ansys/fluent/core/launcher/launcher.py b/src/ansys/fluent/core/launcher/launcher.py index e7b7c8754ddf..0eceb38a9fde 100644 --- a/src/ansys/fluent/core/launcher/launcher.py +++ b/src/ansys/fluent/core/launcher/launcher.py @@ -66,7 +66,7 @@ logger = logging.getLogger("pyfluent.launcher") -def create_launcher(fluent_launch_mode: LaunchMode = None, **kwargs): +def create_launcher(fluent_launch_mode: LaunchMode, **kwargs): """Use the factory function to create a launcher for supported launch modes. Parameters @@ -82,7 +82,7 @@ def create_launcher(fluent_launch_mode: LaunchMode = None, **kwargs): Session launcher. Raises ------ - DisallowedValuesError + ValueError If an unknown Fluent launch mode is passed. """ if fluent_launch_mode == LaunchMode.STANDALONE: @@ -93,6 +93,7 @@ def create_launcher(fluent_launch_mode: LaunchMode = None, **kwargs): return PIMLauncher(**kwargs) elif fluent_launch_mode == LaunchMode.SLURM: return SlurmLauncher(**kwargs) + raise ValueError(f"launch mode invalid: {fluent_launch_mode!r}") def _show_gui_to_ui_mode(old_arg_val, **kwds): From c94efa4b210a05ac3b816f0e9c31f75879b5ce21 Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Tue, 23 Sep 2025 22:33:17 +0100 Subject: [PATCH 7/9] Update launchers typing to be more specific --- .../core/launcher/container_launcher.py | 71 +-- src/ansys/fluent/core/launcher/launcher.py | 129 ++++- .../fluent/core/launcher/pim_launcher.py | 59 ++- .../fluent/core/launcher/slurm_launcher.py | 19 +- .../core/launcher/standalone_launcher.py | 130 ++--- src/ansys/fluent/core/session_utilities.py | 500 ++++++++++++++---- 6 files changed, 677 insertions(+), 231 deletions(-) diff --git a/src/ansys/fluent/core/launcher/container_launcher.py b/src/ansys/fluent/core/launcher/container_launcher.py index ad24c691c5a4..cd5fed69b529 100644 --- a/src/ansys/fluent/core/launcher/container_launcher.py +++ b/src/ansys/fluent/core/launcher/container_launcher.py @@ -39,7 +39,7 @@ import logging import os import time -from typing import Any +from typing import Any, TypedDict, Unpack from ansys.fluent.core.fluent_connection import FluentConnection from ansys.fluent.core.launcher.fluent_container import ( @@ -64,6 +64,33 @@ from ansys.fluent.core.session import _parse_server_info_file from ansys.fluent.core.utils.fluent_version import FluentVersion + +class ContainerArgsWithoutDryRun(TypedDict, total=False): + ui_mode: UIMode | str | None + graphics_driver: ( + FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None + ) + product_version: FluentVersion | str | float | int | None + dimension: Dimension | int | None + precision: Precision | str | None + processor_count: int | None + start_timeout: int + additional_arguments: str + container_dict: dict[str, Any] | None + cleanup_on_exit: bool + start_transcript: bool + py: bool | None + gpu: bool | None + start_watchdog: bool | None + file_transfer_service: Any | None + use_docker_compose: bool | None + use_podman_compose: bool | None + + +class ContainerArgs(ContainerArgsWithoutDryRun, total=False): + dry_run: bool + + _THIS_DIR = os.path.dirname(__file__) _OPTIONS_FILE = os.path.join(_THIS_DIR, "fluent_launcher_options.json") logger = logging.getLogger("pyfluent.launcher") @@ -89,27 +116,8 @@ class DockerLauncher: def __init__( self, - mode: FluentMode | str | None = None, - ui_mode: UIMode | str | None = None, - graphics_driver: ( - FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None - ) = None, - product_version: FluentVersion | str | float | int | None = None, - dimension: Dimension | int | None = None, - precision: Precision | str | None = None, - processor_count: int | None = None, - start_timeout: int = 60, - additional_arguments: str = "", - container_dict: dict | None = None, - dry_run: bool = False, - cleanup_on_exit: bool = True, - start_transcript: bool = True, - py: bool | None = None, - gpu: bool | None = None, - start_watchdog: bool | None = None, - file_transfer_service: Any | None = None, - use_docker_compose: bool | None = None, - use_podman_compose: bool | None = None, + mode: FluentMode | str, + **kwargs: Unpack[ContainerArgs], ): """ Launch a Fluent session in container mode. @@ -183,20 +191,15 @@ def __init__( In job scheduler environments (e.g., SLURM, LSF, PBS), resources and compute nodes are allocated, and core counts are queried from these environments before being passed to Fluent. """ - locals_ = locals().copy() - argvals = { - arg: locals_.get(arg) - for arg in inspect.getargvalues(inspect.currentframe()).args - } - self.argvals, self.new_session = _get_argvals_and_session(argvals) - if self.argvals["start_timeout"] is None: + self.argvals, self.new_session = _get_argvals_and_session({**kwargs, mode: mode}) + if self.argvals.get("start_timeout") is None: self.argvals["start_timeout"] = 60 - self.file_transfer_service = file_transfer_service + self.file_transfer_service = kwargs.get("file_transfer_service") if self.argvals["mode"] == FluentMode.SOLVER_ICING: self.argvals["fluent_icing"] = True - if self.argvals["container_dict"] is None: + if self.argvals.get("container_dict") is None: self.argvals["container_dict"] = {} - if self.argvals["product_version"]: + if "product_version" in self.argvals: self.argvals["container_dict"][ "image_tag" ] = f"v{FluentVersion(self.argvals['product_version']).value}" @@ -204,10 +207,12 @@ def __init__( self._args = _build_fluent_launch_args_string(**self.argvals).split() if FluentMode.is_meshing(self.argvals["mode"]): self._args.append(" -meshing") + + use_docker_compose = kwargs.get("use_docker_compose") + use_podman_compose = kwargs.get("use_podman_compose") self._compose_config = ComposeConfig(use_docker_compose, use_podman_compose) def __call__(self): - if self.argvals["dry_run"]: config_dict, *_ = configure_container_dict( self._args, diff --git a/src/ansys/fluent/core/launcher/launcher.py b/src/ansys/fluent/core/launcher/launcher.py index 0eceb38a9fde..2d84198b2300 100644 --- a/src/ansys/fluent/core/launcher/launcher.py +++ b/src/ansys/fluent/core/launcher/launcher.py @@ -29,7 +29,9 @@ import inspect import logging import os -from typing import Any, Dict +from typing import Any, Literal, TypedDict, Unpack, final, overload + +from typing_extensions import Required import ansys.fluent.core as pyfluent from ansys.fluent.core.fluent_connection import FluentConnection @@ -57,6 +59,7 @@ from ansys.fluent.core.session_meshing import Meshing from ansys.fluent.core.session_pure_meshing import PureMeshing from ansys.fluent.core.session_solver import Solver +from ansys.fluent.core.session_solver_aero import SolverAero from ansys.fluent.core.session_solver_icing import SolverIcing from ansys.fluent.core.utils.deprecate import all_deprecators from ansys.fluent.core.utils.fluent_version import FluentVersion @@ -126,6 +129,95 @@ def _version_to_dimension(old_arg_val): return None +class LaunchFluentArgs(TypedDict, total=False): + product_version: FluentVersion | str | float | int | None + dimension: Dimension | int + precision: Precision | str + processor_count: int | None + journal_file_names: None | str | list[str] + start_timeout: int + additional_arguments: str + env: dict[str, Any] | None + start_container: bool | None + container_dict: dict[str, Any] | None + cleanup_on_exit: bool + start_transcript: bool + ui_mode: UIMode | str | None + graphics_driver: ( + FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None + ) + case_file_name: str | None + case_data_file_name: str | None + lightweight_mode: bool | None + py: bool | None + gpu: bool | list[int] | None + cwd: str | None + fluent_path: str | None + topy: str | list | None + start_watchdog: bool | None + file_transfer_service: Any | None + use_docker_compose: bool + use_podman_compose: bool + + +class SlurmSchedulerOptions(TypedDict, total=False): + scheduler: Required[Literal["slurm"]] + scheduler_headnode: str + scheduler_queue: str + scheduler_account: str + + +@overload +def launch_fluent( + *, + dry_run: Literal[False] = False, + mode: Literal[FluentMode.MESHING, "meshing"], + **kwargs: Unpack[LaunchFluentArgs], +) -> Meshing: ... +@overload +def launch_fluent( + *, + dry_run: Literal[False] = False, + mode: Literal[FluentMode.PURE_MESHING, "pure_meshing"], + **kwargs: Unpack[LaunchFluentArgs], +) -> PureMeshing: ... +@overload +def launch_fluent( + *, + dry_run: Literal[False] = False, + mode: Literal[FluentMode.SOLVER, "solver"] = FluentMode.SOLVER, + **kwargs: Unpack[LaunchFluentArgs], +) -> Solver: ... +@overload +def launch_fluent( + *, + dry_run: Literal[False] = False, + mode: Literal[FluentMode.SOLVER_ICING, "solver_icing"], + **kwargs: Unpack[LaunchFluentArgs], +) -> SolverIcing: ... +@overload +def launch_fluent( + *, + dry_run: Literal[False] = False, + mode: Literal[FluentMode.SOLVER_AERO, "solver_aero"] = ..., + **kwargs: Unpack[LaunchFluentArgs], +) -> SolverAero: ... +@overload +def launch_fluent( + *, + dry_run: Literal[False] = False, + scheduler_options: SlurmSchedulerOptions, + mode: FluentMode | str = FluentMode.SOLVER, + **kwargs: Unpack[LaunchFluentArgs], +) -> SlurmFuture: ... +@overload +def launch_fluent( + *, + dry_run: Literal[True], + **kwargs: Unpack[LaunchFluentArgs], +) -> dict[str, Any]: ... + + # pylint: disable=unused-argument @all_deprecators( deprecate_arg_mappings=[ @@ -146,14 +238,15 @@ def _version_to_dimension(old_arg_val): warn_message="", ) def launch_fluent( + *, product_version: FluentVersion | str | float | int | None = None, - dimension: Dimension | int | None = None, - precision: Precision | str | None = None, + dimension: Dimension | int = Dimension.THREE, + precision: Precision | str = Precision.DOUBLE, processor_count: int | None = None, journal_file_names: None | str | list[str] = None, - start_timeout: int = None, + start_timeout: int | None = None, additional_arguments: str = "", - env: Dict[str, Any] | None = None, + env: dict[str, Any] | None = None, start_container: bool | None = None, container_dict: dict | None = None, dry_run: bool = False, @@ -166,18 +259,26 @@ def launch_fluent( case_file_name: str | None = None, case_data_file_name: str | None = None, lightweight_mode: bool | None = None, - mode: FluentMode | str | None = None, + mode: FluentMode | str = FluentMode.SOLVER, py: bool | None = None, gpu: bool | list[int] | None = None, cwd: str | None = None, fluent_path: str | None = None, topy: str | list | None = None, start_watchdog: bool | None = None, - scheduler_options: dict | None = None, + scheduler_options: SlurmSchedulerOptions | None = None, file_transfer_service: Any | None = None, - use_docker_compose: bool | None = None, - use_podman_compose: bool | None = None, -) -> Meshing | PureMeshing | Solver | SolverIcing | SlurmFuture | dict: + use_docker_compose: bool = False, + use_podman_compose: bool = False, +) -> ( + Meshing + | PureMeshing + | Solver + | SolverIcing + | SolverAero + | SlurmFuture + | dict[Any, Any] +): """Launch Fluent locally in server mode or connect to a running Fluent server instance. @@ -198,8 +299,7 @@ def launch_fluent( in which case ``Dimension.THREE`` is used. Options are either the values of the ``Dimension`` enum (``Dimension.TWO`` or ``Dimension.THREE``) or any of ``2`` and ``3``. precision : Precision or str, optional - Floating point precision. The default is ``None``, in which case ``Precision.DOUBLE`` - is used. Options are either the values of the ``Precision`` enum (``Precision.SINGLE`` + Floating point precision. Options are either the values of the ``Precision`` enum (``Precision.SINGLE`` or ``Precision.DOUBLE``) or any of ``"double"`` and ``"single"``. processor_count : int, optional Number of processors. The default is ``None``, in which case ``1`` @@ -268,7 +368,7 @@ def launch_fluent( This parameter is used only when ``case_file_name`` is provided. The default is ``False``. mode : FluentMode or str or None, optional Launch mode of Fluent to point to a specific session type. Can be a - ``FluentMode`` enum member or a string. The default value is ``None``. + ``FluentMode`` enum member or a string. The default value is ``SOLVER``. Valid string options include ``"meshing"``, ``"pure-meshing"``, and ``"solver"``. py : bool, optional @@ -370,6 +470,7 @@ def _mode_to_launcher_type(fluent_launch_mode: LaunchMode): def connect_to_fluent( + *, ip: str | None = None, port: int | None = None, cleanup_on_exit: bool = False, @@ -378,7 +479,7 @@ def connect_to_fluent( password: str | None = None, start_watchdog: bool | None = None, file_transfer_service: Any | None = None, -) -> Meshing | PureMeshing | Solver | SolverIcing: +) -> Meshing | PureMeshing | Solver | SolverIcing | SolverAero: """Connect to an existing Fluent server instance. Parameters diff --git a/src/ansys/fluent/core/launcher/pim_launcher.py b/src/ansys/fluent/core/launcher/pim_launcher.py index dd3788d7a7c4..68b2f8e6386d 100644 --- a/src/ansys/fluent/core/launcher/pim_launcher.py +++ b/src/ansys/fluent/core/launcher/pim_launcher.py @@ -38,7 +38,7 @@ import inspect import logging import os -from typing import Any, Dict +from typing import Any, Dict, TypedDict, Unpack from ansys.fluent.core.fluent_connection import FluentConnection, _get_max_c_int_limit from ansys.fluent.core.launcher.launch_options import ( @@ -58,6 +58,33 @@ from ansys.fluent.core.utils.fluent_version import FluentVersion import ansys.platform.instancemanagement as pypim + +class PIMArgsWithoutDryRun(TypedDict, total=False): + ui_mode: UIMode | str | None + graphics_driver: ( + FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None + ) + product_version: FluentVersion | str | float | int | None + dimension: Dimension | int | None + precision: Precision | str | None + processor_count: int | None + start_timeout: int + additional_arguments: str + cleanup_on_exit: bool + start_transcript: bool + gpu: bool | None + start_watchdog: bool | None + file_transfer_service: Any | None + + +class PIMArgs(PIMArgsWithoutDryRun, total=False): + dry_run: bool + + +class PIMArgsWithMode(PIMArgs, total=False): + mode: FluentMode | str | None + + _THIS_DIR = os.path.dirname(__file__) _OPTIONS_FILE = os.path.join(_THIS_DIR, "fluent_launcher_options.json") logger = logging.getLogger("pyfluent.launcher") @@ -68,23 +95,7 @@ class PIMLauncher: def __init__( self, - mode: FluentMode | str | None = None, - ui_mode: UIMode | str | None = None, - graphics_driver: ( - FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None - ) = None, - product_version: FluentVersion | str | float | int | None = None, - dimension: Dimension | int | None = None, - precision: Precision | str | None = None, - processor_count: int | None = None, - start_timeout: int = 60, - additional_arguments: str = "", - cleanup_on_exit: bool = True, - dry_run: bool | None = None, - start_transcript: bool = True, - gpu: bool | None = None, - start_watchdog: bool | None = None, - file_transfer_service: Any | None = None, + **kwargs: Unpack[PIMArgsWithMode], ): """ Launch a Fluent session in `PIM `_ mode. @@ -148,6 +159,9 @@ def __init__( In job scheduler environments (e.g., SLURM, LSF, PBS), resources and compute nodes are allocated, and core counts are queried from these environments before being passed to Fluent. """ + additional_arguments = kwargs.get("additional_arguments", "") + start_watchdog = kwargs.get("start_watchdog") + file_transfer_service = kwargs.get("file_transfer_service") if additional_arguments: logger.warning( @@ -160,14 +174,9 @@ def __init__( "'start_watchdog' argument for 'launch_fluent()' method is not supported " "when starting a remote Fluent PyPIM client." ) - locals_ = locals().copy() - argvals = { - arg: locals_.get(arg) - for arg in inspect.getargvalues(inspect.currentframe()).args - } - self.argvals, self.new_session = _get_argvals_and_session(argvals) + self.argvals, self.new_session = _get_argvals_and_session(kwargs) self.file_transfer_service = file_transfer_service - if self.argvals["start_timeout"] is None: + if self.argvals.get("start_timeout") is None: self.argvals["start_timeout"] = 60 def __call__(self): diff --git a/src/ansys/fluent/core/launcher/slurm_launcher.py b/src/ansys/fluent/core/launcher/slurm_launcher.py index 75ae43556bf7..6f0443d3a567 100644 --- a/src/ansys/fluent/core/launcher/slurm_launcher.py +++ b/src/ansys/fluent/core/launcher/slurm_launcher.py @@ -68,7 +68,9 @@ import shutil import subprocess import time -from typing import Any, Callable, Dict +from typing import Any, Callable, Dict, Generic + +from typing_extensions import TypeVar from ansys.fluent.core.exceptions import InvalidArgument from ansys.fluent.core.launcher.launch_options import ( @@ -161,7 +163,14 @@ def cancel(job_id: int) -> None: subprocess.run(["scancel", f"{job_id}"]) -class SlurmFuture: +SessionT = TypeVar( + "SessionT", + bound="Meshing | PureMeshing | Solver | SolverIcing", + default="Meshing | PureMeshing | Solver | SolverIcing", +) + + +class SlurmFuture(Generic[SessionT]): """Encapsulates asynchronous launch of Fluent within a Slurm environment. The interface is similar to Python's @@ -221,9 +230,7 @@ def done(self) -> bool: finished running, otherwise ``False``.""" return self._get_state() in ["", "CANCELLED", "COMPLETED"] - def result( - self, timeout: int = None - ) -> Meshing | PureMeshing | Solver | SolverIcing: + def result(self, timeout: int | None = None) -> SessionT: """Return the session instance corresponding to the Fluent launch. If Fluent hasn't yet launched, then this method will wait up to timeout seconds. If Fluent hasn't launched in timeout seconds, then a TimeoutError will be raised. If @@ -246,7 +253,7 @@ def result( """ return self._future.result(timeout) - def exception(self, timeout: int = None) -> Exception: + def exception(self, timeout: int | None = None) -> Exception: """Return the exception raised by the Fluent launch. If Fluent hasn't yet launched, then this method will wait up to timeout seconds. If Fluent hasn't launched in timeout seconds, then a TimeoutError will be raised. If timeout is diff --git a/src/ansys/fluent/core/launcher/standalone_launcher.py b/src/ansys/fluent/core/launcher/standalone_launcher.py index 10e2fd4573e7..07775ea9b8df 100644 --- a/src/ansys/fluent/core/launcher/standalone_launcher.py +++ b/src/ansys/fluent/core/launcher/standalone_launcher.py @@ -40,7 +40,7 @@ import os from pathlib import Path import subprocess -from typing import Any, Dict +from typing import Any, TypedDict, Unpack from ansys.fluent.core.launcher.error_handler import ( LaunchFluentError, @@ -56,6 +56,7 @@ _get_argvals_and_session, _get_standalone_launch_fluent_version, ) +from ansys.fluent.core.launcher.launcher import LaunchFluentArgs from ansys.fluent.core.launcher.launcher_utils import ( _await_fluent_launch, _build_journal_argument, @@ -69,8 +70,43 @@ _get_server_info_file_names, ) import ansys.fluent.core.launcher.watchdog as watchdog +from ansys.fluent.core.session import BaseSession from ansys.fluent.core.utils.fluent_version import FluentVersion + +class StandaloneArgsWithoutDryRun(TypedDict, total=False): + """TypedDict for standalone launcher arguments without dry_run.""" + + product_version: FluentVersion | str | float | int | None + dimension: Dimension | int + precision: Precision | str + processor_count: int | None + journal_file_names: None | str | list[str] + start_timeout: int + additional_arguments: str + env: dict[str, Any] | None + cleanup_on_exit: bool + start_transcript: bool + ui_mode: UIMode | str | None + graphics_driver: ( + FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None + ) + case_file_name: str | None + case_data_file_name: str | None + lightweight_mode: bool | None + py: bool | None + gpu: bool | list[int] | None + cwd: str | None + fluent_path: str | None + topy: str | list[Any] | None + start_watchdog: bool | None + file_transfer_service: Any | None + + +class StandaloneArgs(StandaloneArgsWithoutDryRun, total=False): + dry_run: bool | None + + logger = logging.getLogger("pyfluent.launcher") @@ -79,32 +115,10 @@ class StandaloneLauncher: def __init__( self, - mode: FluentMode | str | None = None, - ui_mode: UIMode | str | None = None, - graphics_driver: ( - FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str - ) = None, - product_version: FluentVersion | str | float | int | None = None, - dimension: Dimension | int | None = None, - precision: Precision | str | None = None, - processor_count: int | None = None, - journal_file_names: None | str | list[str] = None, - start_timeout: int = 60, - additional_arguments: str = "", - env: Dict[str, Any] | None = None, - cleanup_on_exit: bool = True, + *, + mode: FluentMode, dry_run: bool = False, - start_transcript: bool = True, - case_file_name: str | None = None, - case_data_file_name: str | None = None, - lightweight_mode: bool | None = None, - py: bool | None = None, - gpu: bool | None = None, - cwd: str | None = None, - fluent_path: str | None = None, - topy: str | list | None = None, - start_watchdog: bool | None = None, - file_transfer_service: Any | None = None, + **kwargs: Unpack[LaunchFluentArgs], ): """ Launch a Fluent session in standalone mode. @@ -185,20 +199,14 @@ def __init__( and core counts are queried from these environments before being passed to Fluent. """ import ansys.fluent.core as pyfluent - - locals_ = locals().copy() - argvals = { - arg: locals_.get(arg) - for arg in inspect.getargvalues(inspect.currentframe()).args - } - self.argvals, self.new_session = _get_argvals_and_session(argvals) - self.file_transfer_service = file_transfer_service + self.argvals, self.new_session = _get_argvals_and_session(kwargs) + self.file_transfer_service = kwargs.get("file_transfer_service") if pyfluent.config.show_fluent_gui: - ui_mode = UIMode.GUI - self.argvals["ui_mode"] = UIMode(ui_mode) - if self.argvals["start_timeout"] is None: + kwargs["ui_mode"] = UIMode.GUI + self.argvals["ui_mode"] = UIMode(kwargs.get("ui_mode")) + if self.argvals.get("start_timeout") is None: self.argvals["start_timeout"] = 60 - if self.argvals["lightweight_mode"] is None: + if self.argvals.get("lightweight_mode") is None: self.argvals["lightweight_mode"] = False fluent_version = _get_standalone_launch_fluent_version(self.argvals) if fluent_version: @@ -207,7 +215,7 @@ def __init__( if ( fluent_version and fluent_version >= FluentVersion.v251 - and self.argvals["py"] is None + and self.argvals.get("py") is None ): self.argvals["py"] = True @@ -225,12 +233,12 @@ def __init__( self._sifile_last_mtime = Path(self._server_info_file_name).stat().st_mtime self._kwargs = _get_subprocess_kwargs_for_fluent( - self.argvals["env"], self.argvals + self.argvals.get("env", {}), self.argvals ) - if self.argvals["cwd"]: - self._kwargs.update(cwd=self.argvals["cwd"]) + if "cwd" in self.argvals: + self._kwargs.update(cwd=self.argvals.get("cwd")) self._launch_string += _build_journal_argument( - self.argvals["topy"], self.argvals["journal_file_names"] + self.argvals.get("topy", []), self.argvals.get("journal_file_names") ) if is_windows(): @@ -243,14 +251,14 @@ def __init__( # Using 'start.exe' is better; otherwise Fluent is more susceptible to bad termination attempts. self._launch_cmd = 'start "" ' + self._launch_string else: - if self.argvals["ui_mode"] not in [UIMode.GUI, UIMode.HIDDEN_GUI]: + if self.argvals.get("ui_mode") not in [UIMode.GUI, UIMode.HIDDEN_GUI]: # Using nohup to hide Fluent output from the current terminal self._launch_cmd = "nohup " + self._launch_string + " &" else: self._launch_cmd = self._launch_string - def __call__(self): - if self.argvals["dry_run"]: + def __call__(self) -> tuple[str, str] | BaseSession: + if self.argvals.get("dry_run"): print(f"Fluent launch string: {self._launch_string}") return self._launch_string, self._server_info_file_name try: @@ -261,7 +269,7 @@ def __call__(self): try: _await_fluent_launch( self._server_info_file_name, - self.argvals["start_timeout"], + self.argvals.get("start_timeout", 60), self._sifile_last_mtime, ) except TimeoutError as ex: @@ -275,7 +283,7 @@ def __call__(self): process = subprocess.Popen(launch_cmd, **self._kwargs) _await_fluent_launch( self._server_info_file_name, - self.argvals["start_timeout"], + self.argvals.get("start_timeout", 60), self._sifile_last_mtime, ) else: @@ -284,36 +292,36 @@ def __call__(self): session = self.new_session._create_from_server_info_file( server_info_file_name=self._server_info_file_name, file_transfer_service=self.file_transfer_service, - cleanup_on_exit=self.argvals["cleanup_on_exit"], - start_transcript=self.argvals["start_transcript"], + cleanup_on_exit=self.argvals.get("cleanup_on_exit"), + start_transcript=self.argvals.get("start_transcript"), launcher_args=self.argvals, inside_container=False, ) session._process = process start_watchdog = _confirm_watchdog_start( - self.argvals["start_watchdog"], - self.argvals["cleanup_on_exit"], + self.argvals.get("start_watchdog"), + self.argvals.get("cleanup_on_exit"), session._fluent_connection, ) if start_watchdog: logger.info("Launching Watchdog for local Fluent client...") ip, port, password = _get_server_info(self._server_info_file_name) watchdog.launch(os.getpid(), port, password, ip) - if self.argvals["case_file_name"]: - if FluentMode.is_meshing(self.argvals["mode"]): - session.tui.file.read_case(self.argvals["case_file_name"]) - elif self.argvals["lightweight_mode"]: - session.read_case_lightweight(self.argvals["case_file_name"]) + if self.argvals.get("case_file_name"): + if FluentMode.is_meshing(self.argvals.get("mode")): + session.tui.file.read_case(self.argvals.get("case_file_name")) + elif self.argvals.get("lightweight_mode"): + session.read_case_lightweight(self.argvals.get("case_file_name")) else: session.file.read( file_type="case", - file_name=self.argvals["case_file_name"], + file_name=self.argvals.get("case_file_name"), ) - if self.argvals["case_data_file_name"]: - if not FluentMode.is_meshing(self.argvals["mode"]): + if self.argvals.get("case_data_file_name"): + if not FluentMode.is_meshing(self.argvals.get("mode")): session.file.read( file_type="case-data", - file_name=self.argvals["case_data_file_name"], + file_name=self.argvals.get("case_data_file_name"), ) else: raise RuntimeError( diff --git a/src/ansys/fluent/core/session_utilities.py b/src/ansys/fluent/core/session_utilities.py index e3a16c654ee0..d12dd5530ae6 100644 --- a/src/ansys/fluent/core/session_utilities.py +++ b/src/ansys/fluent/core/session_utilities.py @@ -22,21 +22,32 @@ """Session utilities.""" -from typing import Any, Dict - -import ansys.fluent.core as pyfluent -from ansys.fluent.core.launcher.container_launcher import DockerLauncher +from typing import TYPE_CHECKING, Any, Literal, Unpack, overload + +from ansys.fluent.core import ( + session_meshing, + session_pure_meshing, + session_solver, + session_solver_aero, + session_solver_icing, +) +from ansys.fluent.core.launcher.container_launcher import ( + ContainerArgsWithoutDryRun, + DockerLauncher, +) from ansys.fluent.core.launcher.launch_options import ( - Dimension, - FluentLinuxGraphicsDriver, FluentMode, - FluentWindowsGraphicsDriver, - Precision, - UIMode, ) -from ansys.fluent.core.launcher.pim_launcher import PIMLauncher -from ansys.fluent.core.launcher.standalone_launcher import StandaloneLauncher -from ansys.fluent.core.utils.fluent_version import FluentVersion +from ansys.fluent.core.launcher.launcher import LaunchFluentArgs, connect_to_fluent +from ansys.fluent.core.launcher.pim_launcher import ( + PIMArgsWithoutDryRun, + PIMLauncher, +) +from ansys.fluent.core.launcher.standalone_launcher import ( + StandaloneArgsWithoutDryRun, + StandaloneLauncher, +) +from ansys.fluent.core.session import BaseSession class SessionBase: @@ -47,7 +58,7 @@ class SessionBase: or `from_pim` functions to create a session. """ - _session_mode = { + _session_mode: dict[str, FluentMode] = { "Meshing": FluentMode.MESHING, "PureMeshing": FluentMode.PURE_MESHING, "PrePost": FluentMode.PRE_POST, @@ -56,35 +67,30 @@ class SessionBase: "SolverIcing": FluentMode.SOLVER_ICING, } + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[StandaloneArgsWithoutDryRun], + ) -> BaseSession: ... + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[StandaloneArgsWithoutDryRun], + ) -> tuple[str, str]: ... + @classmethod def from_install( cls, - ui_mode: UIMode | str | None = None, - graphics_driver: ( - FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str - ) = None, - product_version: FluentVersion | str | float | int | None = None, - dimension: Dimension | int | None = None, - precision: Precision | str | None = None, - processor_count: int | None = None, - journal_file_names: None | str | list[str] = None, - start_timeout: int = 60, - additional_arguments: str = "", - env: Dict[str, Any] = {}, # noqa: B006 - cleanup_on_exit: bool = True, + *, dry_run: bool = False, - start_transcript: bool = True, - case_file_name: str | None = None, - case_data_file_name: str | None = None, - lightweight_mode: bool | None = None, - py: bool | None = None, - gpu: bool | None = None, - cwd: str | None = None, - fluent_path: str | None = None, - topy: str | list | None = None, - start_watchdog: bool | None = None, - file_transfer_service: Any | None = None, - ): + **kwargs: Unpack[StandaloneArgsWithoutDryRun], + ) -> BaseSession | tuple[str, str]: """ Launch a Fluent session in standalone mode. @@ -161,34 +167,35 @@ def from_install( In job scheduler environments (e.g., SLURM, LSF, PBS), resources and compute nodes are allocated, and core counts are queried from these environments before being passed to Fluent. """ - mode = cls._session_mode[cls.__name__] - argvals = locals().copy() - argvals.pop("cls", None) # Remove the class reference from the arguments - launcher = StandaloneLauncher(**argvals) + launcher = StandaloneLauncher( + **kwargs, dry_run=dry_run, mode=cls._session_mode[cls.__name__] + ) return launcher() + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> BaseSession: ... + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> dict[str, Any]: ... + @classmethod def from_container( cls, - ui_mode: UIMode | str | None = None, - graphics_driver: ( - FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None - ) = None, - product_version: FluentVersion | str | float | int | None = None, - dimension: Dimension | int | None = None, - precision: Precision | str | None = None, - processor_count: int | None = None, - start_timeout: int = 60, - additional_arguments: str = "", - container_dict: dict | None = None, + *, dry_run: bool = False, - cleanup_on_exit: bool = True, - start_transcript: bool = True, - py: bool | None = None, - gpu: bool | None = None, - start_watchdog: bool | None = None, - file_transfer_service: Any | None = None, - ): + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> BaseSession | dict[str, Any]: """ Launch a Fluent session in container mode. @@ -255,32 +262,35 @@ def from_container( In job scheduler environments (e.g., SLURM, LSF, PBS), resources and compute nodes are allocated, and core counts are queried from these environments before being passed to Fluent. """ - mode = cls._session_mode[cls.__name__] - argvals = locals().copy() - argvals.pop("cls", None) - launcher = DockerLauncher(**argvals) + launcher = DockerLauncher( + **kwargs, dry_run=dry_run, mode=cls._session_mode[cls.__name__] + ) return launcher() + @overload @classmethod def from_pim( cls, - ui_mode: UIMode | str | None = None, - graphics_driver: ( - FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None - ) = None, - product_version: FluentVersion | str | float | int | None = None, - dimension: Dimension | int | None = None, - precision: Precision | str | None = None, - processor_count: int | None = None, - start_timeout: int = 60, - additional_arguments: str = "", - cleanup_on_exit: bool = True, - dry_run: bool | None = None, - start_transcript: bool = True, - gpu: bool | None = None, - start_watchdog: bool | None = None, - file_transfer_service: Any | None = None, - ): + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> BaseSession: ... + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> dict[str, Any]: ... + + @classmethod + def from_pim( + cls, + *, + dry_run: bool = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> BaseSession | dict[str, Any]: """ Launch a Fluent session in `PIM `_ mode. @@ -342,10 +352,10 @@ def from_pim( In job scheduler environments (e.g., SLURM, LSF, PBS), resources and compute nodes are allocated, and core counts are queried from these environments before being passed to Fluent. """ - mode = cls._session_mode[cls.__name__] - argvals = locals().copy() - argvals.pop("cls", None) - launcher = PIMLauncher(**argvals) + kwargs_with_mode = dict(kwargs) + kwargs_with_mode["mode"] = cls._session_mode[cls.__name__] + kwargs_with_mode["dry_run"] = dry_run + launcher = PIMLauncher(**kwargs_with_mode) return launcher() @classmethod @@ -382,7 +392,7 @@ def from_connection( TypeError If the session type does not match the expected session type. """ - session = pyfluent.connect_to_fluent( + session = connect_to_fluent( ip=ip, port=port, server_info_file_name=server_info_file_name, @@ -403,34 +413,340 @@ def from_connection( class Meshing(SessionBase): """Encapsulates a Fluent server for meshing session connection.""" - pass + if TYPE_CHECKING: + + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[LaunchFluentArgs], + ) -> session_meshing.Meshing: ... + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[LaunchFluentArgs], + ) -> tuple[str, str]: ... + + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> session_meshing.Meshing: ... + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> dict[str, Any]: ... + + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> session_meshing.Meshing: ... + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> dict[str, Any]: ... class PureMeshing(SessionBase): """Encapsulates a Fluent server for pure meshing session connection.""" - pass + if TYPE_CHECKING: + + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[LaunchFluentArgs], + ) -> session_pure_meshing.PureMeshing: ... + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[LaunchFluentArgs], + ) -> tuple[str, str]: ... + + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> session_pure_meshing.PureMeshing: ... + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> dict[str, Any]: ... + + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> session_pure_meshing.PureMeshing: ... + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> dict[str, Any]: ... class PrePost(SessionBase): """Encapsulates a Fluent server for pre-post session connection.""" - pass + if TYPE_CHECKING: + + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[LaunchFluentArgs], + ) -> session_solver.Solver: ... + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[LaunchFluentArgs], + ) -> tuple[str, str]: ... + + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> session_solver.Solver: ... + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> dict[str, Any]: ... + + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> session_solver.Solver: ... + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> dict[str, Any]: ... class Solver(SessionBase): """Encapsulates a Fluent server for solver session connection.""" - pass + if TYPE_CHECKING: + + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[LaunchFluentArgs], + ) -> session_solver.Solver: ... + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[LaunchFluentArgs], + ) -> tuple[str, str]: ... + + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> session_solver.Solver: ... + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> dict[str, Any]: ... + + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> session_solver.Solver: ... + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> dict[str, Any]: ... class SolverAero(SessionBase): """Encapsulates a Fluent server for solver aero session connection.""" - pass + if TYPE_CHECKING: + + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[LaunchFluentArgs], + ) -> session_solver_aero.SolverAero: ... + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[LaunchFluentArgs], + ) -> tuple[str, str]: ... + + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> session_solver_aero.SolverAero: ... + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> dict[str, Any]: ... + + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> session_solver_aero.SolverAero: ... + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> dict[str, Any]: ... class SolverIcing(SessionBase): """Encapsulates a Fluent server for solver icing session connection.""" - pass + if TYPE_CHECKING: + + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[LaunchFluentArgs], + ) -> session_solver_icing.SolverIcing: ... + @overload + @classmethod + def from_install( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[LaunchFluentArgs], + ) -> tuple[str, str]: ... + + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> session_solver_icing.SolverIcing: ... + @overload + @classmethod + def from_container( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[ContainerArgsWithoutDryRun], + ) -> dict[str, Any]: ... + + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[False] = False, + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> session_solver_icing.SolverIcing: ... + @overload + @classmethod + def from_pim( + cls, + *, + dry_run: Literal[True], + **kwargs: Unpack[PIMArgsWithoutDryRun], + ) -> dict[str, Any]: ... From a0faf05927685db012e469a47d5d4a7e5fe3d76a Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Wed, 24 Sep 2025 09:43:04 +0100 Subject: [PATCH 8/9] Fix ci --- src/ansys/fluent/core/launcher/container_launcher.py | 8 ++++++-- src/ansys/fluent/core/launcher/launcher.py | 4 ++-- src/ansys/fluent/core/launcher/pim_launcher.py | 4 +++- src/ansys/fluent/core/launcher/standalone_launcher.py | 5 ++++- src/ansys/fluent/core/session_solver.py | 10 ++++------ src/ansys/fluent/core/session_utilities.py | 4 +++- 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/ansys/fluent/core/launcher/container_launcher.py b/src/ansys/fluent/core/launcher/container_launcher.py index cd5fed69b529..bd6609780c6c 100644 --- a/src/ansys/fluent/core/launcher/container_launcher.py +++ b/src/ansys/fluent/core/launcher/container_launcher.py @@ -39,7 +39,9 @@ import logging import os import time -from typing import Any, TypedDict, Unpack +from typing import Any, TypedDict + +from typing_extensions import Unpack from ansys.fluent.core.fluent_connection import FluentConnection from ansys.fluent.core.launcher.fluent_container import ( @@ -191,7 +193,9 @@ def __init__( In job scheduler environments (e.g., SLURM, LSF, PBS), resources and compute nodes are allocated, and core counts are queried from these environments before being passed to Fluent. """ - self.argvals, self.new_session = _get_argvals_and_session({**kwargs, mode: mode}) + self.argvals, self.new_session = _get_argvals_and_session( + {**kwargs, mode: mode} + ) if self.argvals.get("start_timeout") is None: self.argvals["start_timeout"] = 60 self.file_transfer_service = kwargs.get("file_transfer_service") diff --git a/src/ansys/fluent/core/launcher/launcher.py b/src/ansys/fluent/core/launcher/launcher.py index 2d84198b2300..d3b902e925a9 100644 --- a/src/ansys/fluent/core/launcher/launcher.py +++ b/src/ansys/fluent/core/launcher/launcher.py @@ -29,9 +29,9 @@ import inspect import logging import os -from typing import Any, Literal, TypedDict, Unpack, final, overload +from typing import Any, Literal, TypedDict, overload -from typing_extensions import Required +from typing_extensions import Required, Unpack import ansys.fluent.core as pyfluent from ansys.fluent.core.fluent_connection import FluentConnection diff --git a/src/ansys/fluent/core/launcher/pim_launcher.py b/src/ansys/fluent/core/launcher/pim_launcher.py index 68b2f8e6386d..f927ec3d9857 100644 --- a/src/ansys/fluent/core/launcher/pim_launcher.py +++ b/src/ansys/fluent/core/launcher/pim_launcher.py @@ -38,7 +38,9 @@ import inspect import logging import os -from typing import Any, Dict, TypedDict, Unpack +from typing import Any, Dict, TypedDict + +from typing_extensions import Unpack from ansys.fluent.core.fluent_connection import FluentConnection, _get_max_c_int_limit from ansys.fluent.core.launcher.launch_options import ( diff --git a/src/ansys/fluent/core/launcher/standalone_launcher.py b/src/ansys/fluent/core/launcher/standalone_launcher.py index 07775ea9b8df..ef6c10a0d805 100644 --- a/src/ansys/fluent/core/launcher/standalone_launcher.py +++ b/src/ansys/fluent/core/launcher/standalone_launcher.py @@ -40,7 +40,9 @@ import os from pathlib import Path import subprocess -from typing import Any, TypedDict, Unpack +from typing import Any, TypedDict + +from typing_extensions import Unpack from ansys.fluent.core.launcher.error_handler import ( LaunchFluentError, @@ -199,6 +201,7 @@ def __init__( and core counts are queried from these environments before being passed to Fluent. """ import ansys.fluent.core as pyfluent + self.argvals, self.new_session = _get_argvals_and_session(kwargs) self.file_transfer_service = kwargs.get("file_transfer_service") if pyfluent.config.show_fluent_gui: diff --git a/src/ansys/fluent/core/session_solver.py b/src/ansys/fluent/core/session_solver.py index f84828469ecf..db2db698fcc3 100644 --- a/src/ansys/fluent/core/session_solver.py +++ b/src/ansys/fluent/core/session_solver.py @@ -24,14 +24,12 @@ import logging import threading +from typing import TYPE_CHECKING, Any, Dict, cast import warnings import weakref -from typing import TYPE_CHECKING, Any, Dict, cast from ansys.api.fluent.v0 import svar_pb2 as SvarProtoModule - import ansys.fluent.core as pyfluent -import ansys.fluent.core.solver.function.reduction as reduction_old from ansys.fluent.core.exceptions import BetaFeaturesNotEnabled from ansys.fluent.core.pyfluent_warnings import PyFluentDeprecationWarning from ansys.fluent.core.services import SchemeEval, service_creator @@ -52,6 +50,7 @@ StateT, StateType, ) +import ansys.fluent.core.solver.function.reduction as reduction_old from ansys.fluent.core.streaming_services.events_streaming import SolverEvent from ansys.fluent.core.streaming_services.monitor_streaming import MonitorsManager from ansys.fluent.core.system_coupling import SystemCoupling @@ -62,12 +61,11 @@ from ansys.fluent.core.workflow import ClassicWorkflow if TYPE_CHECKING: - import ansys.fluent.core.generated.solver.settings_252 as settings_root - from ansys.fluent.core.generated.solver.tui_252 import main_menu - from ansys.fluent.core.generated.datamodel_252.preferences import ( Root as preferences_root, ) + import ansys.fluent.core.generated.solver.settings_252 as settings_root + from ansys.fluent.core.generated.solver.tui_252 import main_menu tui_logger = logging.getLogger("pyfluent.tui") diff --git a/src/ansys/fluent/core/session_utilities.py b/src/ansys/fluent/core/session_utilities.py index d12dd5530ae6..1d839b8511c9 100644 --- a/src/ansys/fluent/core/session_utilities.py +++ b/src/ansys/fluent/core/session_utilities.py @@ -22,7 +22,9 @@ """Session utilities.""" -from typing import TYPE_CHECKING, Any, Literal, Unpack, overload +from typing import TYPE_CHECKING, Any, Literal, overload + +from typing_extensions import Unpack from ansys.fluent.core import ( session_meshing, From f5f72cea07879ed1842cb24a58e59fc51338451e Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Wed, 24 Sep 2025 10:33:28 +0100 Subject: [PATCH 9/9] Fix ci again --- .../core/launcher/container_launcher.py | 9 ++++--- src/ansys/fluent/core/launcher/launcher.py | 20 ++++++++++++-- .../fluent/core/launcher/pim_launcher.py | 11 +++++--- .../core/launcher/standalone_launcher.py | 11 ++++---- src/ansys/fluent/core/parametric.py | 2 +- src/ansys/fluent/core/session_utilities.py | 27 ++++++++++++++++--- 6 files changed, 62 insertions(+), 18 deletions(-) diff --git a/src/ansys/fluent/core/launcher/container_launcher.py b/src/ansys/fluent/core/launcher/container_launcher.py index bd6609780c6c..127966071183 100644 --- a/src/ansys/fluent/core/launcher/container_launcher.py +++ b/src/ansys/fluent/core/launcher/container_launcher.py @@ -35,7 +35,6 @@ >>> container_solver_session = container_solver_launcher() """ -import inspect import logging import os import time @@ -67,7 +66,9 @@ from ansys.fluent.core.utils.fluent_version import FluentVersion -class ContainerArgsWithoutDryRun(TypedDict, total=False): +class ContainerArgsWithoutDryRun( + TypedDict, total=False +): # pylint: disable=missing-class-docstring ui_mode: UIMode | str | None graphics_driver: ( FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None @@ -89,7 +90,9 @@ class ContainerArgsWithoutDryRun(TypedDict, total=False): use_podman_compose: bool | None -class ContainerArgs(ContainerArgsWithoutDryRun, total=False): +class ContainerArgs( + ContainerArgsWithoutDryRun, total=False +): # pylint: disable=missing-class-docstring dry_run: bool diff --git a/src/ansys/fluent/core/launcher/launcher.py b/src/ansys/fluent/core/launcher/launcher.py index d3b902e925a9..6d4acd67c5a5 100644 --- a/src/ansys/fluent/core/launcher/launcher.py +++ b/src/ansys/fluent/core/launcher/launcher.py @@ -129,7 +129,9 @@ def _version_to_dimension(old_arg_val): return None -class LaunchFluentArgs(TypedDict, total=False): +class LaunchFluentArgs( + TypedDict, total=False +): # pylint: disable=missing-class-docstring product_version: FluentVersion | str | float | int | None dimension: Dimension | int precision: Precision | str @@ -160,7 +162,9 @@ class LaunchFluentArgs(TypedDict, total=False): use_podman_compose: bool -class SlurmSchedulerOptions(TypedDict, total=False): +class SlurmSchedulerOptions( + TypedDict, total=False +): # pylint: disable=missing-class-docstring scheduler: Required[Literal["slurm"]] scheduler_headnode: str scheduler_queue: str @@ -174,6 +178,8 @@ def launch_fluent( mode: Literal[FluentMode.MESHING, "meshing"], **kwargs: Unpack[LaunchFluentArgs], ) -> Meshing: ... + + @overload def launch_fluent( *, @@ -181,6 +187,8 @@ def launch_fluent( mode: Literal[FluentMode.PURE_MESHING, "pure_meshing"], **kwargs: Unpack[LaunchFluentArgs], ) -> PureMeshing: ... + + @overload def launch_fluent( *, @@ -188,6 +196,8 @@ def launch_fluent( mode: Literal[FluentMode.SOLVER, "solver"] = FluentMode.SOLVER, **kwargs: Unpack[LaunchFluentArgs], ) -> Solver: ... + + @overload def launch_fluent( *, @@ -195,6 +205,8 @@ def launch_fluent( mode: Literal[FluentMode.SOLVER_ICING, "solver_icing"], **kwargs: Unpack[LaunchFluentArgs], ) -> SolverIcing: ... + + @overload def launch_fluent( *, @@ -202,6 +214,8 @@ def launch_fluent( mode: Literal[FluentMode.SOLVER_AERO, "solver_aero"] = ..., **kwargs: Unpack[LaunchFluentArgs], ) -> SolverAero: ... + + @overload def launch_fluent( *, @@ -210,6 +224,8 @@ def launch_fluent( mode: FluentMode | str = FluentMode.SOLVER, **kwargs: Unpack[LaunchFluentArgs], ) -> SlurmFuture: ... + + @overload def launch_fluent( *, diff --git a/src/ansys/fluent/core/launcher/pim_launcher.py b/src/ansys/fluent/core/launcher/pim_launcher.py index f927ec3d9857..5315f9fe8e6e 100644 --- a/src/ansys/fluent/core/launcher/pim_launcher.py +++ b/src/ansys/fluent/core/launcher/pim_launcher.py @@ -35,7 +35,6 @@ >>> pim_solver_session = pim_solver_launcher() """ -import inspect import logging import os from typing import Any, Dict, TypedDict @@ -61,7 +60,9 @@ import ansys.platform.instancemanagement as pypim -class PIMArgsWithoutDryRun(TypedDict, total=False): +class PIMArgsWithoutDryRun( + TypedDict, total=False +): # pylint: disable=missing-class-docstring ui_mode: UIMode | str | None graphics_driver: ( FluentWindowsGraphicsDriver | FluentLinuxGraphicsDriver | str | None @@ -79,11 +80,13 @@ class PIMArgsWithoutDryRun(TypedDict, total=False): file_transfer_service: Any | None -class PIMArgs(PIMArgsWithoutDryRun, total=False): +class PIMArgs( + PIMArgsWithoutDryRun, total=False +): # pylint: disable=missing-class-docstring dry_run: bool -class PIMArgsWithMode(PIMArgs, total=False): +class PIMArgsWithMode(PIMArgs, total=False): # pylint: disable=missing-class-docstring mode: FluentMode | str | None diff --git a/src/ansys/fluent/core/launcher/standalone_launcher.py b/src/ansys/fluent/core/launcher/standalone_launcher.py index ef6c10a0d805..7730853bb9e8 100644 --- a/src/ansys/fluent/core/launcher/standalone_launcher.py +++ b/src/ansys/fluent/core/launcher/standalone_launcher.py @@ -35,7 +35,6 @@ >>> standalone_solver_session = standalone_solver_launcher() """ -import inspect import logging import os from pathlib import Path @@ -76,9 +75,9 @@ from ansys.fluent.core.utils.fluent_version import FluentVersion -class StandaloneArgsWithoutDryRun(TypedDict, total=False): - """TypedDict for standalone launcher arguments without dry_run.""" - +class StandaloneArgsWithoutDryRun( + TypedDict, total=False +): # pylint: disable=missing-class-docstring product_version: FluentVersion | str | float | int | None dimension: Dimension | int precision: Precision | str @@ -105,7 +104,9 @@ class StandaloneArgsWithoutDryRun(TypedDict, total=False): file_transfer_service: Any | None -class StandaloneArgs(StandaloneArgsWithoutDryRun, total=False): +class StandaloneArgs( + StandaloneArgsWithoutDryRun, total=False +): # pylint: disable=missing-class-docstring dry_run: bool | None diff --git a/src/ansys/fluent/core/parametric.py b/src/ansys/fluent/core/parametric.py index fb5c9ae19e79..a13f38837745 100644 --- a/src/ansys/fluent/core/parametric.py +++ b/src/ansys/fluent/core/parametric.py @@ -60,7 +60,7 @@ def convert_design_point_parameter_units( - value: Dict[str, float | int | str] + value: Dict[str, float | int | str], ) -> Dict[str, float | int]: """Convert design point parameter units.""" diff --git a/src/ansys/fluent/core/session_utilities.py b/src/ansys/fluent/core/session_utilities.py index 1d839b8511c9..cb286b0c328f 100644 --- a/src/ansys/fluent/core/session_utilities.py +++ b/src/ansys/fluent/core/session_utilities.py @@ -77,6 +77,7 @@ def from_install( dry_run: Literal[False] = False, **kwargs: Unpack[StandaloneArgsWithoutDryRun], ) -> BaseSession: ... + @overload @classmethod def from_install( @@ -87,7 +88,7 @@ def from_install( ) -> tuple[str, str]: ... @classmethod - def from_install( + def from_install( # pylint: disable=missing-param-doc cls, *, dry_run: bool = False, @@ -182,6 +183,7 @@ def from_container( dry_run: Literal[False] = False, **kwargs: Unpack[ContainerArgsWithoutDryRun], ) -> BaseSession: ... + @overload @classmethod def from_container( @@ -192,7 +194,7 @@ def from_container( ) -> dict[str, Any]: ... @classmethod - def from_container( + def from_container( # pylint: disable=missing-param-doc cls, *, dry_run: bool = False, @@ -277,6 +279,7 @@ def from_pim( dry_run: Literal[False] = False, **kwargs: Unpack[PIMArgsWithoutDryRun], ) -> BaseSession: ... + @overload @classmethod def from_pim( @@ -287,7 +290,7 @@ def from_pim( ) -> dict[str, Any]: ... @classmethod - def from_pim( + def from_pim( # pylint: disable=missing-param-doc cls, *, dry_run: bool = False, @@ -425,6 +428,7 @@ def from_install( dry_run: Literal[False] = False, **kwargs: Unpack[LaunchFluentArgs], ) -> session_meshing.Meshing: ... + @overload @classmethod def from_install( @@ -442,6 +446,7 @@ def from_container( dry_run: Literal[False] = False, **kwargs: Unpack[ContainerArgsWithoutDryRun], ) -> session_meshing.Meshing: ... + @overload @classmethod def from_container( @@ -459,6 +464,7 @@ def from_pim( dry_run: Literal[False] = False, **kwargs: Unpack[PIMArgsWithoutDryRun], ) -> session_meshing.Meshing: ... + @overload @classmethod def from_pim( @@ -482,6 +488,7 @@ def from_install( dry_run: Literal[False] = False, **kwargs: Unpack[LaunchFluentArgs], ) -> session_pure_meshing.PureMeshing: ... + @overload @classmethod def from_install( @@ -499,6 +506,7 @@ def from_container( dry_run: Literal[False] = False, **kwargs: Unpack[ContainerArgsWithoutDryRun], ) -> session_pure_meshing.PureMeshing: ... + @overload @classmethod def from_container( @@ -516,6 +524,7 @@ def from_pim( dry_run: Literal[False] = False, **kwargs: Unpack[PIMArgsWithoutDryRun], ) -> session_pure_meshing.PureMeshing: ... + @overload @classmethod def from_pim( @@ -539,6 +548,7 @@ def from_install( dry_run: Literal[False] = False, **kwargs: Unpack[LaunchFluentArgs], ) -> session_solver.Solver: ... + @overload @classmethod def from_install( @@ -556,6 +566,7 @@ def from_container( dry_run: Literal[False] = False, **kwargs: Unpack[ContainerArgsWithoutDryRun], ) -> session_solver.Solver: ... + @overload @classmethod def from_container( @@ -573,6 +584,7 @@ def from_pim( dry_run: Literal[False] = False, **kwargs: Unpack[PIMArgsWithoutDryRun], ) -> session_solver.Solver: ... + @overload @classmethod def from_pim( @@ -596,6 +608,7 @@ def from_install( dry_run: Literal[False] = False, **kwargs: Unpack[LaunchFluentArgs], ) -> session_solver.Solver: ... + @overload @classmethod def from_install( @@ -613,6 +626,7 @@ def from_container( dry_run: Literal[False] = False, **kwargs: Unpack[ContainerArgsWithoutDryRun], ) -> session_solver.Solver: ... + @overload @classmethod def from_container( @@ -630,6 +644,7 @@ def from_pim( dry_run: Literal[False] = False, **kwargs: Unpack[PIMArgsWithoutDryRun], ) -> session_solver.Solver: ... + @overload @classmethod def from_pim( @@ -653,6 +668,7 @@ def from_install( dry_run: Literal[False] = False, **kwargs: Unpack[LaunchFluentArgs], ) -> session_solver_aero.SolverAero: ... + @overload @classmethod def from_install( @@ -670,6 +686,7 @@ def from_container( dry_run: Literal[False] = False, **kwargs: Unpack[ContainerArgsWithoutDryRun], ) -> session_solver_aero.SolverAero: ... + @overload @classmethod def from_container( @@ -687,6 +704,7 @@ def from_pim( dry_run: Literal[False] = False, **kwargs: Unpack[PIMArgsWithoutDryRun], ) -> session_solver_aero.SolverAero: ... + @overload @classmethod def from_pim( @@ -710,6 +728,7 @@ def from_install( dry_run: Literal[False] = False, **kwargs: Unpack[LaunchFluentArgs], ) -> session_solver_icing.SolverIcing: ... + @overload @classmethod def from_install( @@ -727,6 +746,7 @@ def from_container( dry_run: Literal[False] = False, **kwargs: Unpack[ContainerArgsWithoutDryRun], ) -> session_solver_icing.SolverIcing: ... + @overload @classmethod def from_container( @@ -744,6 +764,7 @@ def from_pim( dry_run: Literal[False] = False, **kwargs: Unpack[PIMArgsWithoutDryRun], ) -> session_solver_icing.SolverIcing: ... + @overload @classmethod def from_pim(