ansys-fluent-core 0.30.dev2__py3-none-any.whl → 0.30.dev3__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 (76) hide show
  1. ansys/fluent/core/__init__.py +14 -3
  2. ansys/fluent/core/codegen/datamodelgen.py +17 -3
  3. ansys/fluent/core/codegen/settingsgen.py +26 -4
  4. ansys/fluent/core/codegen/walk_api.py +11 -1
  5. ansys/fluent/core/exceptions.py +7 -4
  6. ansys/fluent/core/generated/api_tree/api_objects.json +1 -1
  7. ansys/fluent/core/generated/datamodel_242/meshing_utilities.pyi +990 -0
  8. ansys/fluent/core/generated/datamodel_251/meshing_utilities.pyi +1002 -0
  9. ansys/fluent/core/generated/datamodel_252/meshing.py +7 -0
  10. ansys/fluent/core/generated/datamodel_252/meshing_utilities.pyi +1007 -0
  11. ansys/fluent/core/generated/datamodel_252/preferences.py +132 -3
  12. ansys/fluent/core/generated/fluent_version_252.py +3 -3
  13. ansys/fluent/core/generated/meshing/tui_252.py +111 -12
  14. ansys/fluent/core/generated/solver/settings_222.py +166 -170
  15. ansys/fluent/core/generated/solver/settings_222.pyi +10 -8
  16. ansys/fluent/core/generated/solver/settings_231.py +551 -598
  17. ansys/fluent/core/generated/solver/settings_231.pyi +40 -38
  18. ansys/fluent/core/generated/solver/settings_232.py +689 -736
  19. ansys/fluent/core/generated/solver/settings_232.pyi +39 -37
  20. ansys/fluent/core/generated/solver/settings_241.py +1365 -1439
  21. ansys/fluent/core/generated/solver/settings_241.pyi +1071 -1074
  22. ansys/fluent/core/generated/solver/settings_242.py +2852 -3098
  23. ansys/fluent/core/generated/solver/settings_242.pyi +2059 -2151
  24. ansys/fluent/core/generated/solver/settings_251.py +3656 -3914
  25. ansys/fluent/core/generated/solver/settings_251.pyi +2915 -3008
  26. ansys/fluent/core/generated/solver/settings_252.py +5894 -5707
  27. ansys/fluent/core/generated/solver/settings_252.pyi +4411 -4297
  28. ansys/fluent/core/generated/solver/tui_252.py +205 -25
  29. ansys/fluent/core/get_build_details.py +2 -2
  30. ansys/fluent/core/launcher/container_launcher.py +7 -1
  31. ansys/fluent/core/launcher/fluent_container.py +3 -2
  32. ansys/fluent/core/launcher/pim_launcher.py +7 -1
  33. ansys/fluent/core/launcher/slurm_launcher.py +7 -1
  34. ansys/fluent/core/launcher/standalone_launcher.py +7 -1
  35. ansys/fluent/core/services/datamodel_se.py +28 -23
  36. ansys/fluent/core/services/field_data.py +17 -5
  37. ansys/fluent/core/session_base_meshing.py +3 -3
  38. ansys/fluent/core/session_meshing.py +4 -4
  39. ansys/fluent/core/session_meshing.pyi +9 -9
  40. ansys/fluent/core/session_pure_meshing.pyi +9 -9
  41. ansys/fluent/core/session_solver.py +1 -1
  42. ansys/fluent/core/session_solver.pyi +5 -5
  43. ansys/fluent/core/solver/_docstrings.py +244 -0
  44. ansys/fluent/core/solver/error_message.py +7 -12
  45. ansys/fluent/core/solver/flobject.py +40 -15
  46. ansys/fluent/core/utils/fluent_version.py +2 -3
  47. ansys/fluent/core/workflow.py +1 -0
  48. {ansys_fluent_core-0.30.dev2.dist-info → ansys_fluent_core-0.30.dev3.dist-info}/METADATA +4 -4
  49. {ansys_fluent_core-0.30.dev2.dist-info → ansys_fluent_core-0.30.dev3.dist-info}/RECORD +75 -72
  50. ansys/fluent/core/_version.py +0 -40
  51. /ansys/fluent/core/generated/datamodel_222/{PartManagement.py → part_management.py} +0 -0
  52. /ansys/fluent/core/generated/datamodel_222/{PMFileManagement.py → pm_file_management.py} +0 -0
  53. /ansys/fluent/core/generated/datamodel_231/{PartManagement.py → part_management.py} +0 -0
  54. /ansys/fluent/core/generated/datamodel_231/{PMFileManagement.py → pm_file_management.py} +0 -0
  55. /ansys/fluent/core/generated/datamodel_231/{solverworkflow.py → solver_workflow.py} +0 -0
  56. /ansys/fluent/core/generated/datamodel_232/{PartManagement.py → part_management.py} +0 -0
  57. /ansys/fluent/core/generated/datamodel_232/{PMFileManagement.py → pm_file_management.py} +0 -0
  58. /ansys/fluent/core/generated/datamodel_232/{solverworkflow.py → solver_workflow.py} +0 -0
  59. /ansys/fluent/core/generated/datamodel_241/{PartManagement.py → part_management.py} +0 -0
  60. /ansys/fluent/core/generated/datamodel_241/{PMFileManagement.py → pm_file_management.py} +0 -0
  61. /ansys/fluent/core/generated/datamodel_241/{solverworkflow.py → solver_workflow.py} +0 -0
  62. /ansys/fluent/core/generated/datamodel_242/{MeshingUtilities.py → meshing_utilities.py} +0 -0
  63. /ansys/fluent/core/generated/datamodel_242/{PartManagement.py → part_management.py} +0 -0
  64. /ansys/fluent/core/generated/datamodel_242/{PMFileManagement.py → pm_file_management.py} +0 -0
  65. /ansys/fluent/core/generated/datamodel_242/{solverworkflow.py → solver_workflow.py} +0 -0
  66. /ansys/fluent/core/generated/datamodel_251/{MeshingUtilities.py → meshing_utilities.py} +0 -0
  67. /ansys/fluent/core/generated/datamodel_251/{PartManagement.py → part_management.py} +0 -0
  68. /ansys/fluent/core/generated/datamodel_251/{PMFileManagement.py → pm_file_management.py} +0 -0
  69. /ansys/fluent/core/generated/datamodel_251/{solverworkflow.py → solver_workflow.py} +0 -0
  70. /ansys/fluent/core/generated/datamodel_252/{MeshingUtilities.py → meshing_utilities.py} +0 -0
  71. /ansys/fluent/core/generated/datamodel_252/{PartManagement.py → part_management.py} +0 -0
  72. /ansys/fluent/core/generated/datamodel_252/{PMFileManagement.py → pm_file_management.py} +0 -0
  73. /ansys/fluent/core/generated/datamodel_252/{solverworkflow.py → solver_workflow.py} +0 -0
  74. /ansys/fluent/core/{systemcoupling.py → system_coupling.py} +0 -0
  75. {ansys_fluent_core-0.30.dev2.dist-info → ansys_fluent_core-0.30.dev3.dist-info}/LICENSE +0 -0
  76. {ansys_fluent_core-0.30.dev2.dist-info → ansys_fluent_core-0.30.dev3.dist-info}/WHEEL +0 -0
