ansys-fluent-core 0.34.dev0__py3-none-any.whl → 0.35.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ansys-fluent-core might be problematic. Click here for more details.

Files changed (108) hide show
  1. ansys/fluent/core/__init__.py +48 -84
  2. ansys/fluent/core/codegen/allapigen.py +2 -2
  3. ansys/fluent/core/codegen/builtin_settingsgen.py +41 -13
  4. ansys/fluent/core/codegen/datamodelgen.py +3 -1
  5. ansys/fluent/core/codegen/print_fluent_version.py +2 -2
  6. ansys/fluent/core/codegen/settingsgen.py +18 -6
  7. ansys/fluent/core/codegen/tuigen.py +6 -5
  8. ansys/fluent/core/data_model_cache.py +2 -2
  9. ansys/fluent/core/docker/docker_compose.py +11 -9
  10. ansys/fluent/core/docker/utils.py +35 -0
  11. ansys/fluent/core/examples/downloads.py +8 -11
  12. ansys/fluent/core/exceptions.py +13 -1
  13. ansys/fluent/core/field_data_interfaces.py +239 -38
  14. ansys/fluent/core/file_session.py +167 -61
  15. ansys/fluent/core/fluent_connection.py +41 -26
  16. ansys/fluent/core/generated/api_tree/api_objects.json +1 -1
  17. ansys/fluent/core/generated/datamodel_231/flicing.py +40 -40
  18. ansys/fluent/core/generated/datamodel_231/meshing.py +231 -231
  19. ansys/fluent/core/generated/datamodel_232/flicing.py +50 -50
  20. ansys/fluent/core/generated/datamodel_232/meshing.py +189 -189
  21. ansys/fluent/core/generated/datamodel_241/flicing.py +30 -30
  22. ansys/fluent/core/generated/datamodel_241/meshing.py +290 -290
  23. ansys/fluent/core/generated/datamodel_242/flicing.py +50 -50
  24. ansys/fluent/core/generated/datamodel_242/meshing.py +331 -331
  25. ansys/fluent/core/generated/datamodel_242/part_management.py +6 -6
  26. ansys/fluent/core/generated/datamodel_251/flicing.py +65 -65
  27. ansys/fluent/core/generated/datamodel_251/meshing.py +300 -300
  28. ansys/fluent/core/generated/datamodel_251/part_management.py +6 -6
  29. ansys/fluent/core/generated/datamodel_252/flicing.py +25 -25
  30. ansys/fluent/core/generated/datamodel_252/meshing.py +382 -382
  31. ansys/fluent/core/generated/datamodel_252/part_management.py +10 -10
  32. ansys/fluent/core/generated/datamodel_261/flicing.py +45 -45
  33. ansys/fluent/core/generated/datamodel_261/meshing.py +454 -435
  34. ansys/fluent/core/generated/datamodel_261/part_management.py +5 -5
  35. ansys/fluent/core/generated/datamodel_261/preferences.py +7 -0
  36. ansys/fluent/core/generated/fluent_version_252.py +1 -1
  37. ansys/fluent/core/generated/fluent_version_261.py +3 -3
  38. ansys/fluent/core/generated/meshing/tui_261.py +54 -3
  39. ansys/fluent/core/generated/solver/settings_231.py +1 -0
  40. ansys/fluent/core/generated/solver/settings_231.pyi +3025 -1
  41. ansys/fluent/core/generated/solver/settings_232.py +1 -0
  42. ansys/fluent/core/generated/solver/settings_232.pyi +3425 -1
  43. ansys/fluent/core/generated/solver/settings_241.py +1 -0
  44. ansys/fluent/core/generated/solver/settings_241.pyi +4423 -1
  45. ansys/fluent/core/generated/solver/settings_242.py +1 -0
  46. ansys/fluent/core/generated/solver/settings_242.pyi +5474 -1
  47. ansys/fluent/core/generated/solver/settings_251.py +11 -0
  48. ansys/fluent/core/generated/solver/settings_251.pyi +6006 -1
  49. ansys/fluent/core/generated/solver/settings_252.py +11 -1
  50. ansys/fluent/core/generated/solver/settings_252.pyi +6782 -2
  51. ansys/fluent/core/generated/solver/settings_261.py +5592 -2740
  52. ansys/fluent/core/generated/solver/settings_261.pyi +10335 -1994
  53. ansys/fluent/core/generated/solver/settings_builtin.py +560 -38
  54. ansys/fluent/core/generated/solver/settings_builtin.pyi +24 -18
  55. ansys/fluent/core/generated/solver/tui_261.py +409 -285
  56. ansys/fluent/core/launcher/container_launcher.py +25 -6
  57. ansys/fluent/core/launcher/error_handler.py +1 -1
  58. ansys/fluent/core/launcher/fluent_container.py +97 -45
  59. ansys/fluent/core/launcher/launch_options.py +5 -4
  60. ansys/fluent/core/launcher/launcher.py +18 -2
  61. ansys/fluent/core/launcher/launcher_utils.py +63 -15
  62. ansys/fluent/core/launcher/pim_launcher.py +17 -3
  63. ansys/fluent/core/launcher/process_launch_string.py +3 -2
  64. ansys/fluent/core/launcher/server_info.py +7 -3
  65. ansys/fluent/core/launcher/slurm_launcher.py +4 -2
  66. ansys/fluent/core/launcher/standalone_launcher.py +6 -3
  67. ansys/fluent/core/launcher/watchdog.py +6 -6
  68. ansys/fluent/core/launcher/watchdog_exec +1 -1
  69. ansys/fluent/core/logger.py +3 -1
  70. ansys/fluent/core/module_config.py +358 -0
  71. ansys/fluent/core/pyfluent_warnings.py +9 -3
  72. ansys/fluent/core/report.py +2 -2
  73. ansys/fluent/core/search.py +34 -13
  74. ansys/fluent/core/services/__init__.py +2 -2
  75. ansys/fluent/core/services/api_upgrade.py +3 -2
  76. ansys/fluent/core/services/app_utilities.py +39 -0
  77. ansys/fluent/core/services/datamodel_se.py +4 -2
  78. ansys/fluent/core/services/deprecated_field_data.py +4 -4
  79. ansys/fluent/core/services/field_data.py +185 -49
  80. ansys/fluent/core/services/health_check.py +3 -1
  81. ansys/fluent/core/services/interceptors.py +8 -6
  82. ansys/fluent/core/services/reduction.py +16 -5
  83. ansys/fluent/core/services/settings.py +1 -0
  84. ansys/fluent/core/session.py +47 -4
  85. ansys/fluent/core/session_pure_meshing.py +6 -6
  86. ansys/fluent/core/session_pure_meshing.pyi +1 -0
  87. ansys/fluent/core/session_shared.py +4 -4
  88. ansys/fluent/core/session_solver.py +41 -10
  89. ansys/fluent/core/session_solver.pyi +1 -0
  90. ansys/fluent/core/session_utilities.py +7 -0
  91. ansys/fluent/core/solver/error_message.py +2 -2
  92. ansys/fluent/core/solver/flobject.py +192 -123
  93. ansys/fluent/core/solver/function/reduction.py +37 -9
  94. ansys/fluent/core/solver/settings_builtin_bases.py +3 -3
  95. ansys/fluent/core/solver/settings_builtin_data.py +7 -17
  96. ansys/fluent/core/streaming_services/datamodel_event_streaming.py +3 -2
  97. ansys/fluent/core/streaming_services/datamodel_streaming.py +3 -1
  98. ansys/fluent/core/streaming_services/events_streaming.py +2 -18
  99. ansys/fluent/core/system_coupling.py +3 -1
  100. ansys/fluent/core/utils/__init__.py +0 -7
  101. ansys/fluent/core/utils/data_transfer.py +3 -3
  102. ansys/fluent/core/utils/file_transfer_service.py +24 -15
  103. ansys/fluent/core/utils/fluent_version.py +4 -6
  104. ansys/fluent/core/utils/networking.py +21 -11
  105. {ansys_fluent_core-0.34.dev0.dist-info → ansys_fluent_core-0.35.dev0.dist-info}/METADATA +10 -11
  106. {ansys_fluent_core-0.34.dev0.dist-info → ansys_fluent_core-0.35.dev0.dist-info}/RECORD +108 -106
  107. {ansys_fluent_core-0.34.dev0.dist-info → ansys_fluent_core-0.35.dev0.dist-info}/WHEEL +1 -1
  108. {ansys_fluent_core-0.34.dev0.dist-info/licenses → ansys_fluent_core-0.35.dev0.dist-info}/LICENSE +0 -0
