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.
@@ -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)
@@ -25,7 +25,6 @@
25
25
  A useful subset of what is imported by
26
26
  Ansys Inc/v{NNN}/ACT/apis/Mechanical.py
27
27
  """
28
-
29
28
  import clr
30
29
 
31
30
  clr.AddReference("Ansys.Mechanical.DataModel")
@@ -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
- import clr # isort: skip
50
-
51
- clr.AddReference("System.Collections")
52
- clr.AddReference("Ansys.ACT.WB1")
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
- vars["MechanicalEnums"] = MechanicalEnums
71
- # Graphics
72
- vars["Point"] = Point
73
- vars["SectionPlane"] = SectionPlane
74
- # Math
75
- vars["Point2D"] = Point2D
76
- vars["Point3D"] = Point3D
77
- vars["Vector3D"] = Vector3D
78
- vars["VariableDefinitionType"] = VariableDefinitionType
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
- warnings.warn(
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
- warnings.warn(
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 ``10000`` is used.
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
- print(f"Installed methods")
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
- while time.time() < t_max:
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
- conn = rpyc.connect(self.host, self.port)
90
- conn.ping() # Simple ping to check if the connection is healthy
91
- conn.close()
92
- print("Server is ready to connect")
93
- break
94
- except:
95
- time.sleep(2)
96
- else:
97
- raise TimeoutError(
98
- f"Server at {self.host}:{self.port} not ready within {self.timeout} seconds."
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.root.service_exit()
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
- print("Initializing Mechanical ...")
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
- # Check the IDE and raise an exception if it's not VS Code
155
- if revision < min(revns) or revision > max(revns):
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 ide != "vscode":
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
- else:
160
- return _vscode_impl(target, revision)
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
- exe = atp.get_mechanical_path(allow_input=False, version=revision)
206
- version = atp.version_from_path("mechanical", exe)
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
- try:
2243
- port = launch_grpc(port=port, verbose=verbose_mechanical, **start_parm)
2244
- start_parm["local"] = True
2245
- mechanical = Mechanical(
2246
- ip=ip,
2247
- port=port,
2248
- loglevel=loglevel,
2249
- log_file=log_file,
2250
- log_mechanical=log_mechanical,
2251
- timeout=start_timeout,
2252
- cleanup_on_exit=cleanup_on_exit,
2253
- keep_connection_alive=keep_connection_alive,
2254
- **start_parm,
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
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: ansys-mechanical-core
3
- Version: 0.11.13
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.3 ; extra == "doc"
33
- Requires-Dist: ansys-sphinx-theme[autoapi, changelog]==1.3.1 ; extra == "doc"
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.2 ; extra == "doc"
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.0 ; extra == "doc"
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.1 ; extra == "doc"
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.18.0 ; extra == "doc"
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==6.1.1 ; extra == "tests"
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=u0OpMtxVeEO9GvfxzUN0yf0x3mtox0Gjn4f0kO1qk7A,2564
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=Yic_KFrxuZA0HUsuRsfld-j37YnfYuM97PRLYhnm-Y8,7334
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=FNxMHv8FWcpP92jYqNTo6uPlmH0HnsGRHSnivaVyYjg,83663
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=spB7yuxHO3n7I_UkQVnRaYft3iO77LuCUpExtzddLcU,22084
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=-DN4N5Sh-nRQAud4izyTfo-EvGwOfGAiZ8zELPiuj8A,1606
20
- ansys/mechanical/core/embedding/imports.py,sha256=m-ywpl29iB1r57Mt9qS2GYFF2HfZ37kNt-01OkKqAwM,4414
21
- ansys/mechanical/core/embedding/initializer.py,sha256=knq3HzfQD8-yUB-cGHjzA4IKG_bOsEPd57tle_cvVNs,8086
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=w8S_dzPmtR4qwKTdPCbrFTXhiEvnqda-nEBSsdOqexM,8841
37
- ansys/mechanical/core/embedding/rpc/server.py,sha256=l0nHrptN3tui1iDfAZ3MhrH1pex_dEtRDFIrsPfrZC8,13101
38
- ansys/mechanical/core/embedding/rpc/utils.py,sha256=Jr40xwvGCnlZZJE4fw6QoXsb8fqeGhres8bwE9ISez8,4342
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.13.dist-info/entry_points.txt,sha256=tErx6bIM27HGgwyM6ryyTUTw30Ab2F9J3FFkX2TPkhI,130
46
- ansys_mechanical_core-0.11.13.dist-info/LICENSE,sha256=AVOPDv4UX26lKidhDvFf_fMR13Pr-n4wVAYSVyvD7Ww,1098
47
- ansys_mechanical_core-0.11.13.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
48
- ansys_mechanical_core-0.11.13.dist-info/METADATA,sha256=lrlhVb1Cw40iMS_9bpm8gNpu9t4lnqIMck3rZymH0Gs,10487
49
- ansys_mechanical_core-0.11.13.dist-info/RECORD,,
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.10.1
2
+ Generator: flit 3.11.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any