ansys-mechanical-core 0.11.14__py3-none-any.whl → 0.11.16__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 +3 -3
- ansys/mechanical/core/embedding/app.py +26 -12
- ansys/mechanical/core/embedding/appdata.py +26 -22
- ansys/mechanical/core/embedding/enum_importer.py +6 -0
- ansys/mechanical/core/embedding/{viz → graphics}/embedding_plotter.py +1 -1
- ansys/mechanical/core/embedding/initializer.py +70 -0
- ansys/mechanical/core/embedding/messages.py +27 -22
- ansys/mechanical/core/embedding/resolver.py +1 -1
- ansys/mechanical/core/embedding/rpc/__init__.py +3 -7
- ansys/mechanical/core/embedding/rpc/client.py +19 -5
- ansys/mechanical/core/embedding/rpc/default_server.py +131 -0
- ansys/mechanical/core/embedding/rpc/server.py +146 -158
- ansys/mechanical/core/embedding/rpc/utils.py +18 -0
- ansys/mechanical/core/embedding/runtime.py +6 -0
- ansys/mechanical/core/ide_config.py +1 -0
- ansys/mechanical/core/mechanical.py +24 -12
- {ansys_mechanical_core-0.11.14.dist-info → ansys_mechanical_core-0.11.16.dist-info}/METADATA +15 -12
- {ansys_mechanical_core-0.11.14.dist-info → ansys_mechanical_core-0.11.16.dist-info}/RECORD +24 -23
- {ansys_mechanical_core-0.11.14.dist-info → ansys_mechanical_core-0.11.16.dist-info}/WHEEL +1 -1
- /ansys/mechanical/core/embedding/{viz → graphics}/__init__.py +0 -0
- /ansys/mechanical/core/embedding/{viz → graphics}/usd_converter.py +0 -0
- /ansys/mechanical/core/embedding/{viz → graphics}/utils.py +0 -0
- {ansys_mechanical_core-0.11.14.dist-info → ansys_mechanical_core-0.11.16.dist-info}/entry_points.txt +0 -0
- {ansys_mechanical_core-0.11.14.dist-info → ansys_mechanical_core-0.11.16.dist-info}/licenses/LICENSE +0 -0
@@ -21,7 +21,6 @@
|
|
21
21
|
# SOFTWARE.
|
22
22
|
"""Remote Procedure Call (RPC) server."""
|
23
23
|
|
24
|
-
import fnmatch
|
25
24
|
import os
|
26
25
|
import threading
|
27
26
|
import time
|
@@ -31,26 +30,63 @@ import rpyc
|
|
31
30
|
from rpyc.utils.server import ThreadedServer
|
32
31
|
import toolz
|
33
32
|
|
33
|
+
from ansys.mechanical.core.embedding.app import App
|
34
34
|
from ansys.mechanical.core.embedding.background import BackgroundApp
|
35
|
-
|
35
|
+
import ansys.mechanical.core.embedding.utils
|
36
36
|
|
37
|
-
from .utils import MethodType,
|
37
|
+
from .utils import MethodType, get_free_port, get_remote_methods
|
38
38
|
|
39
39
|
# TODO : implement logging
|
40
40
|
|
41
|
-
|
41
|
+
|
42
|
+
class ForegroundAppBackend:
|
43
|
+
"""Backend for the python server where mechanical uses the main thread."""
|
44
|
+
|
45
|
+
def __init__(self, app: App):
|
46
|
+
"""Create a new instance of ForegroundAppBackend."""
|
47
|
+
self._app = app
|
48
|
+
self._poster = app.poster
|
49
|
+
|
50
|
+
def try_post(self, callable: typing.Callable) -> typing.Any:
|
51
|
+
"""Try to post to mechanical's main thread."""
|
52
|
+
return self._poster.try_post(callable)
|
53
|
+
|
54
|
+
def get_app(self) -> App:
|
55
|
+
"""Get the app object."""
|
56
|
+
return self._app
|
57
|
+
|
58
|
+
|
59
|
+
class BackgroundAppBackend:
|
60
|
+
"""Backend for the python server where mechanical uses the background thread."""
|
61
|
+
|
62
|
+
def __init__(self, backgroundapp: BackgroundApp):
|
63
|
+
"""Create a new instance of BackgroundAppBackend."""
|
64
|
+
self._backgroundapp = backgroundapp
|
65
|
+
|
66
|
+
def try_post(self, callable: typing.Callable) -> typing.Any:
|
67
|
+
"""Try to post to mechanical's main thread."""
|
68
|
+
return self._backgroundapp.try_post(callable)
|
69
|
+
|
70
|
+
def get_app(self) -> App:
|
71
|
+
"""Get the app object."""
|
72
|
+
return self._backgroundapp.app
|
42
73
|
|
43
74
|
|
44
75
|
class MechanicalService(rpyc.Service):
|
45
76
|
"""Starts Mechanical app services."""
|
46
77
|
|
47
|
-
def __init__(self,
|
78
|
+
def __init__(self, backend, functions=[], impl=[]):
|
48
79
|
"""Initialize the service."""
|
49
80
|
super().__init__()
|
50
|
-
self.
|
81
|
+
self._backend = backend
|
51
82
|
self._install_functions(functions)
|
52
|
-
self.
|
53
|
-
|
83
|
+
self._install_classes(impl)
|
84
|
+
|
85
|
+
def _try_post(self, callable: typing.Callable) -> typing.Any:
|
86
|
+
return self._backend.try_post(callable)
|
87
|
+
|
88
|
+
def _get_app(self) -> App:
|
89
|
+
return self._backend.get_app()
|
54
90
|
|
55
91
|
def on_connect(self, conn):
|
56
92
|
"""Handle client connection."""
|
@@ -62,8 +98,16 @@ class MechanicalService(rpyc.Service):
|
|
62
98
|
|
63
99
|
def _install_functions(self, methods):
|
64
100
|
"""Install the given list of methods."""
|
101
|
+
if not methods:
|
102
|
+
return
|
65
103
|
[self._install_function(method) for method in methods]
|
66
104
|
|
105
|
+
def _install_classes(self, impl):
|
106
|
+
"""Install the given list of classes."""
|
107
|
+
if not impl:
|
108
|
+
return
|
109
|
+
[self._install_class(_impl) for _impl in impl]
|
110
|
+
|
67
111
|
def _install_class(self, impl):
|
68
112
|
"""Install methods from the given implemented class."""
|
69
113
|
if impl is None:
|
@@ -84,7 +128,7 @@ class MechanicalService(rpyc.Service):
|
|
84
128
|
else:
|
85
129
|
setattr(prop._owner, propname, *arg)
|
86
130
|
|
87
|
-
return self.
|
131
|
+
return self._try_post(curried)
|
88
132
|
|
89
133
|
return posted
|
90
134
|
|
@@ -97,7 +141,7 @@ class MechanicalService(rpyc.Service):
|
|
97
141
|
result = original_method(*args, **kwargs)
|
98
142
|
return result
|
99
143
|
|
100
|
-
return self.
|
144
|
+
return self._try_post(curried)
|
101
145
|
|
102
146
|
return posted
|
103
147
|
|
@@ -108,9 +152,9 @@ class MechanicalService(rpyc.Service):
|
|
108
152
|
|
109
153
|
def posted(*args, **kwargs):
|
110
154
|
def curried():
|
111
|
-
return curried_method(self.
|
155
|
+
return curried_method(self._get_app(), *args, **kwargs)
|
112
156
|
|
113
|
-
return self.
|
157
|
+
return self._try_post(curried)
|
114
158
|
|
115
159
|
return posted
|
116
160
|
|
@@ -209,9 +253,7 @@ class MechanicalService(rpyc.Service):
|
|
209
253
|
def exposed_service_exit(self):
|
210
254
|
"""Exit the server."""
|
211
255
|
print("Shutting down server ...")
|
212
|
-
self.
|
213
|
-
self._backgroundapp = None
|
214
|
-
self._server.stop_async()
|
256
|
+
self._exit_f()
|
215
257
|
print("Server stopped")
|
216
258
|
|
217
259
|
|
@@ -220,184 +262,130 @@ class MechanicalEmbeddedServer:
|
|
220
262
|
|
221
263
|
def __init__(
|
222
264
|
self,
|
223
|
-
service: typing.Type[rpyc.Service] = MechanicalService,
|
224
265
|
port: int = None,
|
225
266
|
version: int = None,
|
226
267
|
methods: typing.List[typing.Callable] = [],
|
227
|
-
impl=
|
268
|
+
impl: typing.List = [],
|
228
269
|
):
|
229
270
|
"""Initialize the server."""
|
230
271
|
self._exited = False
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
self._port = self.get_free_port(port)
|
237
|
-
if impl is None:
|
238
|
-
self._impl = None
|
272
|
+
use_background_app = False
|
273
|
+
if use_background_app:
|
274
|
+
self._app_instance = BackgroundApp(version=version)
|
275
|
+
self._backend = BackgroundAppBackend(self._app_instance)
|
239
276
|
else:
|
240
|
-
self.
|
277
|
+
self._app_instance = App(version=version)
|
278
|
+
self._backend = ForegroundAppBackend(self._app_instance)
|
279
|
+
self._port = get_free_port(port)
|
280
|
+
self._install_methods(methods)
|
281
|
+
self._install_classes(impl)
|
282
|
+
self._server = ThreadedServer(self._create_service(), port=self._port)
|
241
283
|
|
242
|
-
|
243
|
-
|
244
|
-
my_service._server = self
|
284
|
+
def _create_service(self):
|
285
|
+
service = MechanicalService(self._backend, self._methods, self._impl)
|
245
286
|
|
246
|
-
|
247
|
-
|
248
|
-
"""Get free port.
|
287
|
+
def exit_f():
|
288
|
+
self.stop()
|
249
289
|
|
250
|
-
|
251
|
-
|
252
|
-
if port is None:
|
253
|
-
port = PYMECHANICAL_DEFAULT_RPC_PORT
|
290
|
+
service._exit_f = exit_f
|
291
|
+
return service
|
254
292
|
|
255
|
-
|
256
|
-
|
293
|
+
def _is_stopped(self):
|
294
|
+
return self._app_instance is None
|
257
295
|
|
258
|
-
|
296
|
+
def _wait_exit(self) -> None:
|
297
|
+
if self._exit_thread is None:
|
298
|
+
return
|
299
|
+
self._exit_thread.join()
|
259
300
|
|
260
|
-
def
|
301
|
+
def _start_background_app(self) -> None:
|
261
302
|
"""Start server on specified port."""
|
262
|
-
|
263
|
-
f"Starting mechanical application in server.\n"
|
264
|
-
f"Listening on port {self._port}\n{self._background_app.app}"
|
265
|
-
)
|
303
|
+
self._exit_thread: threading.Thread = None
|
266
304
|
self._server.start()
|
267
|
-
"""try:
|
268
|
-
try:
|
269
|
-
conn.serve_all()
|
270
|
-
except KeyboardInterrupt:
|
271
|
-
print("User interrupt!")
|
272
|
-
finally:
|
273
|
-
conn.close()"""
|
274
305
|
print("Server exited!")
|
275
306
|
self._wait_exit()
|
276
307
|
self._exited = True
|
277
308
|
|
278
|
-
def
|
279
|
-
|
280
|
-
return
|
281
|
-
self._exit_thread.join()
|
309
|
+
def _stop_background_app(self):
|
310
|
+
"""Return immediately but will stop the server.
|
282
311
|
|
283
|
-
|
284
|
-
|
312
|
+
Mechanical is running on the background but
|
313
|
+
the rpyc server is running on the main thread
|
314
|
+
this signals for the server to stop, and the main
|
315
|
+
thread will wait until the server has stopped.
|
316
|
+
"""
|
285
317
|
|
286
318
|
def stop_f(): # wait for all connections to close
|
287
319
|
while len(self._server.clients) > 0:
|
288
320
|
time.sleep(0.005)
|
289
|
-
self.
|
321
|
+
self._app_instance.stop()
|
322
|
+
self._app_instance = None
|
323
|
+
self._backend = None
|
290
324
|
self._server.close()
|
291
325
|
self._exited = True
|
292
326
|
|
293
327
|
self._exit_thread = threading.Thread(target=stop_f)
|
294
328
|
self._exit_thread.start()
|
295
329
|
|
296
|
-
def
|
297
|
-
|
298
|
-
print("Stopping the server...")
|
299
|
-
self._background_app.stop()
|
300
|
-
self._server.close()
|
301
|
-
self._exited = True
|
302
|
-
print("Server stopped.")
|
330
|
+
def _start_foreground_app(self):
|
331
|
+
self._server_stopped = False
|
303
332
|
|
333
|
+
def start_f():
|
334
|
+
print("Server started!")
|
335
|
+
self._server.start()
|
336
|
+
print("Server exited!")
|
304
337
|
|
305
|
-
|
306
|
-
|
338
|
+
self._server_thread = threading.Thread(target=start_f)
|
339
|
+
self._server_thread.start()
|
340
|
+
while True:
|
341
|
+
if self._server_stopped:
|
342
|
+
break
|
343
|
+
try:
|
344
|
+
ansys.mechanical.core.embedding.utils.sleep(40)
|
345
|
+
except Exception as e:
|
346
|
+
print(f"An error occurred: {e}")
|
347
|
+
self._server_thread.join()
|
307
348
|
|
308
|
-
def
|
309
|
-
|
310
|
-
self.
|
349
|
+
def _stop_foreground_app(self):
|
350
|
+
self._server_stopped = True
|
351
|
+
self._server.close()
|
352
|
+
# self._server_thread.join()
|
311
353
|
|
312
|
-
def
|
313
|
-
|
314
|
-
|
354
|
+
def _get_app_repr(self) -> str:
|
355
|
+
def f():
|
356
|
+
return repr(self._backend.get_app())
|
315
357
|
|
316
|
-
|
317
|
-
def run_python_script(
|
318
|
-
self, script: str, enable_logging=False, log_level="WARNING", progress_interval=2000
|
319
|
-
):
|
320
|
-
"""Run scripts using Internal python engine."""
|
321
|
-
result = self._app.execute_script(script)
|
322
|
-
return result
|
358
|
+
return self._backend.try_post(f)
|
323
359
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
"""Run scripts using Internal python engine."""
|
333
|
-
return self._app.execute_script_from_file(file_path)
|
334
|
-
|
335
|
-
@remote_method
|
336
|
-
def clear(self):
|
337
|
-
"""Clear the current project."""
|
338
|
-
self._app.new()
|
339
|
-
|
340
|
-
@property
|
341
|
-
@remote_method
|
342
|
-
def project_directory(self):
|
343
|
-
"""Get the project directory."""
|
344
|
-
return self._app.execute_script("""ExtAPI.DataModel.Project.ProjectDirectory""")
|
345
|
-
|
346
|
-
@remote_method
|
347
|
-
def list_files(self):
|
348
|
-
"""List all files in the project directory."""
|
349
|
-
list = []
|
350
|
-
mechdbPath = self._app.execute_script("""ExtAPI.DataModel.Project.FilePath""")
|
351
|
-
if mechdbPath != "":
|
352
|
-
list.append(mechdbPath)
|
353
|
-
rootDir = self._app.execute_script("""ExtAPI.DataModel.Project.ProjectDirectory""")
|
354
|
-
|
355
|
-
for dirPath, dirNames, fileNames in os.walk(rootDir):
|
356
|
-
for fileName in fileNames:
|
357
|
-
list.append(os.path.join(dirPath, fileName))
|
358
|
-
files_out = "\n".join(list).splitlines()
|
359
|
-
if not files_out: # pragma: no cover
|
360
|
-
print("No files listed")
|
361
|
-
return files_out
|
362
|
-
|
363
|
-
@remote_method
|
364
|
-
def _get_files(self, files, recursive=False):
|
365
|
-
self_files = self.list_files() # to avoid calling it too much
|
366
|
-
|
367
|
-
if isinstance(files, str):
|
368
|
-
if files in self_files:
|
369
|
-
list_files = [files]
|
370
|
-
elif "*" in files:
|
371
|
-
list_files = fnmatch.filter(self_files, files)
|
372
|
-
if not list_files:
|
373
|
-
raise ValueError(
|
374
|
-
f"The `'files'` parameter ({files}) didn't match any file using "
|
375
|
-
f"glob expressions in the remote server."
|
376
|
-
)
|
377
|
-
else:
|
378
|
-
raise ValueError(
|
379
|
-
f"The `'files'` parameter ('{files}') does not match any file or pattern."
|
380
|
-
)
|
381
|
-
|
382
|
-
elif isinstance(files, (list, tuple)):
|
383
|
-
if not all([isinstance(each, str) for each in files]):
|
384
|
-
raise ValueError(
|
385
|
-
"The parameter `'files'` can be a list or tuple, but it "
|
386
|
-
"should only contain strings."
|
387
|
-
)
|
388
|
-
list_files = files
|
360
|
+
def start(self) -> None:
|
361
|
+
"""Start server on specified port."""
|
362
|
+
print(
|
363
|
+
f"Starting mechanical application in server.\n"
|
364
|
+
f"Listening on port {self._port}\n{self._get_app_repr()}"
|
365
|
+
)
|
366
|
+
if isinstance(self._app_instance, BackgroundApp):
|
367
|
+
self._start_background_app()
|
389
368
|
else:
|
390
|
-
|
391
|
-
f"The `file` parameter type ({type(files)}) is not supported."
|
392
|
-
"Only strings, tuple of strings, or list of strings are allowed."
|
393
|
-
)
|
394
|
-
|
395
|
-
return list_files
|
396
|
-
|
397
|
-
|
398
|
-
class MechanicalDefaultServer(MechanicalEmbeddedServer):
|
399
|
-
"""Default server with default service methods."""
|
369
|
+
self._start_foreground_app()
|
400
370
|
|
401
|
-
def
|
402
|
-
"""
|
403
|
-
|
371
|
+
def stop(self) -> None:
|
372
|
+
"""Stop the server."""
|
373
|
+
if self._is_stopped():
|
374
|
+
raise Exception("already stopped!")
|
375
|
+
if isinstance(self._app_instance, BackgroundApp):
|
376
|
+
self._stop_background_app()
|
377
|
+
else:
|
378
|
+
self._stop_foreground_app()
|
379
|
+
|
380
|
+
def _install_classes(self, impl: typing.Union[typing.Any, typing.List]) -> None:
|
381
|
+
app = self._backend.get_app()
|
382
|
+
if impl and not isinstance(impl, list):
|
383
|
+
impl = [impl]
|
384
|
+
self._impl = [i(app) for i in impl] if impl else []
|
385
|
+
|
386
|
+
def _install_methods(
|
387
|
+
self, methods: typing.Union[typing.Callable, typing.List[typing.Callable]]
|
388
|
+
) -> None:
|
389
|
+
if methods and not isinstance(methods, list):
|
390
|
+
methods = [methods]
|
391
|
+
self._methods = methods if methods is not None else []
|
@@ -22,6 +22,10 @@
|
|
22
22
|
"""Utilities necessary for remote calls."""
|
23
23
|
import typing
|
24
24
|
|
25
|
+
from ansys.mechanical.core.mechanical import port_in_use
|
26
|
+
|
27
|
+
PYMECHANICAL_DEFAULT_RPC_PORT = 20000
|
28
|
+
|
25
29
|
|
26
30
|
class remote_method:
|
27
31
|
"""Decorator for passing remote methods."""
|
@@ -116,3 +120,17 @@ def get_remote_methods(
|
|
116
120
|
if result != None:
|
117
121
|
attrname, method = result
|
118
122
|
yield attrname, method, MethodType.METHOD
|
123
|
+
|
124
|
+
|
125
|
+
def get_free_port(port: int = None):
|
126
|
+
"""Get free port.
|
127
|
+
|
128
|
+
If port is not given, it will find a free port starting from PYMECHANICAL_DEFAULT_RPC_PORT.
|
129
|
+
"""
|
130
|
+
if port is None:
|
131
|
+
port = PYMECHANICAL_DEFAULT_RPC_PORT
|
132
|
+
|
133
|
+
while port_in_use(port):
|
134
|
+
port += 1
|
135
|
+
|
136
|
+
return port
|
@@ -50,13 +50,17 @@ def _bind_assembly_for_explicit_interface(assembly_name: str):
|
|
50
50
|
# if pythonnet is not installed, we can't bind the assembly
|
51
51
|
try:
|
52
52
|
distribution("pythonnet")
|
53
|
+
Logger.warning("Cannot bind for explicit interface because pythonnet is installed")
|
53
54
|
return
|
54
55
|
except ModuleNotFoundError:
|
55
56
|
pass
|
56
57
|
|
58
|
+
Logger.debug(f"Binding assembly for explicit interface {assembly_name}")
|
57
59
|
import clr
|
58
60
|
|
61
|
+
Logger.debug(f"Binding assembly for explicit interface, Loading {assembly_name}")
|
59
62
|
assembly = clr.AddReference(assembly_name)
|
63
|
+
Logger.debug(f"Binding assembly for explicit interface, Loaded {assembly_name}")
|
60
64
|
from Python.Runtime import BindingManager, BindingOptions
|
61
65
|
|
62
66
|
binding_options = BindingOptions()
|
@@ -78,6 +82,8 @@ def initialize(version: int) -> None:
|
|
78
82
|
if version >= 242 or os.name == "nt":
|
79
83
|
# function codec is distributed with pymechanical on linux only
|
80
84
|
# at version 242 or later
|
85
|
+
Logger.debug("Registering function codec")
|
81
86
|
__register_function_codec()
|
87
|
+
Logger.debug("Registered function codec")
|
82
88
|
|
83
89
|
_bind_assembly_for_explicit_interface("Ansys.ACT.WB1")
|
@@ -93,6 +93,7 @@ def _vscode_impl(
|
|
93
93
|
If unspecified, it finds the default Mechanical version from ansys-tools-path.
|
94
94
|
"""
|
95
95
|
# Update the user or workspace settings
|
96
|
+
settings_json = "the settings.json file"
|
96
97
|
if target == "user":
|
97
98
|
# Get the path to the user's settings.json file depending on the platform
|
98
99
|
if "win" in sys.platform:
|
@@ -34,6 +34,7 @@ import subprocess # nosec: B404
|
|
34
34
|
import sys
|
35
35
|
import threading
|
36
36
|
import time
|
37
|
+
import typing
|
37
38
|
from typing import Optional
|
38
39
|
import warnings
|
39
40
|
import weakref
|
@@ -460,10 +461,11 @@ class Mechanical(object):
|
|
460
461
|
else:
|
461
462
|
self.log_info("Mechanical connection is treated as remote.")
|
462
463
|
|
464
|
+
self._error_type = grpc.RpcError
|
465
|
+
|
463
466
|
# connect and validate to the channel
|
464
467
|
self._multi_connect(timeout=timeout)
|
465
468
|
self.log_info("Mechanical is ready to accept grpc calls.")
|
466
|
-
self._rpc_type = "grpc"
|
467
469
|
|
468
470
|
def __del__(self): # pragma: no cover
|
469
471
|
"""Clean up on exit."""
|
@@ -482,6 +484,11 @@ class Mechanical(object):
|
|
482
484
|
"""Log associated with the current Mechanical instance."""
|
483
485
|
return self._log
|
484
486
|
|
487
|
+
@property
|
488
|
+
def backend(self) -> str:
|
489
|
+
"""Return the backend type."""
|
490
|
+
return "mechanical"
|
491
|
+
|
485
492
|
@property
|
486
493
|
def version(self) -> str:
|
487
494
|
"""Get the Mechanical version based on the instance.
|
@@ -1204,9 +1211,9 @@ class Mechanical(object):
|
|
1204
1211
|
if progress_bar:
|
1205
1212
|
if not _HAS_TQDM: # pragma: no cover
|
1206
1213
|
raise ModuleNotFoundError(
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1214
|
+
"To use the keyword argument 'progress_bar', you must have "
|
1215
|
+
"installed the 'tqdm' package. To avoid this message, you can "
|
1216
|
+
"set 'progress_bar=False'."
|
1210
1217
|
)
|
1211
1218
|
|
1212
1219
|
n_bytes = os.path.getsize(file_name)
|
@@ -1951,11 +1958,12 @@ def launch_rpyc(
|
|
1951
1958
|
additional_switches=None,
|
1952
1959
|
additional_envs=None,
|
1953
1960
|
verbose=False,
|
1954
|
-
) -> int:
|
1961
|
+
) -> typing.Tuple[int, subprocess.Popen]:
|
1955
1962
|
"""Start Mechanical locally in RPyC mode."""
|
1956
1963
|
_version = atp.version_from_path("mechanical", exec_file)
|
1957
|
-
|
1958
|
-
|
1964
|
+
|
1965
|
+
if not batch:
|
1966
|
+
raise Exception("The rpyc backend does not support graphical mode!")
|
1959
1967
|
|
1960
1968
|
# get the next available port
|
1961
1969
|
local_ports = pymechanical.LOCAL_PORTS
|
@@ -1969,21 +1977,21 @@ def launch_rpyc(
|
|
1969
1977
|
port += 1
|
1970
1978
|
local_ports.append(port)
|
1971
1979
|
|
1980
|
+
# TODO - use multiprocessing
|
1972
1981
|
server_script = """
|
1973
1982
|
import sys
|
1974
1983
|
from ansys.mechanical.core.embedding.rpc import MechanicalDefaultServer
|
1975
1984
|
server = MechanicalDefaultServer(port=int(sys.argv[1]), version=int(sys.argv[2]))
|
1976
1985
|
server.start()
|
1977
1986
|
"""
|
1978
|
-
env_copy = os.environ.copy()
|
1979
1987
|
try:
|
1980
1988
|
embedded_server = subprocess.Popen(
|
1981
|
-
[sys.executable, "-c", server_script, str(port), str(_version)]
|
1989
|
+
[sys.executable, "-c", server_script, str(port), str(_version)]
|
1982
1990
|
) # nosec: B603
|
1983
1991
|
except:
|
1984
1992
|
raise RuntimeError("Unable to start the embedded server.")
|
1985
1993
|
|
1986
|
-
return port
|
1994
|
+
return port, embedded_server
|
1987
1995
|
|
1988
1996
|
|
1989
1997
|
def launch_remote_mechanical(
|
@@ -2306,11 +2314,15 @@ def launch_mechanical(
|
|
2306
2314
|
# pass
|
2307
2315
|
raise exception
|
2308
2316
|
elif backend == "python":
|
2309
|
-
port = launch_rpyc(port=port, **start_parm)
|
2317
|
+
port, process = launch_rpyc(port=port, **start_parm)
|
2310
2318
|
from ansys.mechanical.core.embedding.rpc.client import Client
|
2311
2319
|
|
2312
2320
|
mechanical = Client(
|
2313
|
-
"localhost",
|
2321
|
+
"localhost",
|
2322
|
+
port,
|
2323
|
+
timeout=start_timeout,
|
2324
|
+
cleanup_on_exit=cleanup_on_exit,
|
2325
|
+
process=process,
|
2314
2326
|
)
|
2315
2327
|
|
2316
2328
|
return mechanical
|
{ansys_mechanical_core-0.11.14.dist-info → ansys_mechanical_core-0.11.16.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ansys-mechanical-core
|
3
|
-
Version: 0.11.
|
3
|
+
Version: 0.11.16
|
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>
|
@@ -18,7 +18,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
18
18
|
Classifier: Operating System :: OS Independent
|
19
19
|
License-File: LICENSE
|
20
20
|
Requires-Dist: ansys-api-mechanical==0.1.2
|
21
|
-
Requires-Dist: ansys-mechanical-env==0.1.
|
21
|
+
Requires-Dist: ansys-mechanical-env==0.1.12
|
22
22
|
Requires-Dist: ansys-mechanical-stubs==0.1.6
|
23
23
|
Requires-Dist: ansys-pythonnet>=3.1.0rc6
|
24
24
|
Requires-Dist: ansys-tools-path>=0.3.1
|
@@ -30,19 +30,19 @@ Requires-Dist: protobuf>=3.12.2,<6
|
|
30
30
|
Requires-Dist: psutil>=6
|
31
31
|
Requires-Dist: tqdm>=4.45.0
|
32
32
|
Requires-Dist: requests>=2,<3
|
33
|
-
Requires-Dist: sphinx==8.2.
|
34
|
-
Requires-Dist: ansys-sphinx-theme[autoapi, changelog]==1.
|
33
|
+
Requires-Dist: sphinx==8.2.3 ; extra == "doc"
|
34
|
+
Requires-Dist: ansys-sphinx-theme[autoapi, changelog]==1.4.2 ; extra == "doc"
|
35
35
|
Requires-Dist: grpcio==1.70.0 ; extra == "doc"
|
36
36
|
Requires-Dist: imageio-ffmpeg==0.6.0 ; extra == "doc"
|
37
37
|
Requires-Dist: imageio==2.37.0 ; extra == "doc"
|
38
38
|
Requires-Dist: jupyter_sphinx==0.5.3 ; extra == "doc"
|
39
39
|
Requires-Dist: jupyterlab>=3.2.8 ; extra == "doc"
|
40
|
-
Requires-Dist: matplotlib==3.10.
|
41
|
-
Requires-Dist: numpy==2.2.
|
40
|
+
Requires-Dist: matplotlib==3.10.1 ; extra == "doc"
|
41
|
+
Requires-Dist: numpy==2.2.5 ; extra == "doc"
|
42
42
|
Requires-Dist: numpydoc==1.8.0 ; extra == "doc"
|
43
43
|
Requires-Dist: pandas==2.2.3 ; extra == "doc"
|
44
44
|
Requires-Dist: panel==1.6.1 ; extra == "doc"
|
45
|
-
Requires-Dist: plotly==6.0.
|
45
|
+
Requires-Dist: plotly==6.0.1 ; extra == "doc"
|
46
46
|
Requires-Dist: pypandoc==1.15 ; extra == "doc"
|
47
47
|
Requires-Dist: pytest-sphinx==0.6.3 ; extra == "doc"
|
48
48
|
Requires-Dist: pythreejs==2.4.2 ; extra == "doc"
|
@@ -55,21 +55,24 @@ Requires-Dist: sphinx-gallery==0.19.0 ; extra == "doc"
|
|
55
55
|
Requires-Dist: sphinx-notfound-page==1.1.0 ; extra == "doc"
|
56
56
|
Requires-Dist: sphinxcontrib-websupport==2.0.0 ; extra == "doc"
|
57
57
|
Requires-Dist: sphinxemoji==0.3.1 ; extra == "doc"
|
58
|
+
Requires-Dist: ansys-tools-visualization-interface>=0.2.6 ; extra == "graphics"
|
59
|
+
Requires-Dist: usd-core==25.5 ; extra == "graphics"
|
58
60
|
Requires-Dist: ansys-platform-instancemanagement>=1.0.1 ; extra == "pim"
|
59
|
-
Requires-Dist: rpyc==6.0.
|
61
|
+
Requires-Dist: rpyc==6.0.2 ; extra == "rpc"
|
60
62
|
Requires-Dist: toolz==1.0.0 ; extra == "rpc"
|
61
|
-
Requires-Dist: pytest==8.3.
|
62
|
-
Requires-Dist: pytest-cov==6.
|
63
|
-
Requires-Dist: pytest-print==1.0
|
63
|
+
Requires-Dist: pytest==8.3.5 ; extra == "tests"
|
64
|
+
Requires-Dist: pytest-cov==6.1.1 ; extra == "tests"
|
65
|
+
Requires-Dist: pytest-print==1.1.0 ; extra == "tests"
|
64
66
|
Requires-Dist: psutil==7.0.0 ; extra == "tests"
|
65
67
|
Requires-Dist: ansys-tools-visualization-interface>=0.2.6 ; extra == "viz"
|
66
|
-
Requires-Dist: usd-core==
|
68
|
+
Requires-Dist: usd-core==25.5 ; extra == "viz"
|
67
69
|
Project-URL: Changelog, https://mechanical.docs.pyansys.com/version/stable/changelog.html
|
68
70
|
Project-URL: Documentation, https://mechanical.docs.pyansys.com
|
69
71
|
Project-URL: Homepage, https://github.com/ansys/pymechanical
|
70
72
|
Project-URL: Issues, https://github.com/ansys/pymechanical/issues
|
71
73
|
Project-URL: Repository, https://github.com/ansys/pymechanical
|
72
74
|
Provides-Extra: doc
|
75
|
+
Provides-Extra: graphics
|
73
76
|
Provides-Extra: pim
|
74
77
|
Provides-Extra: rpc
|
75
78
|
Provides-Extra: tests
|