@@ -23,10 +23,14 @@
23
23
  """A package providing Fluent's Solver and Meshing capabilities in Python."""
24
24
 
25
25
  import os
26
- from pathlib import Path
27
26
  import pydoc
27
+ import warnings
28
28
 
29
29
  # isort: off
30
+
31
+ # config must be initialized before logging setup.
32
+ from ansys.fluent.core.module_config import config
33
+
30
34
  # Logging has to be imported before importing other PyFluent modules
31
35
  from ansys.fluent.core.logger import set_console_logging_level # noqa: F401
32
36
 
@@ -73,13 +77,13 @@ from ansys.fluent.core.session_utilities import ( # noqa: F401
73
77
  SolverIcing,
74
78
  )
75
79
  from ansys.fluent.core.streaming_services.events_streaming import * # noqa: F401, F403
76
- from ansys.fluent.core.utils import fldoc, get_examples_download_dir
80
+ from ansys.fluent.core.utils import fldoc
77
81
  from ansys.fluent.core.utils.fluent_version import FluentVersion # noqa: F401
78
82
  from ansys.fluent.core.utils.setup_for_fluent import setup_for_fluent # noqa: F401
79
83
 
80
- __version__ = "0.34.dev0"
84
+ __version__ = "0.35.dev0"
81
85
 
