From ee74daa11bb81248041ccc1dbece7ee276ca2f32 Mon Sep 17 00:00:00 2001 From: Gobot1234 Date: Wed, 28 Jan 2026 10:32:09 +0000 Subject: [PATCH 1/6] call .name if it's a settings object --- src/ansys/fluent/core/solver/flobject.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/ansys/fluent/core/solver/flobject.py b/src/ansys/fluent/core/solver/flobject.py index bc035d7487f3..ac4d6215d907 100644 --- a/src/ansys/fluent/core/solver/flobject.py +++ b/src/ansys/fluent/core/solver/flobject.py @@ -40,7 +40,7 @@ from __future__ import annotations -import collections +import collections.abc from contextlib import contextmanager, nullcontext import fnmatch import hashlib @@ -49,6 +49,7 @@ import logging import os import os.path +from pathlib import Path import pickle import string import sys @@ -61,12 +62,14 @@ Generic, List, NewType, + Protocol, Tuple, TypeVar, Union, _eval_type, get_args, get_origin, + override, ) import warnings import weakref @@ -673,10 +676,15 @@ def units(self) -> str | None: return get_si_unit_for_fluent_quantity(quantity) +class SettingsBaseWithName(Protocol): + __class__: type["SettingsBase"] # pyright: ignore[reportIncompatibleMethodOverride] + name: Callable[[], str] + + class Textual(Property): """Exposes attribute accessor on settings object - specific to string objects.""" - def set_state(self, state: StateT | None = None, **kwargs): + def set_state(self, state: str | VariableDescriptor | SettingsBaseWithName | None = None, **kwargs): """Set the state of the object. Parameters @@ -691,6 +699,9 @@ def set_state(self, state: StateT | None = None, **kwargs): TypeError If state is not a string. """ + if isinstance(state, SettingsBase) and hasattr(state, "name"): + state = state.name() + allowed_types = (str, VariableDescriptor) if not isinstance(state, allowed_types): @@ -948,6 +959,10 @@ class Filename(SettingsBase[str], Textual): _state_type = str + @override + def set_state(self, state: Path | str | None = None, **kwargs): + return super().set_state(state, **kwargs) + def file_purpose(self): """Specifies whether this file is used as input or output by Fluent.""" return self.get_attr(_InlineConstants.file_purpose) From e3e621759a0df05737819ebf1e7f3b3808eda79f Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:23:27 +0000 Subject: [PATCH 2/6] chore: adding changelog file 4932.added.md [dependabot-skip] --- doc/changelog.d/4932.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/4932.added.md diff --git a/doc/changelog.d/4932.added.md b/doc/changelog.d/4932.added.md new file mode 100644 index 000000000000..91cc5e766eec --- /dev/null +++ b/doc/changelog.d/4932.added.md @@ -0,0 +1 @@ +Call .name if it's a SettingsBase From d08e0639c947aa87bf639f0e957eb37a6312b108 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:53:35 +0000 Subject: [PATCH 3/6] chore: adding changelog file 4932.added.md [dependabot-skip] --- doc/changelog.d/4932.added.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.d/4932.added.md b/doc/changelog.d/4932.added.md index 91cc5e766eec..2ffdae3d5318 100644 --- a/doc/changelog.d/4932.added.md +++ b/doc/changelog.d/4932.added.md @@ -1 +1 @@ -Call .name if it's a SettingsBase +Call .name if it's a SettingsBase + Path support From 13d739ccb510e547b61ece6401642f99fab7fcb6 Mon Sep 17 00:00:00 2001 From: Gobot1234 Date: Mon, 16 Feb 2026 15:15:27 +0000 Subject: [PATCH 4/6] address copilot --- src/ansys/fluent/core/codegen/settingsgen.py | 5 ++-- src/ansys/fluent/core/solver/flobject.py | 30 ++++++++++++++------ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/ansys/fluent/core/codegen/settingsgen.py b/src/ansys/fluent/core/codegen/settingsgen.py index 358134dbdafd..6f0dffee8f83 100644 --- a/src/ansys/fluent/core/codegen/settingsgen.py +++ b/src/ansys/fluent/core/codegen/settingsgen.py @@ -188,13 +188,13 @@ def _get_unique_name(name): "Integer": "int", "Real": "float | str", "String": "str", - "Filename": "str", + "Filename": "PathType", "BooleanList": "list[bool]", "IntegerList": "list[int]", "RealVector": "tuple[float | str, float | str, float | str]", "RealList": "list[float | str]", "StringList": "list[str]", - "FilenameList": "list[str]", + "FilenameList": "list[PathType]", } @@ -381,6 +381,7 @@ def generate(version: str, static_infos: dict, verbose: bool = False) -> None: header.write("# This is an auto-generated file. DO NOT EDIT!\n") header.write("#\n") header.write("\n") + header.write("from ansys.fluent.core._types import PathType\n") header.write("from ansys.fluent.core.solver.flobject import *\n\n") header.write("from ansys.fluent.core.solver.flobject import (\n") header.write(" _ChildNamedObjectAccessorMixin,\n") diff --git a/src/ansys/fluent/core/solver/flobject.py b/src/ansys/fluent/core/solver/flobject.py index ac4d6215d907..7fb139fb8827 100644 --- a/src/ansys/fluent/core/solver/flobject.py +++ b/src/ansys/fluent/core/solver/flobject.py @@ -41,6 +41,7 @@ from __future__ import annotations import collections.abc +from collections.abc import Sequence from contextlib import contextmanager, nullcontext import fnmatch import hashlib @@ -49,12 +50,12 @@ import logging import os import os.path -from pathlib import Path import pickle import string import sys import types from typing import ( + TYPE_CHECKING, Any, Callable, Dict, @@ -69,11 +70,13 @@ _eval_type, get_args, get_origin, - override, ) import warnings import weakref +from typing_extensions import override + +from ansys.fluent.core._types import PathType from ansys.fluent.core.pyfluent_warnings import ( PyFluentDeprecationWarning, PyFluentUserWarning, @@ -676,7 +679,7 @@ def units(self) -> str | None: return get_si_unit_for_fluent_quantity(quantity) -class SettingsBaseWithName(Protocol): +class SettingsBaseWithName(Protocol): # pylint: disable=missing-class-docstring __class__: type["SettingsBase"] # pyright: ignore[reportIncompatibleMethodOverride] name: Callable[[], str] @@ -684,20 +687,24 @@ class SettingsBaseWithName(Protocol): class Textual(Property): """Exposes attribute accessor on settings object - specific to string objects.""" - def set_state(self, state: str | VariableDescriptor | SettingsBaseWithName | None = None, **kwargs): + def set_state( + self, + state: str | VariableDescriptor | SettingsBaseWithName | None = None, + **kwargs, + ): """Set the state of the object. Parameters ---------- state - Either str or VariableDescriptor. + Either str, settings object with a ``name()`` method or VariableDescriptor. kwargs : Any Keyword arguments. Raises ------ TypeError - If state is not a string. + If state is not an appropriate type. """ if isinstance(state, SettingsBase) and hasattr(state, "name"): state = state.name() @@ -954,13 +961,15 @@ class String(SettingsBase[str], Textual): set_state = Textual.set_state -class Filename(SettingsBase[str], Textual): +class Filename(SettingsBase[PathType], Textual): """A ``Filename`` object representing a file name.""" _state_type = str @override - def set_state(self, state: Path | str | None = None, **kwargs): + def set_state(self, state: PathType | None = None, **kwargs): + if state is not None: + state = os.fspath(state) return super().set_state(state, **kwargs) def file_purpose(self): @@ -973,6 +982,11 @@ class FilenameList(SettingsBase[StringListType], Textual): _state_type = StringListType + if TYPE_CHECKING: + + @override + def set_state(self, state: Sequence[PathType] | None = None, **kwargs): ... + def file_purpose(self): """Specifies whether this file is used as input or output by Fluent.""" return self.get_attr(_InlineConstants.file_purpose) From 4a4c45f74ac4ee8efe9d1438dac0648acd0b2fcb Mon Sep 17 00:00:00 2001 From: James Hilton-Balfe Date: Mon, 16 Feb 2026 16:34:38 +0000 Subject: [PATCH 5/6] Update src/ansys/fluent/core/solver/flobject.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/ansys/fluent/core/solver/flobject.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ansys/fluent/core/solver/flobject.py b/src/ansys/fluent/core/solver/flobject.py index 7fb139fb8827..782ea49753b3 100644 --- a/src/ansys/fluent/core/solver/flobject.py +++ b/src/ansys/fluent/core/solver/flobject.py @@ -987,6 +987,11 @@ class FilenameList(SettingsBase[StringListType], Textual): @override def set_state(self, state: Sequence[PathType] | None = None, **kwargs): ... + @override + def set_state(self, state: Sequence[PathType] | None = None, **kwargs): + if state is not None: + state = [os.fspath(path) for path in state] + return super().set_state(state, **kwargs) def file_purpose(self): """Specifies whether this file is used as input or output by Fluent.""" return self.get_attr(_InlineConstants.file_purpose) From e331ffcfaf631e7f3129e61ea553bd432cffc8d8 Mon Sep 17 00:00:00 2001 From: Gobot1234 Date: Wed, 18 Feb 2026 15:46:50 +0000 Subject: [PATCH 6/6] add tests --- src/ansys/fluent/core/solver/flobject.py | 25 +++++++++--- tests/test_settings_api.py | 48 +++++++++++++++++++++++- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/ansys/fluent/core/solver/flobject.py b/src/ansys/fluent/core/solver/flobject.py index 782ea49753b3..941a2350803c 100644 --- a/src/ansys/fluent/core/solver/flobject.py +++ b/src/ansys/fluent/core/solver/flobject.py @@ -55,7 +55,6 @@ import sys import types from typing import ( - TYPE_CHECKING, Any, Callable, Dict, @@ -982,16 +981,12 @@ class FilenameList(SettingsBase[StringListType], Textual): _state_type = StringListType - if TYPE_CHECKING: - - @override - def set_state(self, state: Sequence[PathType] | None = None, **kwargs): ... - @override def set_state(self, state: Sequence[PathType] | None = None, **kwargs): if state is not None: state = [os.fspath(path) for path in state] return super().set_state(state, **kwargs) + def file_purpose(self): """Specifies whether this file is used as input or output by Fluent.""" return self.get_attr(_InlineConstants.file_purpose) @@ -1065,6 +1060,24 @@ class StringList(SettingsBase[StringListType], Textual): _state_type = StringListType + @override + def set_state( + self, + state: Sequence[str | SettingsBaseWithName | VariableDescriptor] | None = None, + **kwargs, + ): + if isinstance(state, Sequence): + state = [ + ( + entry.name() + if isinstance(entry, SettingsBase) and hasattr(entry, "name") + else entry + ) + for entry in state + ] + + return super().set_state(state, **kwargs) + class BooleanList(SettingsBase[BoolListType], Property): """A ``BooleanList`` object representing a Boolean list setting.""" diff --git a/tests/test_settings_api.py b/tests/test_settings_api.py index 3967e31dbf5d..30f13c6b0e1a 100644 --- a/tests/test_settings_api.py +++ b/tests/test_settings_api.py @@ -20,6 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from pathlib import Path +import tempfile import warnings import pytest @@ -797,7 +799,7 @@ def test_named_object_commands(mixing_elbow_settings_session): solver = mixing_elbow_settings_session inlets = VelocityInlets(solver) inlets.list() - inlets.list_properties(object_name="hot-inlet") + inlets.list_properties(object_name="hot-i nlet") if solver.get_fluent_version() >= FluentVersion.v261: NamedObject.list(inlets) NamedObject.list_properties(inlets, object_name="hot-inlet") @@ -858,3 +860,47 @@ def test_read_only_command_execution(mixing_elbow_case_session): assert contour.display.is_read_only() is True with pytest.raises(ReadOnlyActionError): contour.display() + + +def test_setting_base_with_name(mixing_elbow_settings_session): + solver = mixing_elbow_settings_session + + with solver: + report_def = solver.settings.solution.report_definitions.surface.create( + "test-report-def" + ) + report_def.report_type = "surface-areaavg" + report_def.field = "temperature" + report_def.surface_names = ["hot-inlet"] + + report_file_obj = solver.settings.solution.monitor.report_files.create( + "test-file" + ) + report_file_obj.report_defs = [report_def] + + assert report_file_obj.report_defs() == [report_def.name()] + + +def test_filename_with_pathlib_path(mixing_elbow_settings_session): + solver = mixing_elbow_settings_session + + with tempfile.TemporaryDirectory() as tmpdir, solver: + path_obj = Path(tmpdir) / "test_output.dat" + path_str = str(path_obj) + + report_def = solver.settings.solution.report_definitions.surface.create( + "test-path-report" + ) + report_def.report_type = "surface-areaavg" + report_def.field = "pressure" + report_def.surface_names = ["cold-inlet"] + + report_file = solver.settings.solution.monitor.report_files.create( + "test-path-file" + ) + report_file.report_defs = "test-path-report" + + report_file.file_name = path_obj + + result_path = report_file.file_name() + assert result_path == path_str