ansys-fluent-core 0.35.dev0__py3-none-any.whl → 0.36.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.
- ansys/fluent/core/__init__.py +2 -2
- ansys/fluent/core/codegen/__init__.py +1 -0
- ansys/fluent/core/codegen/builtin_settingsgen.py +4 -0
- ansys/fluent/core/codegen/datamodelgen.py +13 -2
- ansys/fluent/core/codegen/settingsgen.py +7 -0
- ansys/fluent/core/docker/docker_compose.py +30 -1
- ansys/fluent/core/examples/downloads.py +3 -4
- ansys/fluent/core/fluent_connection.py +2 -3
- ansys/fluent/core/generated/api_tree/api_objects.json +1 -1
- ansys/fluent/core/generated/datamodel_231/flicing.py +20 -20
- ansys/fluent/core/generated/datamodel_231/meshing.py +236 -236
- ansys/fluent/core/generated/datamodel_232/flicing.py +50 -50
- ansys/fluent/core/generated/datamodel_232/meshing.py +187 -187
- ansys/fluent/core/generated/datamodel_241/flicing.py +45 -45
- ansys/fluent/core/generated/datamodel_241/meshing.py +229 -229
- ansys/fluent/core/generated/datamodel_242/flicing.py +50 -50
- ansys/fluent/core/generated/datamodel_242/meshing.py +275 -275
- ansys/fluent/core/generated/datamodel_242/part_management.py +3 -3
- ansys/fluent/core/generated/datamodel_251/flicing.py +45 -45
- ansys/fluent/core/generated/datamodel_251/meshing.py +417 -417
- ansys/fluent/core/generated/datamodel_251/part_management.py +9 -9
- ansys/fluent/core/generated/datamodel_252/flicing.py +30 -30
- ansys/fluent/core/generated/datamodel_252/meshing.py +418 -418
- ansys/fluent/core/generated/datamodel_252/part_management.py +5 -5
- ansys/fluent/core/generated/datamodel_261/flicing.py +35 -35
- ansys/fluent/core/generated/datamodel_261/meshing.py +481 -425
- ansys/fluent/core/generated/datamodel_261/meshing_utilities.py +296 -616
- ansys/fluent/core/generated/datamodel_261/meshing_workflow.py +61694 -0
- ansys/fluent/core/generated/datamodel_261/part_management.py +10 -10
- ansys/fluent/core/generated/datamodel_261/preferences.py +56 -0
- ansys/fluent/core/generated/datamodel_261/solver_workflow.py +14 -0
- ansys/fluent/core/generated/fluent_version_261.py +3 -3
- ansys/fluent/core/generated/meshing/tui_261.py +408 -10
- ansys/fluent/core/generated/solver/settings_261.py +15135 -5725
- ansys/fluent/core/generated/solver/settings_261.pyi +10252 -3619
- ansys/fluent/core/generated/solver/tui_261.py +2632 -834
- ansys/fluent/core/launcher/container_launcher.py +12 -3
- ansys/fluent/core/launcher/fluent_container.py +7 -1
- ansys/fluent/core/launcher/launch_options.py +2 -2
- ansys/fluent/core/launcher/launcher.py +2 -6
- ansys/fluent/core/launcher/pim_launcher.py +76 -3
- ansys/fluent/core/launcher/process_launch_string.py +1 -2
- ansys/fluent/core/launcher/slurm_launcher.py +4 -3
- ansys/fluent/core/launcher/standalone_launcher.py +3 -2
- ansys/fluent/core/module_config.py +10 -10
- ansys/fluent/core/report.py +1 -1
- ansys/fluent/core/search.py +12 -0
- ansys/fluent/core/services/__init__.py +2 -0
- ansys/fluent/core/services/datamodel_se.py +4 -1
- ansys/fluent/core/services/field_data.py +24 -0
- ansys/fluent/core/services/reduction.py +2 -0
- ansys/fluent/core/services/settings.py +1 -1
- ansys/fluent/core/services/solution_variables.py +92 -0
- ansys/fluent/core/session.py +1 -2
- ansys/fluent/core/session_base_meshing.py +8 -0
- ansys/fluent/core/session_meshing.py +5 -0
- ansys/fluent/core/session_pure_meshing.py +6 -0
- ansys/fluent/core/session_pure_meshing.pyi +5 -0
- ansys/fluent/core/session_solver.py +5 -4
- ansys/fluent/core/session_utilities.py +8 -5
- ansys/fluent/core/solver/flobject.py +19 -0
- ansys/fluent/core/solver/flunits.py +2 -0
- ansys/fluent/core/solver/function/reduction.py +2 -0
- ansys/fluent/core/ui/__init__.py +64 -0
- ansys/fluent/core/ui/jupyter_ui.py +203 -0
- ansys/fluent/core/ui/standalone_web_ui.py +296 -0
- ansys/fluent/core/ui/utils.py +173 -0
- ansys/fluent/core/utils/deprecate.py +1 -0
- ansys/fluent/core/utils/networking.py +11 -2
- {ansys_fluent_core-0.35.dev0.dist-info → ansys_fluent_core-0.36.dev0.dist-info}/METADATA +29 -22
- {ansys_fluent_core-0.35.dev0.dist-info → ansys_fluent_core-0.36.dev0.dist-info}/RECORD +73 -68
- {ansys_fluent_core-0.35.dev0.dist-info → ansys_fluent_core-0.36.dev0.dist-info}/WHEEL +1 -1
- {ansys_fluent_core-0.35.dev0.dist-info → ansys_fluent_core-0.36.dev0.dist-info/licenses}/LICENSE +0 -0
|
@@ -72,6 +72,7 @@ class BaseMeshing:
|
|
|
72
72
|
self._fluent_version = fluent_version
|
|
73
73
|
self._meshing_utilities = None
|
|
74
74
|
self._old_workflow = None
|
|
75
|
+
self._meshing_workflow = None
|
|
75
76
|
self._part_management = None
|
|
76
77
|
self._pm_file_management = None
|
|
77
78
|
self._preferences = None
|
|
@@ -127,6 +128,13 @@ class BaseMeshing:
|
|
|
127
128
|
self._old_workflow = _make_datamodel_module(self, "workflow")
|
|
128
129
|
return self._old_workflow
|
|
129
130
|
|
|
131
|
+
@property
|
|
132
|
+
def meshing_workflow(self):
|
|
133
|
+
"""Full API to meshing and meshing_workflow."""
|
|
134
|
+
if self._meshing_workflow is None:
|
|
135
|
+
self._meshing_workflow = _make_datamodel_module(self, "meshing_workflow")
|
|
136
|
+
return self._meshing_workflow
|
|
137
|
+
|
|
130
138
|
def watertight_workflow(self, initialize: bool = True):
|
|
131
139
|
"""Datamodel root of workflow."""
|
|
132
140
|
self._current_workflow = WorkflowMode.WATERTIGHT_MESHING_MODE.value(
|
|
@@ -127,6 +127,11 @@ class Meshing(PureMeshing):
|
|
|
127
127
|
"""Workflow datamodel root."""
|
|
128
128
|
return super(Meshing, self).workflow
|
|
129
129
|
|
|
130
|
+
@property
|
|
131
|
+
def meshing_workflow(self):
|
|
132
|
+
"""Full API to meshing and meshing_workflow."""
|
|
133
|
+
return super(Meshing, self).meshing_workflow
|
|
134
|
+
|
|
130
135
|
@property
|
|
131
136
|
def PartManagement(self):
|
|
132
137
|
"""Part management datamodel root."""
|
|
@@ -50,6 +50,7 @@ class PureMeshing(BaseSession):
|
|
|
50
50
|
|
|
51
51
|
_rules = [
|
|
52
52
|
"workflow",
|
|
53
|
+
"meshing_workflow",
|
|
53
54
|
"meshing",
|
|
54
55
|
"MeshingUtilities",
|
|
55
56
|
"PartManagement",
|
|
@@ -146,6 +147,11 @@ class PureMeshing(BaseSession):
|
|
|
146
147
|
"""Datamodel root of workflow."""
|
|
147
148
|
return self._base_meshing.workflow
|
|
148
149
|
|
|
150
|
+
@property
|
|
151
|
+
def meshing_workflow(self):
|
|
152
|
+
"""Full API to meshing and meshing_workflow."""
|
|
153
|
+
return self._base_meshing.meshing_workflow
|
|
154
|
+
|
|
149
155
|
def watertight(self):
|
|
150
156
|
"""Get a new watertight workflow."""
|
|
151
157
|
return self._base_meshing.watertight_workflow()
|
|
@@ -34,6 +34,9 @@ from ansys.fluent.core.generated.datamodel_252.preferences import (
|
|
|
34
34
|
Root as preferences_root,
|
|
35
35
|
)
|
|
36
36
|
from ansys.fluent.core.generated.datamodel_252.workflow import Root as workflow_root
|
|
37
|
+
from ansys.fluent.core.generated.datamodel_261.meshing_workflow import (
|
|
38
|
+
Root as meshing_workflow_root,
|
|
39
|
+
)
|
|
37
40
|
from ansys.fluent.core.generated.meshing.tui_252 import main_menu
|
|
38
41
|
|
|
39
42
|
class PureMeshing:
|
|
@@ -45,6 +48,8 @@ class PureMeshing:
|
|
|
45
48
|
def meshing_utilities(self) -> meshing_utilities_root: ...
|
|
46
49
|
@property
|
|
47
50
|
def workflow(self) -> workflow_root: ...
|
|
51
|
+
@property
|
|
52
|
+
def meshing_workflow(self) -> meshing_workflow_root: ...
|
|
48
53
|
def watertight(self): ...
|
|
49
54
|
def fault_tolerant(self): ...
|
|
50
55
|
def two_dimensional_meshing(self): ...
|
|
@@ -160,10 +160,11 @@ class Solver(BaseSession):
|
|
|
160
160
|
)
|
|
161
161
|
#: Manage Fluent's solution monitors.
|
|
162
162
|
self.monitors = MonitorsManager(fluent_connection._id, monitors_service)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
if not pyfluent.config.disable_monitor_refresh_on_init:
|
|
164
|
+
self.events.register_callback(
|
|
165
|
+
(SolverEvent.SOLUTION_INITIALIZED, SolverEvent.DATA_LOADED),
|
|
166
|
+
self.monitors.refresh,
|
|
167
|
+
)
|
|
167
168
|
|
|
168
169
|
fluent_connection.register_finalizer_cb(self.monitors.stop)
|
|
169
170
|
|
|
@@ -90,8 +90,9 @@ class SessionBase:
|
|
|
90
90
|
|
|
91
91
|
Parameters
|
|
92
92
|
----------
|
|
93
|
-
ui_mode : UIMode
|
|
94
|
-
Defines the user interface mode for Fluent.
|
|
93
|
+
ui_mode : UIMode or str, optional
|
|
94
|
+
Defines the user interface mode for Fluent. Accepts either a ``UIMode`` value
|
|
95
|
+
or a corresponding string such as ``"no_gui"``, ``"hidden_gui"``, or ``"gui"``.
|
|
95
96
|
graphics_driver : FluentWindowsGraphicsDriver or FluentLinuxGraphicsDriver
|
|
96
97
|
Specifies the graphics driver for Fluent. Options are from the ``FluentWindowsGraphicsDriver`` enum
|
|
97
98
|
(for Windows) or the ``FluentLinuxGraphicsDriver`` enum (for Linux).
|
|
@@ -194,8 +195,9 @@ class SessionBase:
|
|
|
194
195
|
|
|
195
196
|
Parameters
|
|
196
197
|
----------
|
|
197
|
-
ui_mode : UIMode
|
|
198
|
-
Defines the user interface mode for Fluent.
|
|
198
|
+
ui_mode : UIMode or str, optional
|
|
199
|
+
Defines the user interface mode for Fluent. Accepts either a ``UIMode`` value
|
|
200
|
+
or a corresponding string such as ``"no_gui"``, ``"hidden_gui"``, or ``"gui"``.
|
|
199
201
|
graphics_driver : FluentWindowsGraphicsDriver or FluentLinuxGraphicsDriver
|
|
200
202
|
Specifies the graphics driver for Fluent. Options are from the ``FluentWindowsGraphicsDriver`` enum
|
|
201
203
|
(for Windows) or the ``FluentLinuxGraphicsDriver`` enum (for Linux).
|
|
@@ -287,7 +289,8 @@ class SessionBase:
|
|
|
287
289
|
Parameters
|
|
288
290
|
----------
|
|
289
291
|
ui_mode : UIMode or str, optional
|
|
290
|
-
Defines the user interface mode for Fluent.
|
|
292
|
+
Defines the user interface mode for Fluent. Accepts either a ``UIMode`` value
|
|
293
|
+
or a corresponding string such as ``"no_gui"``, ``"hidden_gui"``, or ``"gui"``.
|
|
291
294
|
graphics_driver : FluentWindowsGraphicsDriver or FluentLinuxGraphicsDriver
|
|
292
295
|
Specifies the graphics driver for Fluent. Options are from the ``FluentWindowsGraphicsDriver`` enum
|
|
293
296
|
(for Windows) or the ``FluentLinuxGraphicsDriver`` enum (for Linux).
|
|
@@ -80,6 +80,7 @@ from ansys.fluent.core.variable_strategies import (
|
|
|
80
80
|
FluentFieldDataNamingStrategy as naming_strategy,
|
|
81
81
|
)
|
|
82
82
|
import ansys.units
|
|
83
|
+
from ansys.units import VariableDescriptor
|
|
83
84
|
|
|
84
85
|
from . import _docstrings
|
|
85
86
|
from ..pyfluent_warnings import warning_for_fluent_dev_version
|
|
@@ -676,7 +677,21 @@ class Textual(Property):
|
|
|
676
677
|
Either str or VariableDescriptor.
|
|
677
678
|
kwargs : Any
|
|
678
679
|
Keyword arguments.
|
|
680
|
+
|
|
681
|
+
Raises
|
|
682
|
+
------
|
|
683
|
+
TypeError
|
|
684
|
+
If state is not a string.
|
|
679
685
|
"""
|
|
686
|
+
allowed_types = (str, VariableDescriptor)
|
|
687
|
+
|
|
688
|
+
if not isinstance(state, allowed_types):
|
|
689
|
+
if self._has_migration_adapter:
|
|
690
|
+
return self.base_set_state(state=state, **kwargs)
|
|
691
|
+
raise TypeError(
|
|
692
|
+
f"Expected state to be {' or '.join(t.__name__ for t in allowed_types)}, "
|
|
693
|
+
f"got {type(state).__name__}."
|
|
694
|
+
)
|
|
680
695
|
return self.base_set_state(state=_to_field_name_str(state), **kwargs)
|
|
681
696
|
|
|
682
697
|
|
|
@@ -2282,6 +2297,10 @@ def get_cls(name, info, parent=None, version=None, parent_taboo=None):
|
|
|
2282
2297
|
)
|
|
2283
2298
|
cls._allowed_values = allowed_values
|
|
2284
2299
|
|
|
2300
|
+
has_migration_adapter = info.get("has-migration-adapter?", False)
|
|
2301
|
+
if has_migration_adapter:
|
|
2302
|
+
cls._has_migration_adapter = True
|
|
2303
|
+
|
|
2285
2304
|
except Exception:
|
|
2286
2305
|
print(
|
|
2287
2306
|
f"Unable to construct class for '{name}' of "
|
|
@@ -298,6 +298,8 @@ def get_si_unit_for_fluent_quantity(
|
|
|
298
298
|
# attribute only for dimensionless variables
|
|
299
299
|
if quantity is None:
|
|
300
300
|
return ""
|
|
301
|
+
if isinstance(quantity, list): # real vector
|
|
302
|
+
quantity = quantity[0]
|
|
301
303
|
if not isinstance(quantity, str):
|
|
302
304
|
raise InvalidQuantityType(quantity)
|
|
303
305
|
try:
|
|
@@ -211,6 +211,8 @@ def _eval_reduction(
|
|
|
211
211
|
weight = "Weight=" + str(weight)
|
|
212
212
|
locations = str(locations) + ", " + weight
|
|
213
213
|
|
|
214
|
+
if hasattr(expr, "definition"):
|
|
215
|
+
expr = expr.definition()
|
|
214
216
|
expr_str = _expr_to_expr_str(naming_strategy().to_string(expr))
|
|
215
217
|
if condition:
|
|
216
218
|
expr_str = expr_str + ", " + condition
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
"""Public exposure of ui UI for PyFluent."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def in_jupyter():
|
|
27
|
+
"""Checks if the library is being used in a Jupyter environment."""
|
|
28
|
+
try:
|
|
29
|
+
from IPython import get_ipython
|
|
30
|
+
|
|
31
|
+
return "IPKernelApp" in get_ipython().config
|
|
32
|
+
except (ImportError, AttributeError):
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if in_jupyter():
|
|
37
|
+
from ansys.fluent.core.ui.jupyter_ui import (
|
|
38
|
+
set_auto_refresh,
|
|
39
|
+
settings_ui,
|
|
40
|
+
)
|
|
41
|
+
else:
|
|
42
|
+
from ansys.fluent.core.ui.standalone_web_ui import ( # noqa: F401
|
|
43
|
+
build_settings_view,
|
|
44
|
+
set_auto_refresh,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def ui(settings_obj):
|
|
49
|
+
"""PyFluent ui UI wrapper."""
|
|
50
|
+
if in_jupyter():
|
|
51
|
+
import IPython
|
|
52
|
+
from IPython.display import display
|
|
53
|
+
|
|
54
|
+
if hasattr(IPython, "get_ipython") and "ZMQInteractiveShell" in str(
|
|
55
|
+
type(IPython.get_ipython())
|
|
56
|
+
):
|
|
57
|
+
display(settings_ui(settings_obj))
|
|
58
|
+
else:
|
|
59
|
+
import panel as pn
|
|
60
|
+
|
|
61
|
+
pn.extension()
|
|
62
|
+
view = build_settings_view(settings_obj)
|
|
63
|
+
view.servable()
|
|
64
|
+
pn.serve(view)
|
|
@@ -0,0 +1,203 @@
|
|
|
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
|
+
"""Render ui UI in Jupyter notebook."""
|
|
24
|
+
|
|
25
|
+
from ansys.fluent.core.ui.utils import (
|
|
26
|
+
_parse_path,
|
|
27
|
+
_render_widget_from_props_generic,
|
|
28
|
+
_safe_get_properties,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
import ipywidgets as widgets
|
|
33
|
+
except ModuleNotFoundError as exc:
|
|
34
|
+
raise ModuleNotFoundError(
|
|
35
|
+
"Missing dependencies, use 'pip install ansys-fluent-core[ui-jupyter]' to install them."
|
|
36
|
+
) from exc
|
|
37
|
+
|
|
38
|
+
from ansys.fluent.core.solver.flobject import (
|
|
39
|
+
BaseCommand,
|
|
40
|
+
Group,
|
|
41
|
+
NamedObject,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def set_auto_refresh():
|
|
46
|
+
"""Refreshes the UI w.r.t. server state for each command execution or parameter invocation."""
|
|
47
|
+
raise NotImplementedError("This is yet to be implemented in jupyter environment.")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _render_widgets_from_props(settings_obj, label, props):
|
|
51
|
+
"""Render widget using pre-fetched props instead of repeated calls."""
|
|
52
|
+
return _render_widget_from_props_generic(settings_obj, label, props, widgets)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _param_ui(settings_obj, props):
|
|
56
|
+
label = props["python_name"].replace("_", " ").capitalize()
|
|
57
|
+
|
|
58
|
+
def get_fn():
|
|
59
|
+
try:
|
|
60
|
+
return getattr(props["parent"], props["python_name"])
|
|
61
|
+
except AttributeError:
|
|
62
|
+
return props["parent"][props["obj_name"]]
|
|
63
|
+
|
|
64
|
+
def set_fn(v):
|
|
65
|
+
return setattr(settings_obj.parent, props["python_name"], v)
|
|
66
|
+
|
|
67
|
+
widget = _render_widgets_from_props(get_fn(), label, props)
|
|
68
|
+
output = widgets.Output()
|
|
69
|
+
with output:
|
|
70
|
+
output.clear_output()
|
|
71
|
+
print(_parse_path(settings_obj))
|
|
72
|
+
if hasattr(widget, "_is_list_text"):
|
|
73
|
+
typ, parse_csv = widget._is_list_text
|
|
74
|
+
|
|
75
|
+
def commit_text_list(change):
|
|
76
|
+
if change["name"] == "value":
|
|
77
|
+
raw = change["new"]
|
|
78
|
+
vals = (
|
|
79
|
+
[typ(v.strip()) for v in raw.split(",") if v.strip()]
|
|
80
|
+
if parse_csv
|
|
81
|
+
else list(change["new"])
|
|
82
|
+
)
|
|
83
|
+
with output:
|
|
84
|
+
output.clear_output()
|
|
85
|
+
set_fn(vals)
|
|
86
|
+
print(f"{_parse_path(settings_obj)} = {vals}")
|
|
87
|
+
|
|
88
|
+
widget.observe(commit_text_list)
|
|
89
|
+
else:
|
|
90
|
+
|
|
91
|
+
def on_change(change):
|
|
92
|
+
if change["name"] == "value":
|
|
93
|
+
with output:
|
|
94
|
+
output.clear_output()
|
|
95
|
+
try:
|
|
96
|
+
set_fn(change["new"])
|
|
97
|
+
print(f"{_parse_path(settings_obj)} = {change['new']}")
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(f"Error setting {label}: {e}")
|
|
100
|
+
|
|
101
|
+
widget.observe(on_change)
|
|
102
|
+
return widgets.VBox([widget, output])
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _command_ui(func, props):
|
|
106
|
+
"""
|
|
107
|
+
Renders input widgets for function arguments based on .argument_names()
|
|
108
|
+
and executes func(**kwargs) on button click.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
# Get argument names from the function object
|
|
112
|
+
if not hasattr(func, "argument_names"):
|
|
113
|
+
return widgets.HTML("Command has no 'argument_names()'.")
|
|
114
|
+
|
|
115
|
+
arg_names = func.argument_names
|
|
116
|
+
arg_widgets = {}
|
|
117
|
+
controls = []
|
|
118
|
+
for name in arg_names:
|
|
119
|
+
child_obj = getattr(func, name)
|
|
120
|
+
child_props = _safe_get_properties(child_obj)
|
|
121
|
+
widget = _render_widgets_from_props(child_obj, name, child_props)
|
|
122
|
+
arg_widgets[name] = widget
|
|
123
|
+
controls.append(widget)
|
|
124
|
+
|
|
125
|
+
# Run button
|
|
126
|
+
button = widgets.Button(
|
|
127
|
+
description=f"Run {props['python_name']}", button_style="success"
|
|
128
|
+
)
|
|
129
|
+
output = widgets.Output()
|
|
130
|
+
with output:
|
|
131
|
+
output.clear_output()
|
|
132
|
+
print(_parse_path(func))
|
|
133
|
+
|
|
134
|
+
def on_click(_):
|
|
135
|
+
kwargs = {name: w.value for name, w in arg_widgets.items()}
|
|
136
|
+
with output:
|
|
137
|
+
output.clear_output()
|
|
138
|
+
try:
|
|
139
|
+
func(**kwargs)
|
|
140
|
+
kwargs_str = "("
|
|
141
|
+
for k, v in kwargs.items():
|
|
142
|
+
if type(v) is str:
|
|
143
|
+
if v != "":
|
|
144
|
+
kwargs_str += f"{k}='{v}', "
|
|
145
|
+
else:
|
|
146
|
+
kwargs_str += f"{k}={v}, "
|
|
147
|
+
print(f"{_parse_path(func)}" + kwargs_str.strip()[:-1] + ")")
|
|
148
|
+
except Exception as e:
|
|
149
|
+
print("Error:", e)
|
|
150
|
+
|
|
151
|
+
button.on_click(on_click)
|
|
152
|
+
return widgets.VBox(controls + [button, output])
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def settings_ui(obj, indent=0):
|
|
156
|
+
"""Render settings objects into ui graphics."""
|
|
157
|
+
props = _safe_get_properties(obj)
|
|
158
|
+
if isinstance(obj, (Group, NamedObject)):
|
|
159
|
+
if isinstance(obj, Group):
|
|
160
|
+
command_names = obj.get_active_command_names()
|
|
161
|
+
child_names = obj.get_active_child_names() + command_names
|
|
162
|
+
else:
|
|
163
|
+
command_names = obj.command_names
|
|
164
|
+
child_names = list(obj) + command_names
|
|
165
|
+
accordions = []
|
|
166
|
+
for child_name in child_names:
|
|
167
|
+
|
|
168
|
+
def lazy_loader(name=child_name, parent=obj, lvl=indent + 1):
|
|
169
|
+
try:
|
|
170
|
+
child_obj = getattr(parent, name)
|
|
171
|
+
except AttributeError:
|
|
172
|
+
child_obj = parent[name]
|
|
173
|
+
return settings_ui(child_obj, lvl)
|
|
174
|
+
|
|
175
|
+
acc = widgets.Accordion(children=[widgets.HTML("Loading...")])
|
|
176
|
+
if child_name in command_names:
|
|
177
|
+
acc.set_title(0, f"⚡ {child_name}")
|
|
178
|
+
else:
|
|
179
|
+
acc.set_title(0, child_name)
|
|
180
|
+
|
|
181
|
+
def on_selected(change, loader=lazy_loader, accordion=acc):
|
|
182
|
+
if change["name"] == "selected_index" and change["new"] == 0:
|
|
183
|
+
if isinstance(accordion.children[0], widgets.HTML):
|
|
184
|
+
accordion.children = [loader()]
|
|
185
|
+
|
|
186
|
+
acc.observe(on_selected, names="selected_index")
|
|
187
|
+
accordions.append(acc)
|
|
188
|
+
|
|
189
|
+
return widgets.VBox(accordions)
|
|
190
|
+
|
|
191
|
+
else:
|
|
192
|
+
if isinstance(obj, BaseCommand):
|
|
193
|
+
return (
|
|
194
|
+
widgets.VBox([_command_ui(obj, props)])
|
|
195
|
+
if props["is_active"]
|
|
196
|
+
else widgets.HTML("")
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
return (
|
|
200
|
+
widgets.VBox([_param_ui(obj, props)])
|
|
201
|
+
if props["is_active"]
|
|
202
|
+
else widgets.HTML("")
|
|
203
|
+
)
|