82
- _VERSION_INFO = "Build date: June 24, 2025 09:29 UTC ShaID: f235a41"
86
+ _VERSION_INFO = "Build date: August 12, 2025 05:58 UTC ShaID: c65664b"
83
87
  """
84
88
  Global variable indicating the version info of the PyFluent package.
85
89
  Build timestamp and commit hash are added to this variable during packaging.
@@ -108,86 +112,46 @@ def version_info() -> str:
108
112
  return _VERSION_INFO if _VERSION_INFO is not None else __version__
109
113
 
110
114
 
111
- # Latest released Fluent version
112
- FLUENT_RELEASE_VERSION = "25.2.0"
113
-
114
- # Current dev Fluent version
115
- FLUENT_DEV_VERSION = "26.1.0"
116
-
117
- # Path to the example input/data files are downloaded
118
- EXAMPLES_PATH = str(get_examples_download_dir())
119
-
120
- # Host path which is mounted to the container
121
- CONTAINER_MOUNT_SOURCE = None
122
-
123
- # Path inside the container where the host path is mounted
124
- CONTAINER_MOUNT_TARGET = "/home/container/workdir"
125
-
126
- # Set this to False to stop automatically inferring and setting REMOTING_SERVER_ADDRESS
127
- INFER_REMOTING_IP = True
128
-
129
- # Time in second to wait for response for each ip while inferring remoting ip
130
- INFER_REMOTING_IP_TIMEOUT_PER_IP = 2
131
-
132
115
  pydoc.text.docother = fldoc.docother.__get__(pydoc.text, pydoc.TextDoc)
133
116
 
134
- # Whether to use datamodel state caching
135
- DATAMODEL_USE_STATE_CACHE = True
136
-
137
- # Whether to use datamodel attribute caching
138
- DATAMODEL_USE_ATTR_CACHE = True
139
-
140
- # Whether to stream and cache commands state
141
- DATAMODEL_USE_NOCOMMANDS_DIFF_STATE = True
142
-
143
- # Whether to return the state changes on mutating datamodel rpcs
144
- DATAMODEL_RETURN_STATE_CHANGES = True
145
-
146
- # Whether to use remote gRPC file transfer service
147
- USE_FILE_TRANSFER_SERVICE = False
148
-
149
- # Directory where API files are written out during codegen
150
- CODEGEN_OUTDIR = os.getenv(
151
- "PYFLUENT_CODEGEN_OUTDIR", (Path(__file__) / ".." / "generated").resolve()
152
- )
153
-
154
- # Whether to show mesh in Fluent after case read
155
- FLUENT_SHOW_MESH_AFTER_CASE_READ = False
156
-
157
- # Whether to write the automatic transcript in Fluent
158
- FLUENT_AUTOMATIC_TRANSCRIPT = False
159
-
160
- # Whether to interrupt Fluent solver from PyFluent
161
- SUPPORT_SOLVER_INTERRUPT = False
162
-
163
- # Whether to start watchdog
164
- START_WATCHDOG = None
165
-
166
- # Health check timeout in seconds
167
- CHECK_HEALTH_TIMEOUT = 60
168
-
169
- # Whether to skip health check
170
- CHECK_HEALTH = True
171
-
172
- # Whether to print search results
173
- PRINT_SEARCH_RESULTS = True
174
-
175
- # Whether to clear environment variables related to Fluent parallel mode
176
- CLEAR_FLUENT_PARA_ENVS = False
177
-
178
- # Set stdout of the launched Fluent process
179
- # Valid values are same as subprocess.Popen's stdout argument
180
- LAUNCH_FLUENT_STDOUT = None
181
-
182
- # Set stderr of the launched Fluent process
183
- # Valid values are same as subprocess.Popen's stderr argument
184
- LAUNCH_FLUENT_STDERR = None
185
-
186
- # Set the IP address of the Fluent server while launching Fluent
187
- LAUNCH_FLUENT_IP = None
188
-
189
- # Set the port of the Fluent server while launching Fluent
190
- LAUNCH_FLUENT_PORT = None
191
117
 
192
- # Skip password check during rpc execution when Fluent is launched from PyFluent
193
- LAUNCH_FLUENT_SKIP_PASSWORD_CHECK = False
118
+ _config_by_deprecated_name = {
119
+ "FLUENT_RELEASE_VERSION": "fluent_release_version",
120
+ "FLUENT_DEV_VERSION": "fluent_dev_version",
121
+ "EXAMPLES_PATH": "examples_path",
122
+ "CONTAINER_MOUNT_SOURCE": "container_mount_source",
123
+ "CONTAINER_MOUNT_TARGET": "container_mount_target",
124
+ "INFER_REMOTING_IP": "infer_remoting_ip",
125
+ "INFER_REMOTING_IP_TIMEOUT_PER_IP": "infer_remoting_ip_timeout_per_ip",
126
+ "DATAMODEL_USE_STATE_CACHE": "datamodel_use_state_cache",
127
+ "DATAMODEL_USE_ATTR_CACHE": "datamodel_use_attr_cache",
128
+ "DATAMODEL_USE_NOCOMMANDS_DIFF_STATE": "datamodel_use_nocommands_diff_state",
129
+ "DATAMODEL_RETURN_STATE_CHANGES": "datamodel_return_state_changes",
130
+ "USE_FILE_TRANSFER_SERVICE": "use_file_transfer_service",
131
+ "CODEGEN_OUTDIR": "codegen_outdir",
132
+ "FLUENT_SHOW_MESH_AFTER_CASE_READ": "fluent_show_mesh_after_case_read",
133
+ "FLUENT_AUTOMATIC_TRANSCRIPT": "fluent_automatic_transcript",
134
+ "SUPPORT_SOLVER_INTERRUPT": "support_solver_interrupt",
135
+ "START_WATCHDOG": "start_watchdog",
136
+ "CHECK_HEALTH_TIMEOUT": "check_health_timeout",
137
+ "CHECK_HEALTH": "check_health",
138
+ "PRINT_SEARCH_RESULTS": "print_search_results",
139
+ "CLEAR_FLUENT_PARA_ENVS": "clear_fluent_para_envs",
140
+ "LAUNCH_FLUENT_STDOUT": "launch_fluent_stdout",
141
+ "LAUNCH_FLUENT_STDERR": "launch_fluent_stderr",
142
+ "LAUNCH_FLUENT_IP": "launch_fluent_ip",
143
+ "LAUNCH_FLUENT_PORT": "launch_fluent_port",
144
+ "LAUNCH_FLUENT_SKIP_PASSWORD_CHECK": "launch_fluent_skip_password_check",
145
+ }
146
+
147
+
148
+ def __getattr__(name: str) -> str:
149
+ """Get the value of a deprecated configuration variable."""
150
+ if name in _config_by_deprecated_name:
151
+ config_name = _config_by_deprecated_name[name]
152
+ warnings.warn(
153
+ f"'{name}' is deprecated, use 'config.{config_name}' instead.",
154
+ category=PyFluentDeprecationWarning,
155
+ )
156
+ return getattr(config, config_name)
157
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@@ -23,10 +23,10 @@
23
23
  """Module to generate Fluent API classes."""
24
24
 
25
25
  import argparse
26
- import os
27
26
  from pathlib import Path
28
27
  import pickle
29
28
 
29
+ from ansys.fluent.core import config
30
30
  from ansys.fluent.core.codegen import ( # noqa: F401
31
31
  builtin_settingsgen,
32
32
  datamodelgen,
@@ -51,7 +51,7 @@ def generate(version: str, static_infos: dict, verbose: bool = False):
51
51
  Path(api_tree_file).parent.mkdir(parents=True, exist_ok=True)
52
52
  with open(api_tree_file, "wb") as f:
53
53
  pickle.dump(api_tree, f)
54
- if os.getenv("PYFLUENT_CODEGEN_SKIP_BUILTIN_SETTINGS") != "1":
54
+ if not config.codegen_skip_builtin_settings:
55
55
  builtin_settingsgen.generate(version)
56
56
 
57
57
 
@@ -22,25 +22,38 @@
22
22
 
23
23
  """Generate builtin setting classes."""
24
24
 
25
- from ansys.fluent.core import CODEGEN_OUTDIR, FluentVersion
26
- from ansys.fluent.core.solver.flobject import CreatableNamedObjectMixin, NamedObject
25
+ import re
26
+
27
+ from ansys.fluent.core import FluentVersion, config
28
+ from ansys.fluent.core.solver.flobject import (
29
+ CreatableNamedObjectMixin,
30
+ NamedObject,
31
+ _ChildNamedObjectAccessorMixin,
32
+ )
27
33
  from ansys.fluent.core.solver.settings_builtin_data import DATA
28
34
  from ansys.fluent.core.utils.fluent_version import all_versions
29
35
 
30
- _PY_FILE = CODEGEN_OUTDIR / "solver" / "settings_builtin.py"
31
- _PYI_FILE = CODEGEN_OUTDIR / "solver" / "settings_builtin.pyi"
36
+ _PY_FILE = config.codegen_outdir / "solver" / "settings_builtin.py"
37
+ _PYI_FILE = config.codegen_outdir / "solver" / "settings_builtin.pyi"
32
38
 
33
39
 
34
40
  def _get_settings_root(version: str):
35
- from ansys.fluent.core import CODEGEN_OUTDIR, utils
41
+ from ansys.fluent.core import config, utils
36
42
 
37
43
  settings = utils.load_module(
38
44
  f"settings_{version}",
39
- CODEGEN_OUTDIR / "solver" / f"settings_{version}.py",
45
+ config.codegen_outdir / "solver" / f"settings_{version}.py",
40
46
  )
41
47
  return settings.root
42
48
 
43
49
 
50
+ def _convert_camel_case_to_snake_case(name: str) -> str:
51
+ """Convert CamelCase to snake_case."""
52
+ # Replace uppercase letters with lowercase and prepend an underscore
53
+ name = re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()
54
+ return name
55
+
56
+
44
57
  def _get_named_objects_in_path(root, path, kind):
45
58
  named_objects = []
46
59
  cls = root
@@ -52,6 +65,8 @@ def _get_named_objects_in_path(root, path, kind):
52
65
  cls = cls.child_object_type
53
66
  final_type = ""
54
67
  if kind == "NamedObject":
68
+ if not issubclass(cls, (NamedObject, _ChildNamedObjectAccessorMixin)):
69
+ raise TypeError(f"{cls.__name__} is not NamedObject type.")
55
70
  if issubclass(cls, CreatableNamedObjectMixin):
56
71
  final_type = "Creatable"
57
72
  else:
@@ -62,7 +77,7 @@ def _get_named_objects_in_path(root, path, kind):
62
77
  def generate(version: str):
63
78
  """Generate builtin setting classes."""
64
79
  print("Generating builtin settings...")
65
- CODEGEN_OUTDIR.mkdir(exist_ok=True)
80
+ config.codegen_outdir.mkdir(exist_ok=True)
66
81
  root = _get_settings_root(version)
67
82
  version = FluentVersion(version)
68
83
  with open(_PY_FILE, "w") as f:
@@ -72,8 +87,11 @@ def generate(version: str):
72
87
  "from ansys.fluent.core.solver.flobject import SettingsBase\n\n\n"
73
88
  )
74
89
  f.write("__all__ = [\n")
75
- for name, _ in DATA.items():
90
+ for name, (kind, _) in DATA.items():
76
91
  f.write(f' "{name}",\n')
92
+ if kind == "Command":
93
+ command_name = _convert_camel_case_to_snake_case(name)
94
+ f.write(f' "{command_name}",\n')
77
95
  f.write("]\n\n")
78
96
  for name, v in DATA.items():
79
97
  kind, path = v
@@ -86,8 +104,9 @@ def generate(version: str):
86
104
  if kind == "NamedObject":
87
105
  kind = f"{final_type}NamedObject"
88
106
  f.write(f"class {name}(_{kind}Setting):\n")
89
- doc_kind = "command" if kind == "Command" else "setting"
107
+ doc_kind = "command object" if kind == "Command" else "setting"
90
108
  f.write(f' """{name} {doc_kind}."""\n\n')
109
+ f.write(f' _db_name = "{name}"\n\n')
91
110
  f.write(" def __init__(self")
92
111
  for named_object in named_objects:
93
112
  f.write(f", {named_object}: str")
@@ -96,8 +115,6 @@ def generate(version: str):
96
115
  f.write(", name: str = None")
97
116
  elif kind == "CreatableNamedObject":
98
117
  f.write(", name: str = None, new_instance_name: str = None")
99
- if kind == "Command":
100
- f.write(", **kwargs")
101
118
  f.write("):\n")
102
119
  f.write(" super().__init__(settings_source=settings_source")
103
120
  if kind == "NonCreatableNamedObject":
@@ -106,9 +123,20 @@ def generate(version: str):
106
123
  f.write(", name=name, new_instance_name=new_instance_name")
107
124
  for named_object in named_objects:
108
125
  f.write(f", {named_object}={named_object}")
109
- if kind == "Command":
110
- f.write(", **kwargs")
111
126
  f.write(")\n\n")
127
+ if kind == "Command":
128
+ command_name = _convert_camel_case_to_snake_case(name)
129
+ f.write(f"class {command_name}(_{kind}Setting):\n")
130
+ f.write(f' """{command_name} command."""\n\n')
131
+ f.write(f' _db_name = "{name}"\n\n')
132
+ f.write(
133
+ " def __new__(cls, settings_source: SettingsBase | Solver | None = None, **kwargs):\n"
134
+ )
135
+ f.write(" instance = super().__new__(cls)\n")
136
+ f.write(
137
+ " instance.__init__(settings_source=settings_source, **kwargs)\n"
138
+ )
139
+ f.write(" return instance(**kwargs)\n\n")
112
140
 
113
141
  with open(_PYI_FILE, "w") as f:
114
142
  for version in FluentVersion:
@@ -210,7 +210,9 @@ class DataModelStaticInfo:
210
210
  self.static_info = None
211
211
  if rules_save_name == "":
212
212
  rules_save_name = rules
213
- datamodel_dir = (pyfluent.CODEGEN_OUTDIR / f"datamodel_{version}").resolve()
213
+ datamodel_dir = (
214
+ pyfluent.config.codegen_outdir / f"datamodel_{version}"
215
+ ).resolve()
214
216
  datamodel_dir.mkdir(exist_ok=True)
215
217
  self.file_name = (
216
218
  datamodel_dir / f"{datamodel_file_name_map[rules_save_name]}.py"
@@ -22,14 +22,14 @@
22
22
 
23
23
  """Module to write Fluent version information."""
24
24
 
25
- from ansys.fluent.core import CODEGEN_OUTDIR, FluentVersion, launch_fluent
25
+ from ansys.fluent.core import FluentVersion, config, launch_fluent
26
26
 
27
27
 
28
28
  def print_fluent_version(app_utilities):
29
29
  """Write Fluent version information to file."""
30
30
  version = FluentVersion(app_utilities.get_product_version()).number
31
31
  build_info = app_utilities.get_build_info()
32
- version_file = (CODEGEN_OUTDIR / f"fluent_version_{version}.py").resolve()
32
+ version_file = (config.codegen_outdir / f"fluent_version_{version}.py").resolve()
33
33
  with open(version_file, "w", encoding="utf8") as f:
34
34
  f.write(f'FLUENT_VERSION = "{version}"\n')
35
35
  f.write(f'FLUENT_BUILD_TIME = "{build_info.build_time}"\n')
@@ -38,6 +38,7 @@ from ansys.fluent.core.solver.flobject import (
38
38
  ListObject,
39
39
  NamedObject,
40
40
  get_cls,
41
+ to_constant_name,
41
42
  to_python_name,
42
43
  )
43
44
  from ansys.fluent.core.utils.fix_doc import fix_settings_doc
@@ -107,10 +108,11 @@ def strip_parameters(docstring: str) -> str:
107
108
 
108
109
 
109
110
  def _populate_data(cls, api_tree: dict, version: str) -> dict:
110
- data = {}
111
- data["version"] = version
112
- data["name"] = cls.__name__
113
- data["bases"] = [base.__name__ for base in cls.__bases__]
111
+ data = {
112
+ "version": version,
113
+ "name": cls.__name__,
114
+ "bases": [base.__name__ for base in cls.__bases__],
115
+ }
114
116
  if "command" in cls.__doc__:
115
117
  data["doc"] = strip_parameters(cls.__doc__)
116
118
  else:
@@ -150,6 +152,7 @@ def _populate_data(cls, api_tree: dict, version: str) -> dict:
150
152
  data["child_object_type"]["doc"] = f"'child_object_type' of {cls.__name__}."
151
153
  else:
152
154
  data["child_object_type"] = None
155
+ data["allowed_values"] = getattr(cls, "_allowed_values", [])
153
156
  return data
154
157
 
155
158
 
@@ -306,7 +309,15 @@ def _write_data(cls_name: str, python_name: str, data: dict, f: IO, f_stub: IO |
306
309
  if return_type:
307
310
  s.write(f" return_type = {return_type!r}\n")
308
311
  s_stub.write(" return_type: str\n")
312
+ for allowed_value in data["allowed_values"]:
313
+ s.write(
314
+ f" {to_constant_name(allowed_value)} = _FlStringConstant({allowed_value!r})\n"
315
+ )
316
+ s_stub.write(
317
+ f" {to_constant_name(allowed_value)}: Final[str] = {allowed_value!r}\n"
318
+ )
309
319
  s.write("\n")
320
+ s_stub.write("\n")
310
321
  for name, (python_name, data, hash_, should_write_stub) in classes_to_write.items():
311
322
  if name not in _CLASS_WRITTEN:
312
323
  _write_data(
@@ -344,7 +355,7 @@ def generate(version: str, static_infos: dict, verbose: bool = False) -> None:
344
355
  shash = _gethash(sinfo)
345
356
  if not sinfo:
346
357
  return {"<solver_session>": api_tree}
347
- output_dir = (pyfluent.CODEGEN_OUTDIR / "solver").resolve()
358
+ output_dir = (pyfluent.config.codegen_outdir / "solver").resolve()
348
359
  output_dir.mkdir(parents=True, exist_ok=True)
349
360
  output_file = output_dir / f"settings_{version}.py"
350
361
  output_stub_file = output_dir / f"settings_{version}.pyi"
@@ -370,10 +381,11 @@ def generate(version: str, static_infos: dict, verbose: bool = False) -> None:
370
381
  header.write(" _InputFile,\n")
371
382
  header.write(" _OutputFile,\n")
372
383
  header.write(" _InOutFile,\n")
384
+ header.write(" _FlStringConstant,\n")
373
385
  header.write(")\n\n")
374
386
  f.write(header.getvalue())
375
387
  f_stub.write(header.getvalue())
376
- f_stub.write("from typing import Any\n\n")
388
+ f_stub.write("from typing import Any, Final\n\n")
377
389
  f.write(f'SHASH = "{shash}"\n\n')
378
390
  name = data["name"]
379
391
  _NAME_BY_HASH[_gethash(data)] = name
@@ -52,6 +52,7 @@ import ansys.fluent.core as pyfluent
52
52
  from ansys.fluent.core import FluentMode, launch_fluent
53
53
  from ansys.fluent.core.codegen import StaticInfoType
54
54
  from ansys.fluent.core.codegen.data.fluent_gui_help_patch import XML_HELP_PATCH
55
+ from ansys.fluent.core.docker.utils import get_ghcr_fluent_image_name
55
56
  from ansys.fluent.core.services.datamodel_tui import (
56
57
  convert_path_to_grpc_path,
57
58
  convert_tui_menu_to_func_name,
@@ -68,7 +69,7 @@ _ROOT_DIR = Path(__file__) / ".." / ".." / ".." / ".." / ".." / ".."
68
69
 
69
70
 
70
71
  def _get_tui_filepath(mode: str, version: str):
71
- return (pyfluent.CODEGEN_OUTDIR / mode / f"tui_{version}.py").resolve()
72
+ return (pyfluent.config.codegen_outdir / mode / f"tui_{version}.py").resolve()
72
73
 
73
74
 
74
75
  _INDENT_STEP = 4
@@ -95,9 +96,9 @@ _XML_HELPSTRINGS = {}
95
96
 
96
97
 
97
98
  def _copy_tui_help_xml_file(version: str):
98
- if os.getenv("PYFLUENT_LAUNCH_CONTAINER") == "1":
99
- image_tag = os.getenv("FLUENT_IMAGE_TAG", "v25.1.0")
100
- image_name = f"ghcr.io/ansys/pyfluent:{image_tag}"
99
+ if pyfluent.config.launch_fluent_container:
100
+ image_tag = pyfluent.config.fluent_image_tag
101
+ image_name = f"{get_ghcr_fluent_image_name(image_tag)}:{image_tag}"
101
102
  container_name = uuid.uuid4().hex
102
103
  is_linux = platform.system() == "Linux"
103
104
  subprocess.run(
@@ -346,7 +347,7 @@ def generate(version, static_infos: dict, verbose: bool = False):
346
347
  api_tree["<solver_session>"] = TUIGenerator(
347
348
  "solver", version, static_infos, verbose
348
349
  ).generate()
349
- if os.getenv("PYFLUENT_HIDE_LOG_SECRETS") != "1":
350
+ if not pyfluent.config.hide_log_secrets:
350
351
  logger.info(
351
352
  "XML help is available but not picked for the following %i paths: ",
352
353
  len(_XML_HELPSTRINGS),
@@ -126,7 +126,7 @@ class _CacheImpl:
126
126
 
127
127
  def _is_dict_parameter_type(version: FluentVersion, rules: str, rules_path: str):
128
128
  """Check if a parameter is a dict type."""
129
- from ansys.fluent.core import CODEGEN_OUTDIR
129
+ from ansys.fluent.core import config
130
130
  from ansys.fluent.core.services.datamodel_se import (
131
131
  PyDictionary,
132
132
  PyNamedObjectContainer,
@@ -136,7 +136,7 @@ def _is_dict_parameter_type(version: FluentVersion, rules: str, rules_path: str)
136
136
 
137
137
  try:
138
138
  module = load_module(
139
- rules, CODEGEN_OUTDIR / f"datamodel_{version.number}" / f"{rules}.py"
139
+ rules, config.codegen_outdir / f"datamodel_{version.number}" / f"{rules}.py"
140
140
  )
141
141
  except FileNotFoundError: # no codegen or during codegen
142
142
  return False
@@ -22,29 +22,31 @@
22
22
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
23
  # SOFTWARE.
24
24
 
25
- import os
26
25
  import subprocess
27
26
  import uuid
28
27
 
28
+ from .utils import get_ghcr_fluent_image_name
29
+
29
30
 
30
31
  class ComposeBasedLauncher:
31
32
  """Launch Fluent through docker or Podman compose."""
32
33
 
33
- def __init__(self, *, container_dict):
34
+ def __init__(self, compose_config, container_dict):
35
+ from ansys.fluent.core import config
36
+
37
+ self._compose_config = compose_config
34
38
  self._compose_name = f"pyfluent_compose_{uuid.uuid4().hex}"
35
39
  self._container_dict = container_dict
40
+ image_tag = config.fluent_image_tag
36
41
  self._image_name = (
37
42
  container_dict.get("fluent_image")
38
- or f"ghcr.io/ansys/pyfluent:{os.getenv('FLUENT_IMAGE_TAG')}"
43
+ or f"{get_ghcr_fluent_image_name(image_tag)}:{image_tag}"
39
44
  )
40
45
  self._container_source = self._set_compose_cmds()
41
46
  self._container_source.remove("compose")
42
47
 
43
48
  self._compose_file = self._get_compose_file(container_dict)
44
49
 
45
- def _is_podman_selected(self):
46
- return os.getenv("PYFLUENT_USE_PODMAN_COMPOSE") == "1"
47
-
48
50
  def _get_compose_file(self, container_dict):
49
51
  """Generates compose file for the Docker Compose setup.
