ansys-mechanical-core 0.11.13__py3-none-any.whl → 0.11.14__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.
- ansys/mechanical/core/__init__.py +0 -1
- ansys/mechanical/core/embedding/app.py +73 -2
- ansys/mechanical/core/embedding/enum_importer.py +0 -1
- ansys/mechanical/core/embedding/global_importer.py +50 -0
- ansys/mechanical/core/embedding/imports.py +30 -58
- ansys/mechanical/core/embedding/initializer.py +6 -4
- ansys/mechanical/core/embedding/messages.py +190 -0
- ansys/mechanical/core/embedding/rpc/client.py +39 -17
- ansys/mechanical/core/embedding/rpc/server.py +35 -14
- ansys/mechanical/core/embedding/rpc/utils.py +0 -2
- ansys/mechanical/core/embedding/transaction.py +51 -0
- ansys/mechanical/core/ide_config.py +21 -7
- ansys/mechanical/core/mechanical.py +72 -16
- {ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info}/METADATA +10 -9
- {ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info}/RECORD +18 -15
- {ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info}/WHEEL +1 -1
- {ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info}/entry_points.txt +0 -0
- {ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info/licenses}/LICENSE +0 -0
@@ -44,7 +44,6 @@ from ansys.mechanical.core.logging import Logger
|
|
44
44
|
LOG = Logger(level=logging.ERROR, to_file=False, to_stdout=True)
|
45
45
|
"""Create logger for package level use."""
|
46
46
|
|
47
|
-
LOG.debug("Loaded logging module as LOG")
|
48
47
|
|
49
48
|
from ansys.mechanical.core._version import __version__
|
50
49
|
from ansys.mechanical.core.mechanical import (
|
@@ -30,6 +30,7 @@ import shutil
|
|
30
30
|
import typing
|
31
31
|
import warnings
|
32
32
|
|
33
|
+
from ansys.mechanical.core import LOG
|
33
34
|
from ansys.mechanical.core.embedding import initializer, runtime
|
34
35
|
from ansys.mechanical.core.embedding.addins import AddinConfiguration
|
35
36
|
from ansys.mechanical.core.embedding.appdata import UniqueUserProfile
|
@@ -89,6 +90,11 @@ def _start_application(configuration: AddinConfiguration, version, db_file) -> "
|
|
89
90
|
return Ansys.Mechanical.Embedding.Application(db_file)
|
90
91
|
|
91
92
|
|
93
|
+
def is_initialized():
|
94
|
+
"""Check if the app has been initialized."""
|
95
|
+
return len(INSTANCES) != 0
|
96
|
+
|
97
|
+
|
92
98
|
class GetterWrapper(object):
|
93
99
|
"""Wrapper class around an attribute of an object."""
|
94
100
|
|
@@ -124,10 +130,17 @@ class App:
|
|
124
130
|
private_appdata : bool, optional
|
125
131
|
Setting for a temporary AppData directory. Default is False.
|
126
132
|
Enables running parallel instances of Mechanical.
|
133
|
+
globals : dict, optional
|
134
|
+
Global variables to be updated. For example, globals().
|
135
|
+
Replaces "app.update_globals(globals())".
|
127
136
|
config : AddinConfiguration, optional
|
128
137
|
Configuration for addins. By default "Mechanical" is used and ACT Addins are disabled.
|
129
138
|
copy_profile : bool, optional
|
130
139
|
Whether to copy the user profile when private_appdata is True. Default is True.
|
140
|
+
enable_logging : bool, optional
|
141
|
+
Whether to enable logging. Default is True.
|
142
|
+
log_level : str, optional
|
143
|
+
The logging level for the application. Default is "WARNING".
|
131
144
|
|
132
145
|
Examples
|
133
146
|
--------
|
@@ -140,6 +153,10 @@ class App:
|
|
140
153
|
|
141
154
|
>>> app = App(private_appdata=True, copy_profile=False)
|
142
155
|
|
156
|
+
Update the global variables with globals
|
157
|
+
|
158
|
+
>>> app = App(globals=globals())
|
159
|
+
|
143
160
|
Create App with "Mechanical" configuration and no ACT Addins
|
144
161
|
|
145
162
|
>>> from ansys.mechanical.core.embedding import AddinConfiguration
|
@@ -147,6 +164,13 @@ class App:
|
|
147
164
|
>>> config = AddinConfiguration("Mechanical")
|
148
165
|
>>> config.no_act_addins = True
|
149
166
|
>>> app = App(config=config)
|
167
|
+
|
168
|
+
Set log level
|
169
|
+
|
170
|
+
>>> app = App(log_level='INFO')
|
171
|
+
|
172
|
+
... INFO - - app - log_info - Starting Mechanical Application
|
173
|
+
|
150
174
|
"""
|
151
175
|
|
152
176
|
def __init__(self, db_file=None, private_appdata=False, **kwargs):
|
@@ -154,6 +178,14 @@ class App:
|
|
154
178
|
global INSTANCES
|
155
179
|
from ansys.mechanical.core import BUILDING_GALLERY
|
156
180
|
|
181
|
+
self._enable_logging = kwargs.get("enable_logging", True)
|
182
|
+
if self._enable_logging:
|
183
|
+
self._log = LOG
|
184
|
+
self._log_level = kwargs.get("log_level", "WARNING")
|
185
|
+
self._log.setLevel(self._log_level)
|
186
|
+
|
187
|
+
self.log_info("Starting Mechanical Application")
|
188
|
+
|
157
189
|
if BUILDING_GALLERY:
|
158
190
|
if len(INSTANCES) != 0:
|
159
191
|
instance: App = INSTANCES[0]
|
@@ -163,6 +195,7 @@ class App:
|
|
163
195
|
return
|
164
196
|
if len(INSTANCES) > 0:
|
165
197
|
raise Exception("Cannot have more than one embedded mechanical instance!")
|
198
|
+
|
166
199
|
version = kwargs.get("version")
|
167
200
|
if version is not None:
|
168
201
|
try:
|
@@ -191,6 +224,11 @@ class App:
|
|
191
224
|
INSTANCES.append(self)
|
192
225
|
self._updated_scopes: typing.List[typing.Dict[str, typing.Any]] = []
|
193
226
|
self._subscribe()
|
227
|
+
self._messages = None
|
228
|
+
|
229
|
+
globals = kwargs.get("globals")
|
230
|
+
if globals:
|
231
|
+
self.update_globals(globals)
|
194
232
|
|
195
233
|
def __repr__(self):
|
196
234
|
"""Get the product info."""
|
@@ -227,6 +265,7 @@ class App:
|
|
227
265
|
remove_lock : bool, optional
|
228
266
|
Whether or not to remove the lock file if it exists before opening the project file.
|
229
267
|
"""
|
268
|
+
self.log_info(f"Opening {db_file} ...")
|
230
269
|
if remove_lock:
|
231
270
|
lock_file = Path(self.DataModel.Project.ProjectDirectory) / ".mech_lock"
|
232
271
|
# Remove the lock file if it exists before opening the project file
|
@@ -437,6 +476,15 @@ This may corrupt the project file.",
|
|
437
476
|
"""Returns the current project directory."""
|
438
477
|
return self.DataModel.Project.ProjectDirectory
|
439
478
|
|
479
|
+
@property
|
480
|
+
def messages(self):
|
481
|
+
"""Lazy-load the MessageManager."""
|
482
|
+
if self._messages is None:
|
483
|
+
from ansys.mechanical.core.embedding.messages import MessageManager
|
484
|
+
|
485
|
+
self._messages = MessageManager(self._app)
|
486
|
+
return self._messages
|
487
|
+
|
440
488
|
def _share(self, other) -> None:
|
441
489
|
"""Shares the state of self with other.
|
442
490
|
|
@@ -580,8 +628,7 @@ This may corrupt the project file.",
|
|
580
628
|
Examples
|
581
629
|
--------
|
582
630
|
>>> from ansys.mechanical.core import App
|
583
|
-
>>> app = App()
|
584
|
-
>>> app.update_globals(globals())
|
631
|
+
>>> app = App(globals=globals())
|
585
632
|
>>> app.print_tree()
|
586
633
|
... ├── Project
|
587
634
|
... | ├── Model
|
@@ -608,3 +655,27 @@ This may corrupt the project file.",
|
|
608
655
|
node = self.DataModel.Project
|
609
656
|
|
610
657
|
self._print_tree(node, max_lines, lines_count, indentation)
|
658
|
+
|
659
|
+
def log_debug(self, message):
|
660
|
+
"""Log the debug message."""
|
661
|
+
if not self._enable_logging:
|
662
|
+
return
|
663
|
+
self._log.debug(message)
|
664
|
+
|
665
|
+
def log_info(self, message):
|
666
|
+
"""Log the info message."""
|
667
|
+
if not self._enable_logging:
|
668
|
+
return
|
669
|
+
self._log.info(message)
|
670
|
+
|
671
|
+
def log_warning(self, message):
|
672
|
+
"""Log the warning message."""
|
673
|
+
if not self._enable_logging:
|
674
|
+
return
|
675
|
+
self._log.warning(message)
|
676
|
+
|
677
|
+
def log_error(self, message):
|
678
|
+
"""Log the error message."""
|
679
|
+
if not self._enable_logging:
|
680
|
+
return
|
681
|
+
self._log.error(message)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright (C) 2022 - 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
|
+
"""Import Mechanical globals."""
|
23
|
+
|
24
|
+
from ansys.mechanical.core.embedding.app import is_initialized
|
25
|
+
|
26
|
+
if not is_initialized():
|
27
|
+
raise Exception("Globals cannot be imported until the embedded app is initialized.")
|
28
|
+
|
29
|
+
import clr
|
30
|
+
|
31
|
+
clr.AddReference("Ansys.Mechanical.DataModel")
|
32
|
+
clr.AddReference("Ansys.ACT.Interfaces")
|
33
|
+
|
34
|
+
|
35
|
+
clr.AddReference("System.Collections")
|
36
|
+
clr.AddReference("Ansys.ACT.WB1")
|
37
|
+
clr.AddReference("Ansys.Mechanical.DataModel")
|
38
|
+
|
39
|
+
# from Ansys.ACT.Mechanical import Transaction
|
40
|
+
# When ansys-pythonnet issue #14 is fixed, uncomment above
|
41
|
+
from Ansys.ACT.Core.Math import Point2D, Point3D # noqa isort: skip
|
42
|
+
from Ansys.ACT.Math import Vector3D # noqa isort: skip
|
43
|
+
from Ansys.Core.Units import Quantity # noqa isort: skip
|
44
|
+
from Ansys.Mechanical.DataModel import MechanicalEnums # noqa isort: skip
|
45
|
+
from Ansys.Mechanical.Graphics import Point, SectionPlane # noqa isort: skip
|
46
|
+
|
47
|
+
from ansys.mechanical.core.embedding.transaction import Transaction # noqa isort: skip
|
48
|
+
|
49
|
+
import System # noqa isort: skip
|
50
|
+
import Ansys # noqa isort: skip
|
@@ -46,36 +46,37 @@ def global_variables(app: "ansys.mechanical.core.App", enums: bool = False) -> t
|
|
46
46
|
To also import all the enums, set the parameter enums to true.
|
47
47
|
"""
|
48
48
|
vars = global_entry_points(app)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
clr.AddReference("Ansys.Mechanical.DataModel")
|
54
|
-
# from Ansys.ACT.Mechanical import Transaction
|
55
|
-
# When ansys-pythonnet issue #14 is fixed, uncomment above
|
56
|
-
from Ansys.ACT.Core.Math import Point2D, Point3D
|
57
|
-
from Ansys.ACT.Math import Vector3D
|
58
|
-
from Ansys.ACT.Mechanical.Fields import VariableDefinitionType
|
59
|
-
from Ansys.Core.Units import Quantity
|
60
|
-
from Ansys.Mechanical.DataModel import MechanicalEnums
|
61
|
-
from Ansys.Mechanical.Graphics import Point, SectionPlane
|
62
|
-
|
63
|
-
import System # isort: skip
|
64
|
-
import Ansys # isort: skip
|
65
|
-
|
66
|
-
vars["Quantity"] = Quantity
|
67
|
-
vars["System"] = System
|
68
|
-
vars["Ansys"] = Ansys
|
49
|
+
|
50
|
+
from ansys.mechanical.core.embedding.app import is_initialized
|
51
|
+
from ansys.mechanical.core.embedding.transaction import Transaction
|
52
|
+
|
69
53
|
vars["Transaction"] = Transaction
|
70
|
-
|
71
|
-
#
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
54
|
+
|
55
|
+
# Import modules if the app is initialized
|
56
|
+
if is_initialized():
|
57
|
+
from ansys.mechanical.core.embedding.global_importer import (
|
58
|
+
Ansys,
|
59
|
+
MechanicalEnums,
|
60
|
+
Point,
|
61
|
+
Point2D,
|
62
|
+
Point3D,
|
63
|
+
Quantity,
|
64
|
+
SectionPlane,
|
65
|
+
System,
|
66
|
+
Vector3D,
|
67
|
+
)
|
68
|
+
|
69
|
+
vars["Quantity"] = Quantity
|
70
|
+
vars["System"] = System
|
71
|
+
vars["Ansys"] = Ansys
|
72
|
+
vars["MechanicalEnums"] = MechanicalEnums
|
73
|
+
# Graphics
|
74
|
+
vars["Point"] = Point
|
75
|
+
vars["SectionPlane"] = SectionPlane
|
76
|
+
# Math
|
77
|
+
vars["Point2D"] = Point2D
|
78
|
+
vars["Point3D"] = Point3D
|
79
|
+
vars["Vector3D"] = Vector3D
|
79
80
|
|
80
81
|
if enums:
|
81
82
|
vars.update(get_all_enums())
|
@@ -95,32 +96,3 @@ def get_all_enums() -> typing.Dict[str, typing.Any]:
|
|
95
96
|
if type(the_enum).__name__ == "CLRMetatype":
|
96
97
|
enums[attr] = the_enum
|
97
98
|
return enums
|
98
|
-
|
99
|
-
|
100
|
-
class Transaction: # When ansys-pythonnet issue #14 is fixed, this class will be removed
|
101
|
-
"""
|
102
|
-
A class to speed up bulk user interactions using Ansys ACT Mechanical Transaction.
|
103
|
-
|
104
|
-
Example
|
105
|
-
-------
|
106
|
-
>>> with Transaction() as transaction:
|
107
|
-
... pass # Perform bulk user interactions here
|
108
|
-
...
|
109
|
-
"""
|
110
|
-
|
111
|
-
def __init__(self):
|
112
|
-
"""Initialize the Transaction class."""
|
113
|
-
import clr
|
114
|
-
|
115
|
-
clr.AddReference("Ansys.ACT.WB1")
|
116
|
-
import Ansys
|
117
|
-
|
118
|
-
self._transaction = Ansys.ACT.Mechanical.Transaction()
|
119
|
-
|
120
|
-
def __enter__(self):
|
121
|
-
"""Enter the context of the transaction."""
|
122
|
-
return self
|
123
|
-
|
124
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
125
|
-
"""Exit the context of the transaction and disposes of resources."""
|
126
|
-
self._transaction.Dispose()
|
@@ -30,6 +30,7 @@ import warnings
|
|
30
30
|
|
31
31
|
from ansys.mechanical.core.embedding.loader import load_clr
|
32
32
|
from ansys.mechanical.core.embedding.resolver import resolve
|
33
|
+
from ansys.mechanical.core.mechanical import LOG
|
33
34
|
|
34
35
|
INITIALIZED_VERSION = None
|
35
36
|
"""Constant for the initialized version."""
|
@@ -85,7 +86,6 @@ def _get_latest_default_version() -> int:
|
|
85
86
|
If multiple versions are detected, select the latest one, as no specific version is provided.
|
86
87
|
"""
|
87
88
|
awp_roots = [value for key, value in os.environ.items() if key.startswith("AWP_ROOT")]
|
88
|
-
|
89
89
|
if not awp_roots:
|
90
90
|
raise Exception("No Mechanical installations found.")
|
91
91
|
|
@@ -94,13 +94,15 @@ def _get_latest_default_version() -> int:
|
|
94
94
|
folder = os.path.basename(os.path.normpath(path))
|
95
95
|
version = folder.split("v")[-1]
|
96
96
|
versions_found.append(int(version))
|
97
|
+
|
98
|
+
LOG.info(f"Available versions of Mechanical: {versions_found}")
|
99
|
+
|
97
100
|
latest_version = max(versions_found)
|
98
101
|
|
99
102
|
if len(awp_roots) > 1:
|
100
|
-
|
103
|
+
LOG.warning(
|
101
104
|
f"Multiple versions of Mechanical found! Using latest version {latest_version} ..."
|
102
105
|
)
|
103
|
-
|
104
106
|
return latest_version
|
105
107
|
|
106
108
|
|
@@ -159,7 +161,7 @@ def __check_loaded_libs(version: int = None): # pragma: no cover
|
|
159
161
|
# For 2025 R1, PyMechanical will crash on shutdown if libX11.so is already loaded
|
160
162
|
# before starting Mechanical
|
161
163
|
if __is_lib_loaded("libX11.so"):
|
162
|
-
|
164
|
+
LOG.warning(
|
163
165
|
"libX11.so is loaded prior to initializing the Embedded Instance of Mechanical.\
|
164
166
|
Python will crash on shutdown..."
|
165
167
|
)
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# Copyright (C) 2022 - 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
|
+
"""Message Manager for App."""
|
24
|
+
|
25
|
+
# TODO: add functionality to filter only errors, warnings, info
|
26
|
+
# TODO: add max number of messages to display
|
27
|
+
# TODO: implement pep8 formatting
|
28
|
+
|
29
|
+
try: # noqa: F401
|
30
|
+
import pandas as pd
|
31
|
+
|
32
|
+
HAS_PANDAS = True
|
33
|
+
"""Whether or not pandas exists."""
|
34
|
+
except ImportError:
|
35
|
+
HAS_PANDAS = False
|
36
|
+
|
37
|
+
|
38
|
+
class MessageManager:
|
39
|
+
"""Message manager for adding, fetching, and printing messages."""
|
40
|
+
|
41
|
+
def __init__(self, app):
|
42
|
+
"""Initialize the message manager."""
|
43
|
+
self._app = app
|
44
|
+
|
45
|
+
# Import necessary classes
|
46
|
+
from Ansys.Mechanical.Application import Message
|
47
|
+
from Ansys.Mechanical.DataModel.Enums import MessageSeverityType
|
48
|
+
|
49
|
+
self._message_severity = MessageSeverityType
|
50
|
+
self._message = Message
|
51
|
+
self._messages = self._app.ExtAPI.Application.Messages
|
52
|
+
|
53
|
+
def _create_messages_data(self): # pragma: no cover
|
54
|
+
"""Update the local cache of messages."""
|
55
|
+
data = {
|
56
|
+
"Severity": [],
|
57
|
+
"TimeStamp": [],
|
58
|
+
"DisplayString": [],
|
59
|
+
"Source": [],
|
60
|
+
"StringID": [],
|
61
|
+
"Location": [],
|
62
|
+
"RelatedObjects": [],
|
63
|
+
}
|
64
|
+
for msg in self._app.ExtAPI.Application.Messages:
|
65
|
+
data["Severity"].append(str(msg.Severity).upper())
|
66
|
+
data["TimeStamp"].append(msg.TimeStamp)
|
67
|
+
data["DisplayString"].append(msg.DisplayString)
|
68
|
+
data["Source"].append(msg.Source)
|
69
|
+
data["StringID"].append(msg.StringID)
|
70
|
+
data["Location"].append(msg.Location)
|
71
|
+
data["RelatedObjects"].append(msg.RelatedObjects)
|
72
|
+
|
73
|
+
return data
|
74
|
+
|
75
|
+
def __repr__(self): # pragma: no cover
|
76
|
+
"""Provide a DataFrame representation of all messages."""
|
77
|
+
if not HAS_PANDAS:
|
78
|
+
return "Pandas is not available. Please pip install pandas to display messages."
|
79
|
+
data = self._create_messages_data()
|
80
|
+
return repr(pd.DataFrame(data))
|
81
|
+
|
82
|
+
def __str__(self):
|
83
|
+
"""Provide a custom string representation of the messages."""
|
84
|
+
if self._messages.Count == 0:
|
85
|
+
return "No messages to display."
|
86
|
+
|
87
|
+
formatted_messages = [f"[{msg.Severity}] : {msg.DisplayString}" for msg in self._messages]
|
88
|
+
return "\n".join(formatted_messages)
|
89
|
+
|
90
|
+
def __getitem__(self, index):
|
91
|
+
"""Allow indexed access to messages."""
|
92
|
+
if len(self._messages) == 0:
|
93
|
+
raise IndexError("No messages are available.")
|
94
|
+
if index >= len(self._messages) or index < 0:
|
95
|
+
raise IndexError("Message index out of range.")
|
96
|
+
return self._messages[index]
|
97
|
+
|
98
|
+
def __len__(self):
|
99
|
+
"""Return the number of messages."""
|
100
|
+
return self._messages.Count
|
101
|
+
|
102
|
+
def add(self, severity: str, text: str):
|
103
|
+
"""Add a message and update the cache.
|
104
|
+
|
105
|
+
Parameters
|
106
|
+
----------
|
107
|
+
severity : str
|
108
|
+
Severity of the message. Can be "info", "warning", or "error".
|
109
|
+
text : str
|
110
|
+
Message text.
|
111
|
+
|
112
|
+
Examples
|
113
|
+
--------
|
114
|
+
>>> app.messages.add("info", "User clicked the start button.")
|
115
|
+
"""
|
116
|
+
severity_map = {
|
117
|
+
"info": self._message_severity.Info,
|
118
|
+
"warning": self._message_severity.Warning,
|
119
|
+
"error": self._message_severity.Error,
|
120
|
+
}
|
121
|
+
|
122
|
+
if severity.lower() not in severity_map:
|
123
|
+
raise ValueError(f"Invalid severity: {severity}")
|
124
|
+
|
125
|
+
_msg = self._message(text, severity_map[severity.lower()])
|
126
|
+
self._messages.Add(_msg)
|
127
|
+
|
128
|
+
def remove(self, index: int):
|
129
|
+
"""Remove a message by index.
|
130
|
+
|
131
|
+
Parameters
|
132
|
+
----------
|
133
|
+
index : int
|
134
|
+
Index of the message to remove.
|
135
|
+
|
136
|
+
Examples
|
137
|
+
--------
|
138
|
+
>>> app.messages.remove(0)
|
139
|
+
"""
|
140
|
+
if index >= len(self._app.ExtAPI.Application.Messages) or index < 0:
|
141
|
+
raise IndexError("Message index out of range.")
|
142
|
+
_msg = self._messages[index]
|
143
|
+
self._messages.Remove(_msg)
|
144
|
+
|
145
|
+
def show(self, filter="Severity;DisplayString"):
|
146
|
+
"""Print all messages with full details.
|
147
|
+
|
148
|
+
Parameters
|
149
|
+
----------
|
150
|
+
filter : str, optional
|
151
|
+
Semicolon separated list of message attributes to display.
|
152
|
+
Default is "severity;message".
|
153
|
+
if filter is "*", all available attributes will be displayed.
|
154
|
+
|
155
|
+
Examples
|
156
|
+
--------
|
157
|
+
>>> app.messages.show()
|
158
|
+
... severity: info
|
159
|
+
... message: Sample message.
|
160
|
+
|
161
|
+
>>> app.messages.show(filter="time_stamp;severity;message")
|
162
|
+
... time_stamp: 1/30/2025 12:10:35 PM
|
163
|
+
... severity: info
|
164
|
+
... message: Sample message.
|
165
|
+
"""
|
166
|
+
if self._messages.Count == 0:
|
167
|
+
print("No messages to display.")
|
168
|
+
return
|
169
|
+
|
170
|
+
if filter == "*":
|
171
|
+
selected_columns = [
|
172
|
+
"TimeStamp",
|
173
|
+
"Severity",
|
174
|
+
"DisplayString",
|
175
|
+
"Source",
|
176
|
+
"StringID",
|
177
|
+
"Location",
|
178
|
+
"RelatedObjects",
|
179
|
+
]
|
180
|
+
else:
|
181
|
+
selected_columns = [col.strip() for col in filter.split(";")]
|
182
|
+
|
183
|
+
for msg in self._messages:
|
184
|
+
for key in selected_columns:
|
185
|
+
print(f"{key}: {getattr(msg, key, 'Specified attribute not found.')}")
|
186
|
+
print()
|
187
|
+
|
188
|
+
def clear(self):
|
189
|
+
"""Clear all messages."""
|
190
|
+
self._messages.Clear()
|
@@ -27,13 +27,14 @@ import time
|
|
27
27
|
|
28
28
|
import rpyc
|
29
29
|
|
30
|
+
from ansys.mechanical.core.embedding.rpc.server import PYMECHANICAL_DEFAULT_RPC_PORT
|
30
31
|
from ansys.mechanical.core.mechanical import DEFAULT_CHUNK_SIZE
|
31
32
|
|
32
33
|
|
33
34
|
class Client:
|
34
35
|
"""Client for connecting to Mechanical services."""
|
35
36
|
|
36
|
-
def __init__(self, host: str, port: int, timeout: float = 120.0):
|
37
|
+
def __init__(self, host: str, port: int, timeout: float = 120.0, cleanup_on_exit=True):
|
37
38
|
"""Initialize the client.
|
38
39
|
|
39
40
|
Parameters
|
@@ -43,18 +44,23 @@ class Client:
|
|
43
44
|
in which case ``localhost`` is used.
|
44
45
|
port : int, optional
|
45
46
|
Port to connect to the Mecahnical server. The default is ``None``,
|
46
|
-
in which case ``
|
47
|
+
in which case ``20000`` is used.
|
47
48
|
timeout : float, optional
|
48
49
|
Maximum allowable time for connecting to the Mechanical server.
|
49
50
|
The default is ``60.0``.
|
50
51
|
|
51
52
|
"""
|
53
|
+
if host is None:
|
54
|
+
host = "localhost"
|
52
55
|
self.host = host
|
56
|
+
if port is None:
|
57
|
+
port = PYMECHANICAL_DEFAULT_RPC_PORT
|
53
58
|
self.port = port
|
54
59
|
self.timeout = timeout
|
55
60
|
self.connection = None
|
56
61
|
self.root = None
|
57
62
|
self._connect()
|
63
|
+
self._cleanup_on_exit = cleanup_on_exit
|
58
64
|
|
59
65
|
def __getattr__(self, attr):
|
60
66
|
"""Get attribute from the root object."""
|
@@ -77,26 +83,34 @@ class Client:
|
|
77
83
|
|
78
84
|
def _connect(self):
|
79
85
|
self._wait_until_ready()
|
80
|
-
self.connection = rpyc.connect(self.host, self.port)
|
81
86
|
self.root = self.connection.root
|
82
87
|
print(f"Connected to {self.host}:{self.port}")
|
83
|
-
|
88
|
+
|
89
|
+
def _exponential_backoff(self, max_time=60.0, base_time=0.1, factor=2):
|
90
|
+
"""Generate exponential backoff timing."""
|
91
|
+
t_max = time.time() + max_time
|
92
|
+
t = base_time
|
93
|
+
while time.time() < t_max:
|
94
|
+
yield t
|
95
|
+
t = min(t * factor, max_time)
|
84
96
|
|
85
97
|
def _wait_until_ready(self):
|
98
|
+
"""Wait until the server is ready."""
|
86
99
|
t_max = time.time() + self.timeout
|
87
|
-
|
100
|
+
for delay in self._exponential_backoff(max_time=self.timeout):
|
101
|
+
if time.time() >= t_max:
|
102
|
+
break # Exit if the timeout is reached
|
88
103
|
try:
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
)
|
104
|
+
self.connection = rpyc.connect(self.host, self.port)
|
105
|
+
self.connection.ping()
|
106
|
+
print("Server is ready.")
|
107
|
+
return
|
108
|
+
except Exception:
|
109
|
+
time.sleep(delay)
|
110
|
+
|
111
|
+
raise TimeoutError(
|
112
|
+
f"Server at {self.host}:{self.port} not ready within {self.timeout} seconds."
|
113
|
+
)
|
100
114
|
|
101
115
|
def close(self):
|
102
116
|
"""Close the connection."""
|
@@ -232,6 +246,14 @@ class Client:
|
|
232
246
|
def exit(self):
|
233
247
|
"""Shuts down the Mechanical instance."""
|
234
248
|
print("Requesting server shutdown ...")
|
235
|
-
self.
|
249
|
+
self.service_exit()
|
236
250
|
self.connection.close()
|
237
251
|
print("Disconnected from server")
|
252
|
+
|
253
|
+
def __del__(self): # pragma: no cover
|
254
|
+
"""Clean up on exit."""
|
255
|
+
if self._cleanup_on_exit:
|
256
|
+
try:
|
257
|
+
self.exit()
|
258
|
+
except Exception as e:
|
259
|
+
print(f"Failed to exit cleanly: {e}")
|
@@ -23,6 +23,8 @@
|
|
23
23
|
|
24
24
|
import fnmatch
|
25
25
|
import os
|
26
|
+
import threading
|
27
|
+
import time
|
26
28
|
import typing
|
27
29
|
|
28
30
|
import rpyc
|
@@ -50,32 +52,28 @@ class MechanicalService(rpyc.Service):
|
|
50
52
|
self._install_class(impl)
|
51
53
|
self.EMBEDDED = True
|
52
54
|
|
55
|
+
def on_connect(self, conn):
|
56
|
+
"""Handle client connection."""
|
57
|
+
print("Client connected")
|
58
|
+
|
59
|
+
def on_disconnect(self, conn):
|
60
|
+
"""Handle client disconnection."""
|
61
|
+
print("Client disconnected")
|
62
|
+
|
53
63
|
def _install_functions(self, methods):
|
54
64
|
"""Install the given list of methods."""
|
55
65
|
[self._install_function(method) for method in methods]
|
56
66
|
|
57
67
|
def _install_class(self, impl):
|
58
68
|
"""Install methods from the given implemented class."""
|
59
|
-
print("Install class")
|
60
69
|
if impl is None:
|
61
70
|
return
|
62
|
-
print("Installing methods from class")
|
63
71
|
for methodname, method, methodtype in get_remote_methods(impl):
|
64
|
-
print(f"installing {methodname} of {impl}")
|
65
72
|
if methodtype == MethodType.METHOD:
|
66
73
|
self._install_method(method)
|
67
74
|
elif methodtype == MethodType.PROP:
|
68
75
|
self._install_property(method, methodname)
|
69
76
|
|
70
|
-
def on_connect(self, conn):
|
71
|
-
"""Handle client connection."""
|
72
|
-
print("Client connected")
|
73
|
-
print(self._backgroundapp.app)
|
74
|
-
|
75
|
-
def on_disconnect(self, conn):
|
76
|
-
"""Handle client disconnection."""
|
77
|
-
print("Client disconnected")
|
78
|
-
|
79
77
|
def _curry_property(self, prop, propname, get: bool):
|
80
78
|
"""Curry the given property."""
|
81
79
|
|
@@ -157,7 +155,6 @@ class MechanicalService(rpyc.Service):
|
|
157
155
|
|
158
156
|
def _install_function(self, function):
|
159
157
|
"""Install a functions with inner and exposed pairs."""
|
160
|
-
print(f"Installing {function}")
|
161
158
|
exposed_name = f"exposed_{function.__name__}"
|
162
159
|
inner_name = f"inner_{function.__name__}"
|
163
160
|
|
@@ -211,8 +208,11 @@ class MechanicalService(rpyc.Service):
|
|
211
208
|
|
212
209
|
def exposed_service_exit(self):
|
213
210
|
"""Exit the server."""
|
211
|
+
print("Shutting down server ...")
|
214
212
|
self._backgroundapp.stop()
|
215
213
|
self._backgroundapp = None
|
214
|
+
self._server.stop_async()
|
215
|
+
print("Server stopped")
|
216
216
|
|
217
217
|
|
218
218
|
class MechanicalEmbeddedServer:
|
@@ -231,7 +231,7 @@ class MechanicalEmbeddedServer:
|
|
231
231
|
self._background_app = BackgroundApp(version=version)
|
232
232
|
self._service = service
|
233
233
|
self._methods = methods
|
234
|
-
|
234
|
+
self._exit_thread: threading.Thread = None
|
235
235
|
|
236
236
|
self._port = self.get_free_port(port)
|
237
237
|
if impl is None:
|
@@ -241,6 +241,7 @@ class MechanicalEmbeddedServer:
|
|
241
241
|
|
242
242
|
my_service = self._service(self._background_app, self._methods, self._impl)
|
243
243
|
self._server = ThreadedServer(my_service, port=self._port)
|
244
|
+
my_service._server = self
|
244
245
|
|
245
246
|
@staticmethod
|
246
247
|
def get_free_port(port=None):
|
@@ -270,8 +271,28 @@ class MechanicalEmbeddedServer:
|
|
270
271
|
print("User interrupt!")
|
271
272
|
finally:
|
272
273
|
conn.close()"""
|
274
|
+
print("Server exited!")
|
275
|
+
self._wait_exit()
|
273
276
|
self._exited = True
|
274
277
|
|
278
|
+
def _wait_exit(self) -> None:
|
279
|
+
if self._exit_thread is None:
|
280
|
+
return
|
281
|
+
self._exit_thread.join()
|
282
|
+
|
283
|
+
def stop_async(self):
|
284
|
+
"""Return immediately but will stop the server."""
|
285
|
+
|
286
|
+
def stop_f(): # wait for all connections to close
|
287
|
+
while len(self._server.clients) > 0:
|
288
|
+
time.sleep(0.005)
|
289
|
+
self._background_app.stop()
|
290
|
+
self._server.close()
|
291
|
+
self._exited = True
|
292
|
+
|
293
|
+
self._exit_thread = threading.Thread(target=stop_f)
|
294
|
+
self._exit_thread.start()
|
295
|
+
|
275
296
|
def stop(self) -> None:
|
276
297
|
"""Stop the server."""
|
277
298
|
print("Stopping the server...")
|
@@ -102,12 +102,10 @@ def get_remote_methods(
|
|
102
102
|
A tuple containing the method name and the method itself
|
103
103
|
for each remote method found in the object
|
104
104
|
"""
|
105
|
-
print(f"Getting remote methods on {obj}")
|
106
105
|
objclass = obj.__class__
|
107
106
|
for attrname in dir(obj):
|
108
107
|
if attrname.startswith("__"):
|
109
108
|
continue
|
110
|
-
print(attrname)
|
111
109
|
if hasattr(objclass, attrname):
|
112
110
|
class_attribute = getattr(objclass, attrname)
|
113
111
|
if isinstance(class_attribute, property):
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Copyright (C) 2022 - 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
|
+
"""A class to speed up bulk user interactions using Ansys ACT Mechanical Transaction."""
|
23
|
+
|
24
|
+
|
25
|
+
class Transaction: # When ansys-pythonnet issue #14 is fixed, this class will be removed
|
26
|
+
"""
|
27
|
+
A class to speed up bulk user interactions using Ansys ACT Mechanical Transaction.
|
28
|
+
|
29
|
+
Example
|
30
|
+
-------
|
31
|
+
>>> with Transaction() as transaction:
|
32
|
+
... pass # Perform bulk user interactions here
|
33
|
+
...
|
34
|
+
"""
|
35
|
+
|
36
|
+
def __init__(self):
|
37
|
+
"""Initialize the Transaction class."""
|
38
|
+
import clr
|
39
|
+
|
40
|
+
clr.AddReference("Ansys.ACT.WB1")
|
41
|
+
import Ansys
|
42
|
+
|
43
|
+
self._transaction = Ansys.ACT.Mechanical.Transaction()
|
44
|
+
|
45
|
+
def __enter__(self):
|
46
|
+
"""Enter the context of the transaction."""
|
47
|
+
return self
|
48
|
+
|
49
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
50
|
+
"""Exit the context of the transaction and disposes of resources."""
|
51
|
+
self._transaction.Dispose()
|
@@ -28,6 +28,7 @@ from pathlib import Path
|
|
28
28
|
import re
|
29
29
|
import site
|
30
30
|
import sys
|
31
|
+
import warnings
|
31
32
|
|
32
33
|
import ansys.tools.path as atp
|
33
34
|
import click
|
@@ -151,13 +152,23 @@ def _cli_impl(
|
|
151
152
|
stubs_location = get_stubs_location()
|
152
153
|
# Get all revision numbers available in ansys-mechanical-stubs
|
153
154
|
revns = get_stubs_versions(stubs_location)
|
154
|
-
|
155
|
-
if revision
|
155
|
+
|
156
|
+
# Check if the user revision number is less or greater than the min and max revisions
|
157
|
+
# in the ansys-mechanical-stubs package location
|
158
|
+
if revision < min(revns):
|
156
159
|
raise Exception(f"PyMechanical Stubs are not available for {revision}")
|
157
|
-
elif
|
160
|
+
elif revision > max(revns):
|
161
|
+
warnings.warn(
|
162
|
+
f"PyMechanical Stubs are not available for {revision}. Using {max(revns)} instead.",
|
163
|
+
stacklevel=2,
|
164
|
+
)
|
165
|
+
revision = max(revns)
|
166
|
+
|
167
|
+
# Check the IDE and raise an exception if it's not VS Code
|
168
|
+
if ide != "vscode":
|
158
169
|
raise Exception(f"{ide} is not supported at the moment.")
|
159
|
-
|
160
|
-
|
170
|
+
|
171
|
+
return _vscode_impl(target, revision)
|
161
172
|
|
162
173
|
|
163
174
|
@click.command()
|
@@ -202,8 +213,11 @@ def cli(ide: str, target: str, revision: int) -> None:
|
|
202
213
|
$ ansys-mechanical-ideconfig --ide vscode --target user --revision 251
|
203
214
|
|
204
215
|
"""
|
205
|
-
|
206
|
-
|
216
|
+
if not revision:
|
217
|
+
exe = atp.get_mechanical_path(allow_input=False, version=revision)
|
218
|
+
version = atp.version_from_path("mechanical", exe)
|
219
|
+
else:
|
220
|
+
version = revision
|
207
221
|
|
208
222
|
return _cli_impl(
|
209
223
|
ide,
|
@@ -30,6 +30,8 @@ import glob
|
|
30
30
|
import os
|
31
31
|
import pathlib
|
32
32
|
import socket
|
33
|
+
import subprocess # nosec: B404
|
34
|
+
import sys
|
33
35
|
import threading
|
34
36
|
import time
|
35
37
|
from typing import Optional
|
@@ -1942,6 +1944,48 @@ def launch_grpc(
|
|
1942
1944
|
return port
|
1943
1945
|
|
1944
1946
|
|
1947
|
+
def launch_rpyc(
|
1948
|
+
exec_file="",
|
1949
|
+
batch=True,
|
1950
|
+
port=MECHANICAL_DEFAULT_PORT,
|
1951
|
+
additional_switches=None,
|
1952
|
+
additional_envs=None,
|
1953
|
+
verbose=False,
|
1954
|
+
) -> int:
|
1955
|
+
"""Start Mechanical locally in RPyC mode."""
|
1956
|
+
_version = atp.version_from_path("mechanical", exec_file)
|
1957
|
+
if _version < 232:
|
1958
|
+
raise VersionError("The Mechanical gRPC interface requires Mechanical 2023 R2 or later.")
|
1959
|
+
|
1960
|
+
# get the next available port
|
1961
|
+
local_ports = pymechanical.LOCAL_PORTS
|
1962
|
+
if port is None:
|
1963
|
+
if not local_ports:
|
1964
|
+
port = MECHANICAL_DEFAULT_PORT
|
1965
|
+
else:
|
1966
|
+
port = max(local_ports) + 1
|
1967
|
+
|
1968
|
+
while port_in_use(port) or port in local_ports:
|
1969
|
+
port += 1
|
1970
|
+
local_ports.append(port)
|
1971
|
+
|
1972
|
+
server_script = """
|
1973
|
+
import sys
|
1974
|
+
from ansys.mechanical.core.embedding.rpc import MechanicalDefaultServer
|
1975
|
+
server = MechanicalDefaultServer(port=int(sys.argv[1]), version=int(sys.argv[2]))
|
1976
|
+
server.start()
|
1977
|
+
"""
|
1978
|
+
env_copy = os.environ.copy()
|
1979
|
+
try:
|
1980
|
+
embedded_server = subprocess.Popen(
|
1981
|
+
[sys.executable, "-c", server_script, str(port), str(_version)], env=env_copy
|
1982
|
+
) # nosec: B603
|
1983
|
+
except:
|
1984
|
+
raise RuntimeError("Unable to start the embedded server.")
|
1985
|
+
|
1986
|
+
return port
|
1987
|
+
|
1988
|
+
|
1945
1989
|
def launch_remote_mechanical(
|
1946
1990
|
version=None,
|
1947
1991
|
) -> (grpc.Channel, Optional["Instance"]): # pragma: no cover
|
@@ -2004,6 +2048,7 @@ def launch_mechanical(
|
|
2004
2048
|
cleanup_on_exit=True,
|
2005
2049
|
version=None,
|
2006
2050
|
keep_connection_alive=True,
|
2051
|
+
backend="mechanical",
|
2007
2052
|
) -> Mechanical:
|
2008
2053
|
"""Start Mechanical locally.
|
2009
2054
|
|
@@ -2086,6 +2131,9 @@ def launch_mechanical(
|
|
2086
2131
|
keep_connection_alive : bool, optional
|
2087
2132
|
Whether to keep the gRPC connection alive by running a background thread
|
2088
2133
|
and making dummy calls for remote connections. The default is ``True``.
|
2134
|
+
backend : str, optional
|
2135
|
+
Type of RPC to use. The default is ``"mechanical"`` which uses grpc.
|
2136
|
+
The other option is ``"python"`` which uses RPyC.
|
2089
2137
|
|
2090
2138
|
Returns
|
2091
2139
|
-------
|
@@ -2239,23 +2287,31 @@ def launch_mechanical(
|
|
2239
2287
|
"additional_envs": additional_envs,
|
2240
2288
|
}
|
2241
2289
|
|
2242
|
-
|
2243
|
-
|
2244
|
-
|
2245
|
-
|
2246
|
-
|
2247
|
-
|
2248
|
-
|
2249
|
-
|
2250
|
-
|
2251
|
-
|
2252
|
-
|
2253
|
-
|
2254
|
-
|
2290
|
+
if backend == "mechanical":
|
2291
|
+
try:
|
2292
|
+
port = launch_grpc(port=port, verbose=verbose_mechanical, **start_parm)
|
2293
|
+
start_parm["local"] = True
|
2294
|
+
mechanical = Mechanical(
|
2295
|
+
ip=ip,
|
2296
|
+
port=port,
|
2297
|
+
loglevel=loglevel,
|
2298
|
+
log_file=log_file,
|
2299
|
+
log_mechanical=log_mechanical,
|
2300
|
+
timeout=start_timeout,
|
2301
|
+
cleanup_on_exit=cleanup_on_exit,
|
2302
|
+
keep_connection_alive=keep_connection_alive,
|
2303
|
+
**start_parm,
|
2304
|
+
)
|
2305
|
+
except Exception as exception: # pragma: no cover
|
2306
|
+
# pass
|
2307
|
+
raise exception
|
2308
|
+
elif backend == "python":
|
2309
|
+
port = launch_rpyc(port=port, **start_parm)
|
2310
|
+
from ansys.mechanical.core.embedding.rpc.client import Client
|
2311
|
+
|
2312
|
+
mechanical = Client(
|
2313
|
+
"localhost", port, timeout=start_timeout, cleanup_on_exit=cleanup_on_exit
|
2255
2314
|
)
|
2256
|
-
except Exception as exception: # pragma: no cover
|
2257
|
-
# pass
|
2258
|
-
raise exception
|
2259
2315
|
|
2260
2316
|
return mechanical
|
2261
2317
|
|
{ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: ansys-mechanical-core
|
3
|
-
Version: 0.11.
|
3
|
+
Version: 0.11.14
|
4
4
|
Summary: A python wrapper for Ansys Mechanical
|
5
5
|
Keywords: pymechanical,mechanical,ansys,pyansys
|
6
6
|
Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.13
|
17
17
|
Classifier: License :: OSI Approved :: MIT License
|
18
18
|
Classifier: Operating System :: OS Independent
|
19
|
+
License-File: LICENSE
|
19
20
|
Requires-Dist: ansys-api-mechanical==0.1.2
|
20
21
|
Requires-Dist: ansys-mechanical-env==0.1.9
|
21
22
|
Requires-Dist: ansys-mechanical-stubs==0.1.6
|
@@ -29,28 +30,28 @@ Requires-Dist: protobuf>=3.12.2,<6
|
|
29
30
|
Requires-Dist: psutil>=6
|
30
31
|
Requires-Dist: tqdm>=4.45.0
|
31
32
|
Requires-Dist: requests>=2,<3
|
32
|
-
Requires-Dist: sphinx==8.1
|
33
|
-
Requires-Dist: ansys-sphinx-theme[autoapi, changelog]==1.3.
|
33
|
+
Requires-Dist: sphinx==8.2.1 ; extra == "doc"
|
34
|
+
Requires-Dist: ansys-sphinx-theme[autoapi, changelog]==1.3.2 ; extra == "doc"
|
34
35
|
Requires-Dist: grpcio==1.70.0 ; extra == "doc"
|
35
36
|
Requires-Dist: imageio-ffmpeg==0.6.0 ; extra == "doc"
|
36
37
|
Requires-Dist: imageio==2.37.0 ; extra == "doc"
|
37
38
|
Requires-Dist: jupyter_sphinx==0.5.3 ; extra == "doc"
|
38
39
|
Requires-Dist: jupyterlab>=3.2.8 ; extra == "doc"
|
39
40
|
Requires-Dist: matplotlib==3.10.0 ; extra == "doc"
|
40
|
-
Requires-Dist: numpy==2.2.
|
41
|
+
Requires-Dist: numpy==2.2.3 ; extra == "doc"
|
41
42
|
Requires-Dist: numpydoc==1.8.0 ; extra == "doc"
|
42
43
|
Requires-Dist: pandas==2.2.3 ; extra == "doc"
|
43
|
-
Requires-Dist: panel==1.6.
|
44
|
+
Requires-Dist: panel==1.6.1 ; extra == "doc"
|
44
45
|
Requires-Dist: plotly==6.0.0 ; extra == "doc"
|
45
46
|
Requires-Dist: pypandoc==1.15 ; extra == "doc"
|
46
47
|
Requires-Dist: pytest-sphinx==0.6.3 ; extra == "doc"
|
47
48
|
Requires-Dist: pythreejs==2.4.2 ; extra == "doc"
|
48
49
|
Requires-Dist: pyvista>=0.39.1 ; extra == "doc"
|
49
50
|
Requires-Dist: sphinx-autobuild==2024.10.3 ; extra == "doc"
|
50
|
-
Requires-Dist: sphinx-autodoc-typehints==3.0
|
51
|
+
Requires-Dist: sphinx-autodoc-typehints==3.1.0 ; extra == "doc"
|
51
52
|
Requires-Dist: sphinx-copybutton==0.5.2 ; extra == "doc"
|
52
53
|
Requires-Dist: sphinx_design==0.6.1 ; extra == "doc"
|
53
|
-
Requires-Dist: sphinx-gallery==0.
|
54
|
+
Requires-Dist: sphinx-gallery==0.19.0 ; extra == "doc"
|
54
55
|
Requires-Dist: sphinx-notfound-page==1.1.0 ; extra == "doc"
|
55
56
|
Requires-Dist: sphinxcontrib-websupport==2.0.0 ; extra == "doc"
|
56
57
|
Requires-Dist: sphinxemoji==0.3.1 ; extra == "doc"
|
@@ -60,7 +61,7 @@ Requires-Dist: toolz==1.0.0 ; extra == "rpc"
|
|
60
61
|
Requires-Dist: pytest==8.3.4 ; extra == "tests"
|
61
62
|
Requires-Dist: pytest-cov==6.0.0 ; extra == "tests"
|
62
63
|
Requires-Dist: pytest-print==1.0.2 ; extra == "tests"
|
63
|
-
Requires-Dist: psutil==
|
64
|
+
Requires-Dist: psutil==7.0.0 ; extra == "tests"
|
64
65
|
Requires-Dist: ansys-tools-visualization-interface>=0.2.6 ; extra == "viz"
|
65
66
|
Requires-Dist: usd-core==24.11 ; extra == "viz"
|
66
67
|
Project-URL: Changelog, https://mechanical.docs.pyansys.com/version/stable/changelog.html
|
@@ -1,29 +1,32 @@
|
|
1
|
-
ansys/mechanical/core/__init__.py,sha256=
|
1
|
+
ansys/mechanical/core/__init__.py,sha256=Cv17LwEk9jFhzFNqoB7afNCTnm2ZfW7_Dm8BS0YWuNY,2522
|
2
2
|
ansys/mechanical/core/_version.py,sha256=nRlEBl4c6kNOE78hhqJwYuPk86jhu70lOSRuZphT81M,1763
|
3
3
|
ansys/mechanical/core/errors.py,sha256=k0hJ89FwbFexLsjVApCbqfy2K7d-MekTPf3-QdtXZK4,4508
|
4
4
|
ansys/mechanical/core/feature_flags.py,sha256=bIRHaURLi70Yor1aJH3Fhlt9xvvyr9GG7JcJ1V59GNg,2078
|
5
|
-
ansys/mechanical/core/ide_config.py,sha256=
|
5
|
+
ansys/mechanical/core/ide_config.py,sha256=toFjpdy2Pcr3DOlNYOYp0D4nIp07xcL62D1jLlE4DN8,7739
|
6
6
|
ansys/mechanical/core/launcher.py,sha256=Rd5kDcC58MZIjsk2d40Bx4qc0DVHzrYuNA3irDvsFKA,6675
|
7
7
|
ansys/mechanical/core/logging.py,sha256=TmIY5L-IrkyAQMKszotcbVCxyHLsMZQDAwbvcrSKwfs,24554
|
8
|
-
ansys/mechanical/core/mechanical.py,sha256=
|
8
|
+
ansys/mechanical/core/mechanical.py,sha256=y42-7LVcStGLAR1pDb5GHeja98hmsBJCnLGiDq_yC64,85508
|
9
9
|
ansys/mechanical/core/misc.py,sha256=f_LjwIvCGaHSIKJ6LuREbCr7gbv9rg2aFQaQ28Edna8,5369
|
10
10
|
ansys/mechanical/core/pool.py,sha256=xii4fNxNH_Xnyom9-ZpvsyXCxoUxa2mDu8brS339B2Y,26572
|
11
11
|
ansys/mechanical/core/run.py,sha256=wUsGPyZx2NwNlrdzIO1cWmDAZeZU0tOY1OvT-8pqjaw,9928
|
12
12
|
ansys/mechanical/core/embedding/__init__.py,sha256=QAUe-offKZZDPz0IYBIUtYi4Dgt02_U93yTeSWXO9fU,1356
|
13
13
|
ansys/mechanical/core/embedding/addins.py,sha256=6n3wCaD36cBbXWCbpniuABgvW6uBSN6xYXA5KkNgfLg,2167
|
14
|
-
ansys/mechanical/core/embedding/app.py,sha256=
|
14
|
+
ansys/mechanical/core/embedding/app.py,sha256=207lfoQIy9njNPgidnlICT3RNQXlsMDRtKbIcAoftkA,24152
|
15
15
|
ansys/mechanical/core/embedding/app_libraries.py,sha256=_czRZ5cPwRo9SIZNitlgmBf2riLdzlGmmD4BJt9Nvng,2922
|
16
16
|
ansys/mechanical/core/embedding/appdata.py,sha256=98BYek_AKH5LaN5J3o8Mx8QDy23_6EpwKyBSiQpiu0E,4273
|
17
17
|
ansys/mechanical/core/embedding/background.py,sha256=dNwi45q8y8iXpMKathDMQd2k7CUfl4X6wIhngQvJcEc,4178
|
18
18
|
ansys/mechanical/core/embedding/cleanup_gui.py,sha256=TEF3l4A7UxMacmlkUwBBymTdqM6h8Be9piID4Hpn_jg,2354
|
19
|
-
ansys/mechanical/core/embedding/enum_importer.py,sha256
|
20
|
-
ansys/mechanical/core/embedding/
|
21
|
-
ansys/mechanical/core/embedding/
|
19
|
+
ansys/mechanical/core/embedding/enum_importer.py,sha256=NpdEG6HzEDuHYJAfhoMuh5AeXypegNL7NKXyUQyrZwM,1605
|
20
|
+
ansys/mechanical/core/embedding/global_importer.py,sha256=Ww-tVXx0fCXC8-_yZxzbpr3I1xJ49c80ZBdAWHwvbh0,2188
|
21
|
+
ansys/mechanical/core/embedding/imports.py,sha256=uRror4o4PGUjnUPF_dZXkHP5uy1dIdWdqkeN0jbwbY4,3414
|
22
|
+
ansys/mechanical/core/embedding/initializer.py,sha256=4LgD5AG5YCmWb_R1EWY8ljq8N_YwnCwtRR1J3dQxVRU,8199
|
22
23
|
ansys/mechanical/core/embedding/loader.py,sha256=e2KWBrVv5001MP6DPJWI0UwrEauUnlTLpz9X6WYFdhk,2503
|
24
|
+
ansys/mechanical/core/embedding/messages.py,sha256=EteUAZe5-xwSZ92pNdnAUeMvwNn4_MU8ScokLMJ-kkc,6553
|
23
25
|
ansys/mechanical/core/embedding/poster.py,sha256=-V1GYrvRDyv8nbaBJze7Uo3PUb1hfOIidf1YI7-cT60,3065
|
24
26
|
ansys/mechanical/core/embedding/resolver.py,sha256=VrUbSV0oLsz0fhoR8C4M9IFFElV-j7nvUaJlO4Su4r0,2200
|
25
27
|
ansys/mechanical/core/embedding/runtime.py,sha256=6ZQsD1qvB2VMJsoLkm9vvsWbVX-buj8jLDAm4Qyc65k,2982
|
26
28
|
ansys/mechanical/core/embedding/shims.py,sha256=LP5px-ED4JNbqFEpYnmBkGiGDdfDkLQ-v1tNnPbz3E8,1732
|
29
|
+
ansys/mechanical/core/embedding/transaction.py,sha256=rU68v9CTrbZ9yQmAtbQDHoKpj5TcoCWmCnSX08pT7JM,2053
|
27
30
|
ansys/mechanical/core/embedding/ui.py,sha256=1XXkKSvui9iHKGqFROJQZMW-3iY-Hh2i1Ixq8Iav8cY,8480
|
28
31
|
ansys/mechanical/core/embedding/utils.py,sha256=7KSFCl9VM_WhrQEtI3Jc9OwhmH9wI7PH0n17ab_ytfo,1900
|
29
32
|
ansys/mechanical/core/embedding/warnings.py,sha256=Iyo95YOneMdCxOImXjnohhQZ86tD3xcnvJPUstlvHy0,3071
|
@@ -33,17 +36,17 @@ ansys/mechanical/core/embedding/logger/linux_api.py,sha256=wM95m4ArlF3gvqKFvKP7D
|
|
33
36
|
ansys/mechanical/core/embedding/logger/sinks.py,sha256=-lAS-M7k3WHAblbrM7nzpOBJiCjN8e6i52GoEeQo_gE,1392
|
34
37
|
ansys/mechanical/core/embedding/logger/windows_api.py,sha256=GoFPfO-_umcCRAQeYrEdYQCTYpeNLB_IrY4hHh_LmTo,5276
|
35
38
|
ansys/mechanical/core/embedding/rpc/__init__.py,sha256=Vk1nDMlxG1pCW7aWf6BEEqBR1UDIaQCUIVyin5uatBQ,1650
|
36
|
-
ansys/mechanical/core/embedding/rpc/client.py,sha256=
|
37
|
-
ansys/mechanical/core/embedding/rpc/server.py,sha256=
|
38
|
-
ansys/mechanical/core/embedding/rpc/utils.py,sha256=
|
39
|
+
ansys/mechanical/core/embedding/rpc/client.py,sha256=l2Zx_1LiyiXf_-uy9RPmETAZcL6VnRfwxrCzT6qYASo,9649
|
40
|
+
ansys/mechanical/core/embedding/rpc/server.py,sha256=sjrA_wUtjpOOXvHUni7YQS5Ony2pz5CnmKfuODuXomU,13677
|
41
|
+
ansys/mechanical/core/embedding/rpc/utils.py,sha256=yFK4Je70ytxSigu5f_TcHUACToGGz4TouBluogGWeQc,4272
|
39
42
|
ansys/mechanical/core/embedding/viz/__init__.py,sha256=KHZQAzlfgEVhi-G0msA6ca1o-2RecoNGzkpYfBIoCTA,1206
|
40
43
|
ansys/mechanical/core/embedding/viz/embedding_plotter.py,sha256=d2GjQiQgDHXfNTgETEIKRZYymkvB8-3KBHs7fF9PW_c,3689
|
41
44
|
ansys/mechanical/core/embedding/viz/usd_converter.py,sha256=kMKmGLThbWf7iR9bYn24mdmgKBkLDdkwdHrOokFvg_U,5329
|
42
45
|
ansys/mechanical/core/embedding/viz/utils.py,sha256=AYvp0okbEk3y9611eGAtvhgh65ytfpHkywVT7qk_liQ,3660
|
43
46
|
ansys/mechanical/core/examples/__init__.py,sha256=Y0T8CKmaALL3diLfhsz3opfBgckD85DfHdzDrVsSwzg,1267
|
44
47
|
ansys/mechanical/core/examples/downloads.py,sha256=5_Krq3HqVeAeD4z3dx9uujLk1u6rPFoAuwQus9eYWjg,4295
|
45
|
-
ansys_mechanical_core-0.11.
|
46
|
-
ansys_mechanical_core-0.11.
|
47
|
-
ansys_mechanical_core-0.11.
|
48
|
-
ansys_mechanical_core-0.11.
|
49
|
-
ansys_mechanical_core-0.11.
|
48
|
+
ansys_mechanical_core-0.11.14.dist-info/entry_points.txt,sha256=tErx6bIM27HGgwyM6ryyTUTw30Ab2F9J3FFkX2TPkhI,130
|
49
|
+
ansys_mechanical_core-0.11.14.dist-info/licenses/LICENSE,sha256=AVOPDv4UX26lKidhDvFf_fMR13Pr-n4wVAYSVyvD7Ww,1098
|
50
|
+
ansys_mechanical_core-0.11.14.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
|
51
|
+
ansys_mechanical_core-0.11.14.dist-info/METADATA,sha256=DewU09uk_OoIQWk9t-epc2gLOb-qBWjcRkweFOz46uM,10509
|
52
|
+
ansys_mechanical_core-0.11.14.dist-info/RECORD,,
|
{ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info}/entry_points.txt
RENAMED
File without changes
|
{ansys_mechanical_core-0.11.13.dist-info → ansys_mechanical_core-0.11.14.dist-info/licenses}/LICENSE
RENAMED
File without changes
|