@@ -334,11 +334,19 @@ class _AllowedSurfaceNames(_AllowedNames):
334
334
 
335
335
  Raises
336
336
  ------
337
+ RuntimeError
338
+ If issue in retrieving surface list.
337
339
  DisallowedValuesError
338
340
  If surface name is invalid.
339
341
  """
340
- if validate_inputs and not self.is_valid(surface_name):
341
- raise DisallowedValuesError("surface", surface_name, self())
342
+ try:
343
+ valid_names = self() # Fetch once, upfront
344
+ except Exception as e:
345
+ raise RuntimeError("Failed to retrieve valid surface names.") from e
346
+
347
+ if validate_inputs and surface_name not in valid_names:
348
+ raise DisallowedValuesError("surface", surface_name, valid_names)
349
+
342
350
  return surface_name
343
351
 
344
352
 
@@ -726,7 +734,7 @@ class FieldTransaction:
726
734
  [
727
735
  FieldDataProtoModule.PathlinesFieldRequest(
728
736
  surfaceId=surface_id,
729
- field=field_name,
737
+ field=self._allowed_scalar_field_names.valid_name(field_name),
730
738
  additionalField=additional_field_name,
731
739
  provideParticleTimeField=provide_particle_time_field,
732
740
  dataLocation=(
@@ -818,7 +826,11 @@ def _get_surface_ids(
818
826
  ]
819
827
  )
820
828
  else:
821
- surface_ids.append(surf)
829
+ allowed_surf_ids = _AllowedSurfaceIDs(field_info)()
830
+ if surf in allowed_surf_ids:
831
+ surface_ids.append(surf)
832
+ else:
833
+ raise DisallowedValuesError("surface", surf, allowed_surf_ids)
822
834
  return surface_ids
823
835
 
824
836
 
@@ -1437,7 +1449,7 @@ class FieldData:
1437
1449
  [
1438
1450
  FieldDataProtoModule.PathlinesFieldRequest(
1439
1451
  surfaceId=surface_id,
1440
- field=field_name,
1452
+ field=self._allowed_scalar_field_names.valid_name(field_name),
1441
1453
  additionalField=additional_field_name,
1442
1454
  provideParticleTimeField=provide_particle_time_field,
1443
1455
  dataLocation=(
@@ -118,10 +118,10 @@ class BaseMeshing:
118
118
  from ansys.fluent.core import CODEGEN_OUTDIR
119
119
 
120
120
  meshing_utilities_module = pyfluent.utils.load_module(
121
- f"MeshingUtilities_{self._version}",
121
+ f"meshing_utilities_{self._version}",
122
122
  CODEGEN_OUTDIR
123
123
  / f"datamodel_{self._version}"
124
- / "MeshingUtilities.py",
124
+ / "meshing_utilities.py",
125
125
  )
126
126
  meshing_utilities_root = meshing_utilities_module.Root(
127
127
  self._se_service, "MeshingUtilities", []
@@ -130,7 +130,7 @@ class BaseMeshing:
130
130
  datamodel_logger.warning(_CODEGEN_MSG_DATAMODEL)
131
131
  if self.get_fluent_version() >= FluentVersion.v242:
132
132
  meshing_utilities_root = PyMenuGeneric(
133
- self._se_service, "meshing_utilities"
133
+ self._se_service, "MeshingUtilities"
134
134
  )
135
135
  return meshing_utilities_root
136
136
 
@@ -64,7 +64,7 @@ class Meshing(PureMeshing):
64
64
  transcript can be subsequently started and stopped
65
65
  using method calls on the ``Session`` object.
66
66
  """