50
52
 
@@ -129,14 +131,14 @@ class ComposeBasedLauncher:
129
131
  """
130
132
 
131
133
  # Determine the compose command
132
- if os.getenv("PYFLUENT_USE_PODMAN_COMPOSE") == "1":
134
+ if self._compose_config.use_podman_compose:
133
135
  self._compose_cmds = (
134
136
  ["sudo", "podman", "compose"]
135
137
  if hasattr(self, "_container_source")
136
138
  and "sudo" in self._container_source
137
139
  else ["podman", "compose"]
138
140
  )
139
- elif os.getenv("PYFLUENT_USE_DOCKER_COMPOSE") == "1":
141
+ elif self._compose_config.use_docker_compose:
140
142
  self._compose_cmds = ["docker", "compose"]
141
143
  else:
142
144
  raise RuntimeError("Neither Docker nor Podman is specified.")
@@ -148,7 +150,7 @@ class ComposeBasedLauncher:
148
150
  try:
149
151
  cmd = self._container_source + ["images", "-q", self._image_name]
150
152
  # Podman users do not always configure rootless mode in /etc/subuids and /etc/subgids
151
- if self._is_podman_selected():
153
+ if self._compose_config.use_podman_compose:
152
154
  sudo_cmd = ["sudo"] + cmd
153
155
  output_1 = subprocess.check_output(cmd)
154
156
  output_2 = subprocess.check_output(sudo_cmd)
@@ -0,0 +1,35 @@
1
+ # Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ """
24
+ Utility functions for working with Fluent Docker images.
25
+ """
26
+
27
+
28
+ def get_ghcr_fluent_image_name(image_tag: str):
29
+ """
30
+ Get the Fluent image name from GitHub registry based on the image tag.
31
+ """
32
+ if image_tag.startswith("sha256:") or image_tag >= "v26.1":
33
+ return "ghcr.io/ansys/fluent"
34
+ else:
35
+ return "ghcr.io/ansys/pyfluent"
@@ -49,16 +49,16 @@ def delete_downloads():
49
49
 
50
50
  Notes
51
51
  -----
52
- The default examples path is given by ``pyfluent.EXAMPLES_PATH``.
52
+ The default examples path is given by ``pyfluent.config.examples_path``.
53
53
  """
54
- shutil.rmtree(pyfluent.EXAMPLES_PATH)
55
- os.makedirs(pyfluent.EXAMPLES_PATH)
54
+ shutil.rmtree(pyfluent.config.examples_path)
55
+ os.makedirs(pyfluent.config.examples_path)
56
56
 
57
57
 
58
58
  def _decompress(file_name: str) -> None:
59
59
  """Decompress zipped file."""
60
60
  zip_ref = zipfile.ZipFile(file_name, "r")
61
- zip_ref.extractall(pyfluent.EXAMPLES_PATH)
61
+ zip_ref.extractall(pyfluent.config.examples_path)
62
62
  return zip_ref.close()
63
63
 
64
64
 
@@ -81,10 +81,7 @@ def _retrieve_file(
81
81
  """Download specified file from specified URL."""
82
82
  file_name = os.path.basename(file_name)
83
83
  if save_path is None:
84
- save_path = os.getenv(
85
- "PYFLUENT_CONTAINER_MOUNT_SOURCE",
86
- pyfluent.CONTAINER_MOUNT_SOURCE or os.getcwd(),
87
- )
84
+ save_path = pyfluent.config.container_mount_source or os.getcwd()
88
85
  else:
89
86
  save_path = os.path.abspath(save_path)
90
87
  local_path = os.path.join(save_path, file_name)
@@ -180,8 +177,8 @@ def download_file(
180
177
  'bracket.iges'
181
178
  """
182
179
  if return_without_path is None:
183
- if os.getenv("PYFLUENT_LAUNCH_CONTAINER") == "1":
184
- if pyfluent.USE_FILE_TRANSFER_SERVICE:
180
+ if pyfluent.config.launch_fluent_container:
181
+ if pyfluent.config.use_file_transfer_service:
185
182
  return_without_path = False
186
183
  else:
187
184
  return_without_path = True
@@ -212,7 +209,7 @@ def path(file_name: str):
212
209
  """
213
210
  if os.path.isabs(file_name):
214
211
  return file_name
215
- file_path = Path(pyfluent.EXAMPLES_PATH) / file_name
212
+ file_path = Path(pyfluent.config.examples_path) / file_name
216
213
  if file_path.is_file():
217
214
  return str(file_path)
218
215
  else:
@@ -34,7 +34,7 @@ class DisallowedValuesError(ValueError):
34
34
  context: str | None = None,
35
35
  name: Any | None = None,
36
36
  allowed_values: Iterable[Any] | None = None,
37
- ):
37
+ ) -> None:
38
38
  """Initialize DisallowedValuesError."""
39
39
  super().__init__(
40
40
  allowed_name_error_message(
@@ -50,3 +50,15 @@ class InvalidArgument(ValueError):
50
50
  """Raised when an argument value is inappropriate."""
51
51
 
52
52
  pass
53
+
54
+
55
+ class BetaFeaturesNotEnabled(RuntimeError):
56
+ """Raised when a beta feature is accessed without enabling beta features."""
57
+
58
+ def __init__(self, feature_name: str | None = None) -> None:
59
+ message = (
60
+ f"The feature '{feature_name}' is not available until 'enable_beta_features()' has been called."
61
+ if feature_name
62
+ else "This feature is not available until 'enable_beta_features()' has been called."
63
+ )
64
+ super().__init__(message)