67
- self.switched = False
67
+ self._switched = False
68
68
  super(Meshing, self).__init__(
69
69
  fluent_connection=fluent_connection,
70
70
  scheme_eval=scheme_eval,
@@ -89,14 +89,14 @@ class Meshing(PureMeshing):
89
89
  scheme_eval=self.scheme_eval,
90
90
  file_transfer_service=self._file_transfer_service,
91
91
  )
92
- self.switched = True
92
+ self._switched = True
93
93
  return solver_session
94
94
 
95
95
  def __getattribute__(self, item: str):
96
- if item == "switched":
96
+ if item == "_switched":
97
97
  return super(Meshing, self).__getattribute__(item)
98
98
 
99
- if self.switched and item != "exit":
99
+ if self._switched and item != "exit":
100
100
  return None
101
101
 
102
102
  return super(Meshing, self).__getattribute__(item)
@@ -20,21 +20,21 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- from ansys.fluent.core.generated.datamodel_242.MeshingUtilities import (
23
+ from ansys.fluent.core.generated.datamodel_251.meshing import Root as meshing_root
24
+ from ansys.fluent.core.generated.datamodel_251.meshing_utilities import (
24
25
  Root as meshing_utilities_root,
25
26
  )
26
- from ansys.fluent.core.generated.datamodel_242.PMFileManagement import (
27
- Root as pmfilemanagement_root,
28
- )
29
- from ansys.fluent.core.generated.datamodel_242.PartManagement import (
27
+ from ansys.fluent.core.generated.datamodel_251.part_management import (
30
28
  Root as partmanagement_root,
31
29
  )
32
- from ansys.fluent.core.generated.datamodel_242.meshing import Root as meshing_root
33
- from ansys.fluent.core.generated.datamodel_242.preferences import (
30
+ from ansys.fluent.core.generated.datamodel_251.pm_file_management import (
31
+ Root as pmfilemanagement_root,
32
+ )
33
+ from ansys.fluent.core.generated.datamodel_251.preferences import (
34
34
  Root as preferences_root,
35
35
  )
36
- from ansys.fluent.core.generated.datamodel_242.workflow import Root as workflow_root
37
- from ansys.fluent.core.generated.meshing.tui_242 import main_menu
36
+ from ansys.fluent.core.generated.datamodel_251.workflow import Root as workflow_root
37
+ from ansys.fluent.core.generated.meshing.tui_251 import main_menu
38
38
 
39
39
  class Meshing:
40
40
  @property
@@ -20,21 +20,21 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- from ansys.fluent.core.generated.datamodel_242.MeshingUtilities import (
23
+ from ansys.fluent.core.generated.datamodel_251.meshing import Root as meshing_root
24
+ from ansys.fluent.core.generated.datamodel_251.meshing_utilities import (
24
25
  Root as meshing_utilities_root,
25
26
  )
26
- from ansys.fluent.core.generated.datamodel_242.PMFileManagement import (
27
- Root as pmfilemanagement_root,
28
- )
29
- from ansys.fluent.core.generated.datamodel_242.PartManagement import (
27
+ from ansys.fluent.core.generated.datamodel_251.part_management import (
30
28
  Root as partmanagement_root,
31
29
  )
32
- from ansys.fluent.core.generated.datamodel_242.meshing import Root as meshing_root
33
- from ansys.fluent.core.generated.datamodel_242.preferences import (
30
+ from ansys.fluent.core.generated.datamodel_251.pm_file_management import (
31
+ Root as pmfilemanagement_root,
32
+ )
33
+ from ansys.fluent.core.generated.datamodel_251.preferences import (
34
34
  Root as preferences_root,
35
35
  )
36
- from ansys.fluent.core.generated.datamodel_242.workflow import Root as workflow_root
37
- from ansys.fluent.core.generated.meshing.tui_242 import main_menu
36
+ from ansys.fluent.core.generated.datamodel_251.workflow import Root as workflow_root
37
+ from ansys.fluent.core.generated.meshing.tui_251 import main_menu
38
38
 
39
39
  class PureMeshing:
40
40
  @property
@@ -54,7 +54,7 @@ from ansys.fluent.core.solver.flobject import (
54
54
  import ansys.fluent.core.solver.function.reduction as reduction_old
55
55
  from ansys.fluent.core.streaming_services.events_streaming import SolverEvent
56
56
  from ansys.fluent.core.streaming_services.monitor_streaming import MonitorsManager
57
- from ansys.fluent.core.systemcoupling import SystemCoupling
57
+ from ansys.fluent.core.system_coupling import SystemCoupling
58
58
  from ansys.fluent.core.utils.execution import asynchronous
59
59
  from ansys.fluent.core.utils.fluent_version import (
60
60
  FluentVersion,
@@ -20,13 +20,13 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
- from ansys.fluent.core.generated.datamodel_242.preferences import (
23
+ from ansys.fluent.core.generated.datamodel_251.preferences import (
24
24
  Root as preferences_root,
25
25
  )
26
- from ansys.fluent.core.generated.datamodel_242.workflow import Root as workflow_root
27
- import ansys.fluent.core.generated.solver.settings_242 as settings_root
28
- from ansys.fluent.core.generated.solver.tui_242 import main_menu
29
- from ansys.fluent.core.systemcoupling import SystemCoupling
26
+ from ansys.fluent.core.generated.datamodel_251.workflow import Root as workflow_root
27
+ import ansys.fluent.core.generated.solver.settings_251 as settings_root
28
+ from ansys.fluent.core.generated.solver.tui_251 import main_menu
29
+ from ansys.fluent.core.system_coupling import SystemCoupling
30
30
 
31
31
  class Solver:
32
32
  @property
@@ -0,0 +1,244 @@
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
+ """Module for analyzing API docstrings."""
24
+
25
+ # N.b. misspellings:
26
+ # - selected missing last e.
27
+ # - many known API misspellings also have corresponding
28
+ # misspellingling for docstring.
29
+ # - CGSN
30
+
31
+ import re
32
+
33
+ _choose_words = ("Choose", "Indicate", "Select", "Specify")
34
+
35
+ _remove_first_words = _choose_words + ("Enter", "Set", "To")
36
+
37
+ # Define problematic patterns with exclusions
38
+ _dubious_patterns = [
39
+ (r"Create an instance of this.", ()),
40
+ (r"Enter the adaption .* menu.", ()),
41
+ (r"Allows you to .*", ()),
42
+ (r"Select to .*", ("method",)),
43
+ (r"Choose .*", ("method",)),
44
+ (r"Enter .*", ("method",)),
45
+ (r"Indicate .*", ("method",)),
46
+ (r"Perform .*", ("method",)),
47
+ (r"Select .*", ("method",)),
48
+ (r"Set .*", ("method",)),
49
+ (r"Specify .*", ("method",)),
50
+ (r".* menu.", ()),
51
+ (r"To .*", ()),
52
+ (r"Name for an object.*", ()),
53
+ ]
54
+
55
+ # Rewriting problematic patterns for suggestions
56
+
57
+ _bad_0 = {
58
+ r"Create an instance of this.": r"Create a new instance of the current object type.",
59
+ r"Allows you to (.*)": r"\1",
60
+ }
61
+
62
+ _bad_1 = {
63
+ rf"{w} (whether or not|whether|if) (.*)": r"Specifies whether \2"
64
+ for w in _choose_words
65
+ }
66
+
67
+ _bad_2 = {
68
+ r"Select to (.*)": r"Specifies whether to \1",
69
+ r"Perform (.*)": r"Specifies whether to perform \1",
70
+ r"Enter a (.*)": r"The \1",
71
+ r"Enter an (.*)": r"The \1",
72
+ r"(.*) menu.": r"\1 object.",
73
+ }
74
+
75
+ _bad_3 = {rf"{w} (.*)": r"\1" for w in _remove_first_words}
76
+
77
+ _bad_4 = {r"Name for an object(.*)": r"Object name\1"}
78
+
79
+ _bad_to_suggested = dict(**_bad_0, **_bad_1, **_bad_2, **_bad_3, **_bad_4)
80
+
81
+ # Pre-compile fixed-format empty patterns (case-sensitive)
82
+ _empty_patterns = [
83
+ re.compile(f"'.*' {item}.") for item in ("child", "command", "query")
84
+ ]
85
+
86
+
87
+ def _suggest_fix(docstring: str):
88
+ """Suggest an improved version of a problematic docstring."""
89
+ for bad, suggestion in _bad_to_suggested.items():
90
+ match = re.match(bad, docstring)
91
+ if match:
92
+ replacement = match.expand(suggestion)
93
+
94
+ # Capitalize if original docstring started with a capital letter
95
+ if docstring[0].isupper():
96
+ replacement = replacement[0].upper() + replacement[1:]
97
+
98
+ # Ensure we don't add duplicate periods
99
+ if replacement.endswith("."):
100
+ return replacement
101
+ return replacement + "."
102
+
103
+ return None # No fix available
104
+
105
+
106
+ def _fixed_doc_string(api_item_type, docstring):
107
+ for pattern_str, exclude_types in _dubious_patterns:
108
+ if api_item_type in exclude_types:
109
+ continue
110
+
111
+ if re.match(pattern_str, docstring):
112
+ fix = _suggest_fix(docstring)
113
+ new_fix = None
114
+ if fix:
115
+ new_fix = _fixed_doc_string(api_item_type, fix)
116
+ return new_fix or fix
117
+
118
+ return None
119
+
120
+
121
+ class _DocStringAnalysis:
122
+ """Analyzes docstrings for potential issues and categorizes them."""
123
+
124
+ def __init__(self):
125
+ """Initialize storage for categorized docstring issues."""
126
+ self.dubious = {}
127
+ self.empty = {}
128
+ self.clean = {}
129
+
130
+ def analyse(self, api_path: str, api_item_type: str, api_cls: object):
131
+ """Extract and analyze the docstring for a given API item."""
132
+ docstring = self.get_basic_docstring(api_cls)
133
+ self.analyse_docstring(api_path, api_item_type, docstring)
134
+
135
+ def analyse_docstring(self, api_path: str, api_item_type: str, docstring: str):
136
+ """Analyze a docstring and categorize it as clean, dubious, or empty."""
137
+
138
+ # Check for empty docstrings first (case-sensitive)
139
+ for pattern in _empty_patterns:
140
+ if pattern.match(docstring):
141
+ self.empty[api_path] = (api_item_type, docstring)
142
+ return
143
+
144
+ # Check for dubious patterns
145
+ # TODO just use None?
146
+ fix = _fixed_doc_string(api_item_type, docstring)
147
+ if fix:
148
+ self.dubious[api_path] = (api_item_type, docstring, fix)
149
+ return
150
+
151
+ # If no issues, classify as clean
152
+ self.clean[api_path] = (api_item_type, docstring)
153
+
154
+ def get_basic_docstring(self, api_cls: object):
155
+ """Extract and clean a class docstring, handling None values."""
156
+ raw_docstring = api_cls.__doc__ or ""
157
+ docstring = "".join(raw_docstring.splitlines()).strip()
158
+
159
+ # Remove parameters section if present
160
+ params_section = " Parameters ---------- "
161
+ idx = docstring.find(params_section)
162
+ return docstring[:idx] if idx != -1 else docstring
163
+
164
+ def show_results(self):
165
+ """Print a categorized summary of analyzed docstrings."""
166
+ print("\nSummary:\n")
167
+ for label, result in [
168
+ ("Empty", self.empty),
169
+ ("Dubious", self.dubious),
170
+ ("Clean", self.clean),
171
+ ]:
172
+ count = len(result)
173
+ print(f"{label}: {count}")
174
+ if label == "Dubious":
175
+ fix_count = len([i for i in result.values() if i[2]])
176
+ print(
177
+ f"\tNumber with/without suggested fixes: {fix_count}/{count - fix_count}"
178
+ )
179
+
180
+ print("\nDetailed results:")
181
+ for label, result in [
182
+ ("Empty", self.empty),
183
+ ("Dubious", self.dubious),
184
+ ("Clean", self.clean),
185
+ ]:
186
+ print(f"\n{label} ({len(result)}):")
187
+ for k, (t, s, *extra) in result.items():
188
+ print(f"{k} ({t}):")
189
+ print(f"\t{s}")
190
+
191
+ # Suggest fixes for dubious patterns
192
+ if label == "Dubious" and extra:
193
+ suggested = extra[0]
194
+ if suggested:
195
+ print(f"\tSuggested Fix: {suggested}")
196
+ else:
197
+ print("\tNo suggested fix")
198
+
199
+
200
+ def show_all_doc_strings(api_path: str, api_item_type: str, api_cls: object):
201
+ """Prints all docstrings for debugging."""
202
+ indent = " " * (api_path.count("."))
203
+ bullet = f"{indent}-"
204
+
205
+ print(f"{bullet} item: {api_path.split('.')[-1]}")
206
+ print(f"{bullet} type: {api_item_type}")
207
+ print(f"{bullet} docstring: {api_cls.__doc__}")
208
+
209
+
210
+ if __name__ == "__main__":
211
+ import argparse
212
+ import importlib
213
+
214
+ from ansys.fluent.core.codegen import walk_api
215
+
216
+ # Sample Usage
217
+ #
218
+ # Whole Fluent settings API check with default settings
219
+ # >>> python src\ansys\fluent\core\solver\_docstrings.py --api-version=252
220
+
221
+ parser = argparse.ArgumentParser()
222
+ parser.add_argument("--cls", dest="api_cls", type=str, default="root")
223
+ parser.add_argument("--path", dest="api_path", type=str, default="")
224
+ parser.add_argument("--output-type", dest="output_type", type=str, default="stats")
225
+ parser.add_argument("--api-version", dest="api_version", type=str, default="")
226
+
227
+ args = parser.parse_args()
228
+
229
+ api_cls = args.api_cls
230
+ api_path = args.api_path
231
+ output_type = args.output_type
232
+ api_version = args.api_version
233
+
234
+ mod = importlib.import_module(
235
+ name=f"ansys.fluent.core.generated.solver.settings_{api_version}"
236
+ )
237
+ cls = getattr(mod, api_cls)
238
+
239
+ if output_type == "show":
240
+ walk_api.walk_api(cls, show_all_doc_strings, api_path)
241
+ elif output_type == "stats":
242
+ analysis = _DocStringAnalysis()
243
+ walk_api.walk_api(cls, analysis.analyse, api_path)
244
+ analysis.show_results()
@@ -24,45 +24,40 @@
24
24
 
25
25
  import difflib
26
26
  from functools import partial
27
- from typing import Any, List
27
+ from typing import Any, Iterable
28
28
 
29
29
 
30
- def closest_allowed_names(trial_name: str, allowed_names: str) -> List[str]:
30
+ def closest_allowed_names(trial_name: str, allowed_names: Iterable[str]) -> list[str]:
31
31
  """Checks if the 'trail_name' is closely matching the 'allowed_names'."""
32
32
  f = partial(difflib.get_close_matches, trial_name, allowed_names)
33
33
  return f(cutoff=0.6, n=5) or f(cutoff=0.3, n=1)
34
34
 
35
35
 
36
36
  def allowed_name_error_message(
37
- allowed_values: Any | None = None,
37
+ allowed_values: Iterable[Any] | None = None,
38
38
  context: str | None = None,
39
- trial_name: str | None = None,
39
+ trial_name: Any | None = None,
40
40
  message: str | None = None,
41
- search_results: list | None = None,
42
41
  ) -> str:
43
42
  """Provide an error message with the closest names matching the 'trial_name' from
44
43
  the 'allowed_values' list."""
45
44
  if not message:
46
45
  message = f"'{context}' has no attribute '{trial_name}'"
47
46
  message += ".\n"
48
- matches = None
49
47
  if allowed_values:
50
- if isinstance(allowed_values, list) and isinstance(allowed_values[0], str):
48
+ matches = None
49
+ if all(isinstance(item, str) for item in allowed_values) and allowed_values:
51
50
  matches = closest_allowed_names(trial_name, allowed_values)
52
51
  if matches:
53
52
  message += f"The most similar names are: {', '.join(matches)}."
54
53
  else:
55
54
  message += f"The allowed values are: {allowed_values}."
56
- elif search_results:
57
- message = message + "\nThe most similar API names are:\n"
58
- for search_result in search_results:
59
- message += search_result + "\n"
60
55
 
61
56
  return message
62
57
 
63
58
 
64
59
  def allowed_values_error(
65
- context: str, trial_name: str, allowed_values: List[str]
60
+ context: str, trial_name: str, allowed_values: Iterable[str | int]
66
61
  ) -> ValueError:
67
62
  """Provide an error message for disallowed values."""
68
63
  return ValueError(
@@ -69,13 +69,13 @@ from typing import (
69
69
  import warnings
70
70
  import weakref
71
71
 
72
- import ansys.fluent.core as pyfluent
73
72
  from ansys.fluent.core.pyfluent_warnings import (
74
73
  PyFluentDeprecationWarning,
75
74
  PyFluentUserWarning,
76
75
  )
77
76
  from ansys.fluent.core.utils.fluent_version import FluentVersion
78
77
 
78
+ from . import _docstrings
79
79
  from .error_message import allowed_name_error_message, allowed_values_error
80
80
  from .flunits import UnhandledQuantity, get_si_unit_for_fluent_quantity
81
81
  from .settings_external import expand_api_file_argument
@@ -695,9 +695,14 @@ class _Alias:
695
695
 
696
696
  def _create_child(cls, name, parent: weakref.CallableProxyType, alias_path=None):
697
697
  if alias_path or isinstance(parent, _Alias):
698
+ bases = (cls,)
699
+ # True child of parent alias is already derived from _Alias.
700
+ # Avoiding duplicate derivation and mro resolution issue.
701
+ if _Alias not in cls.__mro__:
702
+ bases = (_Alias, cls)
698
703
  alias_cls = type(
699
704
  f"{cls.__name__}_alias",
700
- (_Alias, cls),
705
+ bases,
701
706
  dict(cls.__dict__) | {"alias_path": alias_path},
702
707
  )
703
708
  return alias_cls(name, parent.__repr__.__self__)
@@ -945,6 +950,23 @@ def _command_query_name_filter(
945
950
  return ret
946
951
 
947
952
 
953
+ def _get_type_for_completer_info(cls) -> str:
954
+ if issubclass(cls, (FileName, _InputFile)):
955
+ return "InputFilename"
956
+ elif issubclass(cls, (FileName, _OutputFile)):
957
+ return "OutputFilename"
958
+ elif issubclass(cls, (FileName, _InOutFile)):
959
+ return "InOutFilename"
960
+ elif issubclass(cls, (FilenameList, _InputFile)):
961
+ return "InputFilenameList"
962
+ elif issubclass(cls, (FilenameList, _OutputFile)):
963
+ return "OutputFilenameList"
964
+ elif issubclass(cls, (FilenameList, _InOutFile)):
965
+ return "InOutFilenameList"
966
+ else:
967
+ return cls.__bases__[0].__name__
968
+
969
+
948
970
  class Group(SettingsBase[DictStateType]):
949
971
  """A ``Group`` container object.
950
972
 
@@ -1073,7 +1095,7 @@ class Group(SettingsBase[DictStateType]):
1073
1095
  ret.append(
1074
1096
  [
1075
1097
  child_name,
1076
- child.__class__.__bases__[0].__name__,
1098
+ _get_type_for_completer_info(child.__class__),
1077
1099
  child.__doc__,
1078
1100
  ]
1079
1101
  )
@@ -1105,18 +1127,12 @@ class Group(SettingsBase[DictStateType]):
1105
1127
  attr._check_stable()
1106
1128
  return attr
1107
1129
  except AttributeError as ex:
1108
- pyfluent.PRINT_SEARCH_RESULTS = False
1109
- search_results = pyfluent.utils.search(
1110
- search_string=name,
1111
- match_case=False,
1112
- match_whole_word=False,
1113
- )
1114
- pyfluent.PRINT_SEARCH_RESULTS = True
1115
- results = search_results if search_results else []
1116
1130
  error_msg = allowed_name_error_message(
1117
1131
  trial_name=name,
1118
1132
  message=ex.args[0],
1119
- search_results=results,
1133
+ allowed_values=sorted(
1134
+ set(self.get_active_child_names() + self.command_names)
1135
+ ),
1120
1136
  )
1121
1137
  ex.args = (error_msg,)
1122
1138
  raise
@@ -1625,7 +1641,7 @@ class Action(Base):
1625
1641
  ret.append(
1626
1642
  [
1627
1643
  argument_name,
1628
- argument.__class__.__bases__[0].__name__,
1644
+ _get_type_for_completer_info(argument.__class__),
1629
1645
  argument.__doc__,
1630
1646
  ]
1631
1647
  )
@@ -1809,13 +1825,22 @@ _baseTypes = {
1809
1825
 
1810
1826
 
1811
1827
  def _clean_helpinfo(helpinfo):
1812
- helpinfo = helpinfo.strip("\n")
1828
+ helpinfo = helpinfo.strip("\n").lstrip(" ")
1813
1829
  if not helpinfo.endswith("."):
1814
1830
  helpinfo += "."
1815
1831
  helpinfo = helpinfo[0].upper() + helpinfo[1:]
1816
1832
  return helpinfo
1817
1833
 
1818
1834
 
1835
+ def _fix_help_info(obj_type, helpinfo):
1836
+ # The else clause is just picking "object" due to our current
1837
+ # knowledge that the implementation only distinguishes between
1838
+ # "method" and everything else. This is fragile.
1839
+ api_item_type = "method" if obj_type in ("command", "query") else "object"
1840
+ fix = _docstrings._fixed_doc_string(api_item_type, helpinfo)
1841
+ return fix or helpinfo
1842
+
1843
+
1819
1844
  class _ChildNamedObjectAccessorMixin(collections.abc.MutableMapping):
1820
1845
  """A mixin class to provide a dictionary interface at a Group class level if the
1821
1846
  Group has multiple named objects of a similar type. For example, boundary conditions
@@ -1983,7 +2008,7 @@ def get_cls(name, info, parent=None, version=None, parent_taboo=None):
1983
2008
  dct = {"fluent_name": name, "version": version}
1984
2009
  helpinfo = info.get("help")
1985
2010
  if helpinfo:
1986
- dct["__doc__"] = _clean_helpinfo(helpinfo)
2011
+ dct["__doc__"] = _fix_help_info(obj_type, _clean_helpinfo(helpinfo))
1987
2012
  else:
1988
2013
  if parent is None:
1989
2014
  dct["__doc__"] = "'root' object."
@@ -27,7 +27,6 @@ from functools import total_ordering
27
27
  import os
28
28
 
29
29
  import ansys.fluent.core as pyfluent
30
- from ansys.fluent.core._version import fluent_dev_version, fluent_release_version
31
30
 
32
31
 
33
32
  class AnsysVersionNotFound(RuntimeError):
@@ -131,7 +130,7 @@ class FluentVersion(Enum):
131
130
  FluentVersion
132
131
  FluentVersion member corresponding to the latest release.
133
132
  """
134
- return cls(fluent_release_version)
133
+ return cls(pyfluent.FLUENT_RELEASE_VERSION)
135
134
 
136
135
  @classmethod
137
136
  def current_dev(cls):
@@ -142,7 +141,7 @@ class FluentVersion(Enum):
142
141
  FluentVersion
143
142
  FluentVersion member corresponding to the latest development version.
144
143
  """
145
- return cls(fluent_dev_version)
144
+ return cls(pyfluent.FLUENT_DEV_VERSION)
146
145
 
147
146
  @property
148
147
  def awp_var(self):
@@ -1365,6 +1365,7 @@ class Workflow:
1365
1365
  "service",
1366
1366
  "task_object",
1367
1367
  "workflow",
1368
+ "rename",
1368
1369
  },
1369
1370
  _fluent_version=fluent_version,
1370
1371
  )