ansys-pyensight-core 0.11.0__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/pyensight/core/__init__.py +41 -0
- ansys/pyensight/core/common.py +341 -0
- ansys/pyensight/core/deep_pixel_view.html +98 -0
- ansys/pyensight/core/dockerlauncher.py +1124 -0
- ansys/pyensight/core/dvs.py +872 -0
- ansys/pyensight/core/enscontext.py +345 -0
- ansys/pyensight/core/enshell_grpc.py +641 -0
- ansys/pyensight/core/ensight_grpc.py +874 -0
- ansys/pyensight/core/ensobj.py +515 -0
- ansys/pyensight/core/launch_ensight.py +296 -0
- ansys/pyensight/core/launcher.py +388 -0
- ansys/pyensight/core/libuserd.py +2110 -0
- ansys/pyensight/core/listobj.py +280 -0
- ansys/pyensight/core/locallauncher.py +579 -0
- ansys/pyensight/core/py.typed +0 -0
- ansys/pyensight/core/renderable.py +880 -0
- ansys/pyensight/core/session.py +1923 -0
- ansys/pyensight/core/sgeo_poll.html +24 -0
- ansys/pyensight/core/utils/__init__.py +21 -0
- ansys/pyensight/core/utils/adr.py +111 -0
- ansys/pyensight/core/utils/dsg_server.py +1220 -0
- ansys/pyensight/core/utils/export.py +606 -0
- ansys/pyensight/core/utils/omniverse.py +769 -0
- ansys/pyensight/core/utils/omniverse_cli.py +614 -0
- ansys/pyensight/core/utils/omniverse_dsg_server.py +1196 -0
- ansys/pyensight/core/utils/omniverse_glb_server.py +848 -0
- ansys/pyensight/core/utils/parts.py +1221 -0
- ansys/pyensight/core/utils/query.py +487 -0
- ansys/pyensight/core/utils/readers.py +300 -0
- ansys/pyensight/core/utils/resources/Materials/000_sky.exr +0 -0
- ansys/pyensight/core/utils/support.py +128 -0
- ansys/pyensight/core/utils/variables.py +2019 -0
- ansys/pyensight/core/utils/views.py +674 -0
- ansys_pyensight_core-0.11.0.dist-info/METADATA +309 -0
- ansys_pyensight_core-0.11.0.dist-info/RECORD +37 -0
- ansys_pyensight_core-0.11.0.dist-info/WHEEL +4 -0
- ansys_pyensight_core-0.11.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
# Copyright (C) 2022 - 2026 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
|
+
"""
|
|
24
|
+
Python wrapper for the core enshellservice
|
|
25
|
+
|
|
26
|
+
This package defines the EnShellGRPC class which provides a simpler
|
|
27
|
+
interface to the EnShell gRPC interface.
|
|
28
|
+
|
|
29
|
+
Python binding for the EnShell gRPC API
|
|
30
|
+
|
|
31
|
+
This class provides an asynchronous interface to the EnShell
|
|
32
|
+
core gRPC interface.
|
|
33
|
+
"""
|
|
34
|
+
import logging
|
|
35
|
+
import os
|
|
36
|
+
import random
|
|
37
|
+
import re
|
|
38
|
+
import subprocess
|
|
39
|
+
import sys
|
|
40
|
+
from typing import TYPE_CHECKING, Optional
|
|
41
|
+
|
|
42
|
+
from ansys.api.pyensight.v0 import enshell_pb2, enshell_pb2_grpc
|
|
43
|
+
from ansys.pyensight.core import DEFAULT_ANSYS_VERSION # pylint: disable=import-outside-toplevel
|
|
44
|
+
from ansys.tools.common.cyberchannel import create_channel
|
|
45
|
+
import grpc
|
|
46
|
+
|
|
47
|
+
if TYPE_CHECKING:
|
|
48
|
+
from ansys.pyensight.core import Session
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class EnShellGRPC(object):
|
|
52
|
+
"""Create an instance of the EnShell gRPC interface wrapper.
|
|
53
|
+
|
|
54
|
+
The default is to make a connection to an EnShell gRPC server
|
|
55
|
+
on port 12345 on the loopback host. If requested to launch
|
|
56
|
+
the server, it will be the current version.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
port: int, optional
|
|
61
|
+
The port number of the EnShell gRPC server
|
|
62
|
+
host:
|
|
63
|
+
The hostname of the EnShell gRPC server
|
|
64
|
+
version:
|
|
65
|
+
A specific EnShell version number to run (e.g. '232' for 2023R2)
|
|
66
|
+
secret_key: str, optional
|
|
67
|
+
Connection secret key
|
|
68
|
+
grpc_use_tcp_sockets :
|
|
69
|
+
If using gRPC, and if True, then allow TCP Socket based connections
|
|
70
|
+
instead of only local connections.
|
|
71
|
+
grpc_allow_network_connections :
|
|
72
|
+
If using gRPC and using TCP Socket based connections, listen on all networks.
|
|
73
|
+
grpc_disable_tls :
|
|
74
|
+
If using gRPC and using TCP Socket based connections, disable TLS.
|
|
75
|
+
grpc_uds_pathname :
|
|
76
|
+
If using gRPC and using Unix Domain Socket based connections, explicitly
|
|
77
|
+
set the pathname to the shared UDS file instead of using the default.
|
|
78
|
+
disable_grpc_options: bool, optional
|
|
79
|
+
Whether to disable the gRPC options check, and allow to run older
|
|
80
|
+
versions of EnSight
|
|
81
|
+
|
|
82
|
+
WARNING:
|
|
83
|
+
Overriding the default values for these options: grpc_use_tcp_sockets, grpc_allow_network_connections,
|
|
84
|
+
and grpc_disable_tls
|
|
85
|
+
can possibly permit control of this computer and any data which resides on it.
|
|
86
|
+
Modification of this configuration is not recommended. Please see the
|
|
87
|
+
documentation for your installed product for additional information.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(
|
|
91
|
+
self,
|
|
92
|
+
port: int = 12345,
|
|
93
|
+
host: str = "127.0.0.1",
|
|
94
|
+
version: str = DEFAULT_ANSYS_VERSION,
|
|
95
|
+
secret_key: str = "",
|
|
96
|
+
grpc_use_tcp_sockets: bool = False,
|
|
97
|
+
grpc_allow_network_connections: bool = False,
|
|
98
|
+
grpc_disable_tls: bool = False,
|
|
99
|
+
grpc_uds_pathname: Optional[str] = None,
|
|
100
|
+
session: Optional["Session"] = None,
|
|
101
|
+
disable_grpc_options: bool = False,
|
|
102
|
+
):
|
|
103
|
+
self._port = port
|
|
104
|
+
self._host = host
|
|
105
|
+
self._desired_version = version
|
|
106
|
+
#
|
|
107
|
+
self._pid = None
|
|
108
|
+
self._channel = None
|
|
109
|
+
self._stub = None
|
|
110
|
+
self._grpc_use_tcp_sockets = grpc_use_tcp_sockets
|
|
111
|
+
self._grpc_allow_network_connections = grpc_allow_network_connections
|
|
112
|
+
self._grpc_disable_tls = grpc_disable_tls
|
|
113
|
+
self._grpc_uds_pathname = grpc_uds_pathname
|
|
114
|
+
#
|
|
115
|
+
# self._security_token = str(random.randint(0, 1000000))
|
|
116
|
+
self._security_token: Optional[str] = None
|
|
117
|
+
if not secret_key and not disable_grpc_options:
|
|
118
|
+
self._security_token = str(random.randint(0, 1000000))
|
|
119
|
+
else:
|
|
120
|
+
self._security_token = secret_key
|
|
121
|
+
# self._security_token: Optional[int] = None
|
|
122
|
+
#
|
|
123
|
+
# values found from EnShell in the Container
|
|
124
|
+
self._cei_home = None
|
|
125
|
+
self._ansys_version = None
|
|
126
|
+
self._pyensight_session = session
|
|
127
|
+
self._disable_grpc_options = disable_grpc_options
|
|
128
|
+
|
|
129
|
+
def __del__(self):
|
|
130
|
+
self.shutdown()
|
|
131
|
+
|
|
132
|
+
def host(self):
|
|
133
|
+
"""Get the hostname for this connection.
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
str
|
|
138
|
+
the current connection hostname.
|
|
139
|
+
"""
|
|
140
|
+
return self._host
|
|
141
|
+
|
|
142
|
+
def port(self):
|
|
143
|
+
"""Get the port number for this connection.
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
int
|
|
148
|
+
The current connection port number.
|
|
149
|
+
"""
|
|
150
|
+
return self._port
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def security_token(self):
|
|
154
|
+
"""Return the security token for the gRPC connection.
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
str
|
|
159
|
+
Returns the current connection security token
|
|
160
|
+
"""
|
|
161
|
+
return self._security_token
|
|
162
|
+
|
|
163
|
+
@security_token.setter
|
|
164
|
+
def security_token(self, n: str):
|
|
165
|
+
"""set the security token for the gRPC connection.
|
|
166
|
+
|
|
167
|
+
EnShell supports a security token in either numeric (-security {int}) or
|
|
168
|
+
string (ENSIGHT_SECURITY_TOKEN environmental variable) form. If EnShell
|
|
169
|
+
is using a security token, all gRPC calls must include this token. This
|
|
170
|
+
call sets the token for all rGPC calls made by this class.
|
|
171
|
+
Note: for this module, the security token must be a in bytes() format.
|
|
172
|
+
For example: str(1000).encode("utf-8")
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
n : Optional[int], optional
|
|
177
|
+
An string to be used as the security token, by default None
|
|
178
|
+
"""
|
|
179
|
+
self._security_token = n # pragma: no cover
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def grpc_use_tcp_sockets(self):
|
|
183
|
+
"""Get whether to use Unix Domain Sockets or TCP Sockets for gRPC"""
|
|
184
|
+
return self._grpc_use_tcp_sockets
|
|
185
|
+
|
|
186
|
+
@grpc_use_tcp_sockets.setter
|
|
187
|
+
def grpc_use_tcp_sockets(self, use_sockets: bool):
|
|
188
|
+
"""Set whether to use Unix Domain Sockets or TCP Sockets for gRPC"""
|
|
189
|
+
self._grpc_use_tcp_sockets = use_sockets
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def grpc_allow_network_connections(self):
|
|
193
|
+
"""Get whether to allow listening on all networks if using TCP Sockets for gRPC"""
|
|
194
|
+
return self._grpc_allow_network_connections
|
|
195
|
+
|
|
196
|
+
@grpc_allow_network_connections.setter
|
|
197
|
+
def grpc_allow_network_connections(self, allow: bool):
|
|
198
|
+
"""Set whether to allow listening on all networks if using TCP Sockets for gRPC"""
|
|
199
|
+
self._grpc_allow_network_connections = allow
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def grpc_disable_tls(self):
|
|
203
|
+
"""Get whether to use TLS for TCP Sockets for gRPC"""
|
|
204
|
+
return self._grpc_disable_tls
|
|
205
|
+
|
|
206
|
+
@grpc_disable_tls.setter
|
|
207
|
+
def grpc_disable_tls(self, disable_tls: bool):
|
|
208
|
+
"""Set whether to use TLS for TCP Sockets for gRPC"""
|
|
209
|
+
self._grpc_disable_tls = disable_tls
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def grpc_uds_pathname(self):
|
|
213
|
+
"""Get the pathname for the UDS file if not using the default for gRPC"""
|
|
214
|
+
return self._grpc_uds_pathname
|
|
215
|
+
|
|
216
|
+
@grpc_uds_pathname.setter
|
|
217
|
+
def grpc_uds_pathname(self, uds_pathname: str):
|
|
218
|
+
"""Set the pathname for the UDS file if not using the default for gRPC"""
|
|
219
|
+
self._grpc_uds_pathname = uds_pathname
|
|
220
|
+
|
|
221
|
+
def set_random_security_token(self):
|
|
222
|
+
"""Set a random security token for the gRPC connection."""
|
|
223
|
+
self._security_token = str(random.randint(0, 1000000)) # pragma: no cover
|
|
224
|
+
|
|
225
|
+
def shutdown(self):
|
|
226
|
+
"""shut down all gRPC connections.
|
|
227
|
+
|
|
228
|
+
If this class launched the EnShell client instance, it will
|
|
229
|
+
send the gRPC exit() call and then shut down all connections.
|
|
230
|
+
"""
|
|
231
|
+
# if we launched EnShell, shut it down.
|
|
232
|
+
if self._pid is not None: # pragma: no cover
|
|
233
|
+
_ = self.stop_server() # pragma: no cover
|
|
234
|
+
|
|
235
|
+
def start_server(self): # pragma: no cover
|
|
236
|
+
"""Start an EnShell gRPC server instance.
|
|
237
|
+
|
|
238
|
+
If the host application wishes to launch an EnShell instance, start_server()
|
|
239
|
+
will launch a batch mode EnShell application with the security token and
|
|
240
|
+
a gRPC server started on the port passed in the constructor.
|
|
241
|
+
"""
|
|
242
|
+
if self._pid is not None:
|
|
243
|
+
return self._pid
|
|
244
|
+
|
|
245
|
+
my_env = os.environ.copy()
|
|
246
|
+
if self._desired_version != "":
|
|
247
|
+
exe = f"enshell{self._desired_version}"
|
|
248
|
+
else:
|
|
249
|
+
exe = "enshell"
|
|
250
|
+
cmd = [exe, "-app", "-grpc_server", str(self._port)]
|
|
251
|
+
if self._security_token:
|
|
252
|
+
cmd.append("-security")
|
|
253
|
+
cmd.append(self._security_token)
|
|
254
|
+
if self._grpc_use_tcp_sockets:
|
|
255
|
+
cmd.append("-grpc_use_tcp_sockets")
|
|
256
|
+
if self._grpc_allow_network_connections:
|
|
257
|
+
cmd.append("-grpc_allow_network_connections")
|
|
258
|
+
if self._grpc_disable_tls:
|
|
259
|
+
cmd.append("-grpc_disable_tls")
|
|
260
|
+
if self._grpc_uds_pathname:
|
|
261
|
+
cmd.append("-grpc_uds_pathname")
|
|
262
|
+
cmd.append(self._grpc_uds_pathname)
|
|
263
|
+
if sys.platform in ("win32", "cygwin"):
|
|
264
|
+
cmd[0] += ".bat"
|
|
265
|
+
# cmd.append("-minimize_console")
|
|
266
|
+
# si = subprocess.STARTUPINFO()
|
|
267
|
+
# si.dwFlags = subprocess.STARTF_USESHOWWINDOW | subprocess.CREATE_NEW_CONSOLE
|
|
268
|
+
# si.wShowWindow = subprocess.SW_HIDE
|
|
269
|
+
# f = subprocess.DETACHED_PROCESS
|
|
270
|
+
# DETACHED_PROCESS = 0x00000008
|
|
271
|
+
# self._pid = subprocess.Popen(cmd, creationflags=f, close_fds=True, env=my_env).pid
|
|
272
|
+
# self._pid = subprocess.Popen(cmd, startupinfo=si, close_fds=True, env=my_env).pid
|
|
273
|
+
logging.debug(f"command: {cmd}\n\n")
|
|
274
|
+
self._pid = subprocess.Popen(cmd, close_fds=True, env=my_env).pid
|
|
275
|
+
else:
|
|
276
|
+
self._pid = subprocess.Popen(cmd, close_fds=True, env=my_env).pid
|
|
277
|
+
return self._pid
|
|
278
|
+
|
|
279
|
+
def stop_server(self):
|
|
280
|
+
"""Shut down any gPRC connection made by this class.
|
|
281
|
+
|
|
282
|
+
First, if this class launched the EnShell instance, via start_server(), the
|
|
283
|
+
exit_cleanly() gRPC command will be sent. Second, the local gRPC connection is
|
|
284
|
+
dropped
|
|
285
|
+
"""
|
|
286
|
+
response = None
|
|
287
|
+
# if we are connected and we started the server, we will emit the 'exit' message
|
|
288
|
+
if self.is_connected(): # pragma: no cover
|
|
289
|
+
response = self._stub.exit_cleanly(
|
|
290
|
+
enshell_pb2.google_dot_protobuf_dot_empty__pb2.Empty(), metadata=self.metadata()
|
|
291
|
+
)
|
|
292
|
+
self._stub = None
|
|
293
|
+
self._dsg_stub = None
|
|
294
|
+
if self._channel: # pragma: no cover
|
|
295
|
+
self._channel.close()
|
|
296
|
+
self._channel = None
|
|
297
|
+
self._pid = None
|
|
298
|
+
return response
|
|
299
|
+
|
|
300
|
+
def is_connected(self):
|
|
301
|
+
"""Check if a gRPC connection has been established.
|
|
302
|
+
|
|
303
|
+
Returns
|
|
304
|
+
-------
|
|
305
|
+
bool
|
|
306
|
+
True if a previous connect() call made a valid gRPC connection.
|
|
307
|
+
"""
|
|
308
|
+
if not self._channel:
|
|
309
|
+
return False
|
|
310
|
+
return self._channel is not None
|
|
311
|
+
|
|
312
|
+
def connect(self, timeout: Optional[float] = 15.0):
|
|
313
|
+
"""Establish a connection to an EnShell gRPC server.
|
|
314
|
+
|
|
315
|
+
Attempt to connect to an EnShell gRPC server using the host and port
|
|
316
|
+
established by the constructor. Note on failure, this function just
|
|
317
|
+
returns, but is_connected() will return False.
|
|
318
|
+
|
|
319
|
+
Parameters
|
|
320
|
+
----------
|
|
321
|
+
timeout : Optional[float], optional
|
|
322
|
+
timeout how long to wait for the connection to timeout., by default 15.0
|
|
323
|
+
"""
|
|
324
|
+
if self._channel is not None:
|
|
325
|
+
return
|
|
326
|
+
transport_mode = None
|
|
327
|
+
host = None
|
|
328
|
+
port = None
|
|
329
|
+
uds_service = None
|
|
330
|
+
uds_dir = None
|
|
331
|
+
options = [
|
|
332
|
+
("grpc.max_receive_message_length", -1),
|
|
333
|
+
("grpc.max_send_message_length", -1),
|
|
334
|
+
("grpc.testing.fixed_reconnect_backoff_ms", 1100),
|
|
335
|
+
]
|
|
336
|
+
if self._grpc_use_tcp_sockets:
|
|
337
|
+
host = self._host
|
|
338
|
+
transport_mode = "mtls"
|
|
339
|
+
if self._grpc_disable_tls:
|
|
340
|
+
transport_mode = "insecure"
|
|
341
|
+
port = self._port
|
|
342
|
+
else:
|
|
343
|
+
host = "127.0.0.1"
|
|
344
|
+
if sys.platform == "win32":
|
|
345
|
+
transport_mode = "wnua"
|
|
346
|
+
port = self._port
|
|
347
|
+
else:
|
|
348
|
+
transport_mode = "uds"
|
|
349
|
+
uds_service = "pyensight" if self._grpc_uds_pathname else "greeter"
|
|
350
|
+
if not self._grpc_uds_pathname:
|
|
351
|
+
uds_dir = "/tmp"
|
|
352
|
+
else:
|
|
353
|
+
uds_dir = os.path.dirname(self._grpc_uds_pathname)
|
|
354
|
+
# Ignore the security options if the version of EnSight cannot handle them
|
|
355
|
+
if self._disable_grpc_options:
|
|
356
|
+
transport_mode = "insecure"
|
|
357
|
+
host = self._host
|
|
358
|
+
port = self._port
|
|
359
|
+
self._channel = create_channel(
|
|
360
|
+
host=host,
|
|
361
|
+
port=port,
|
|
362
|
+
transport_mode=transport_mode,
|
|
363
|
+
uds_dir=uds_dir,
|
|
364
|
+
uds_service=uds_service,
|
|
365
|
+
grpc_options=options,
|
|
366
|
+
)
|
|
367
|
+
try:
|
|
368
|
+
grpc.channel_ready_future(self._channel).result(timeout=timeout)
|
|
369
|
+
except grpc.FutureTimeoutError: # pragma: no cover
|
|
370
|
+
self._channel = None # pragma: no cover
|
|
371
|
+
return # pragma: no cover
|
|
372
|
+
self._stub = enshell_pb2_grpc.EnShellServiceStub(self._channel)
|
|
373
|
+
|
|
374
|
+
def connect_existing_channel(self, channel: grpc.Channel): # pragma: no cover
|
|
375
|
+
"""Establish a connection to an EnShell gRPC server.
|
|
376
|
+
|
|
377
|
+
Attempt to connect to an EnShell gRPC server using the host and port
|
|
378
|
+
established by the constructor. Note on failure, this function just
|
|
379
|
+
returns, but is_connected() will return False.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
channel : grpc.Channel
|
|
384
|
+
Timeout how long to wait for the connection to timeout.
|
|
385
|
+
"""
|
|
386
|
+
if self._channel is not None:
|
|
387
|
+
raise RuntimeError("connect_existing_channel: channel already connected.")
|
|
388
|
+
|
|
389
|
+
if channel is None:
|
|
390
|
+
raise RuntimeError("connect_existing_channel: bad channel passed in.")
|
|
391
|
+
|
|
392
|
+
self._channel = channel
|
|
393
|
+
self._stub = enshell_pb2_grpc.EnShellServiceStub(self._channel)
|
|
394
|
+
|
|
395
|
+
def metadata(self): # pragma: no cover
|
|
396
|
+
"""Compute internal gRPC stream metadata."""
|
|
397
|
+
ret = list()
|
|
398
|
+
if self._security_token is not None:
|
|
399
|
+
s = self._security_token
|
|
400
|
+
if type(s) == str:
|
|
401
|
+
s = s.encode("utf-8")
|
|
402
|
+
ret.append((b"shared_secret", s))
|
|
403
|
+
return ret
|
|
404
|
+
|
|
405
|
+
def run_command(self, command_string: str):
|
|
406
|
+
"""send an EnShell command string to be executed in EnShell.
|
|
407
|
+
|
|
408
|
+
The string will be sent to EnShell via the EnShellService::run_command()
|
|
409
|
+
gRPC call. An IOError exception may be thrown
|
|
410
|
+
if there's a gRPC communication problem. The response
|
|
411
|
+
is the tuple of the EnShell return code and return string.
|
|
412
|
+
|
|
413
|
+
Parameters
|
|
414
|
+
----------
|
|
415
|
+
command_string : str
|
|
416
|
+
Command_string the EnShell string to be executed.
|
|
417
|
+
|
|
418
|
+
Returns
|
|
419
|
+
-------
|
|
420
|
+
tuple
|
|
421
|
+
A tuple of (int, string) for (returnCode, returnString)
|
|
422
|
+
"""
|
|
423
|
+
self.connect()
|
|
424
|
+
if not self._stub: # pragma: no cover
|
|
425
|
+
return (0, "") # pragma: no cover
|
|
426
|
+
try:
|
|
427
|
+
response = self._stub.run_command(
|
|
428
|
+
enshell_pb2.EnShellCommandLine(command_line=command_string),
|
|
429
|
+
metadata=self.metadata(),
|
|
430
|
+
)
|
|
431
|
+
except Exception: # pragma: no cover
|
|
432
|
+
raise IOError("gRPC connection dropped") # pragma: no cover
|
|
433
|
+
|
|
434
|
+
return (response.ret, response.response)
|
|
435
|
+
|
|
436
|
+
def run_command_with_env(self, command_string: str, env_string: str):
|
|
437
|
+
"""send an EnShell command string and env var string to be executed in EnShell
|
|
438
|
+
|
|
439
|
+
The string will be sent to EnShell via the EnShellService::run_command()
|
|
440
|
+
gRPC call. An IOError exception may be thrown
|
|
441
|
+
if there's a gRPC communication problem. The response
|
|
442
|
+
is the tuple of the EnShell return code and return string.
|
|
443
|
+
Parameters
|
|
444
|
+
----------
|
|
445
|
+
command_string : str
|
|
446
|
+
the EnShell string to be executed.
|
|
447
|
+
env_string : str
|
|
448
|
+
String of the environment.
|
|
449
|
+
|
|
450
|
+
Returns
|
|
451
|
+
-------
|
|
452
|
+
Tuple
|
|
453
|
+
A tuple of (int, string) for (returnCode, returnString)
|
|
454
|
+
"""
|
|
455
|
+
self.connect()
|
|
456
|
+
if not self._stub: # pragma: no cover
|
|
457
|
+
return (0, "") # pragma: no cover
|
|
458
|
+
try:
|
|
459
|
+
response = self._stub.run_command_with_env(
|
|
460
|
+
enshell_pb2.EnShellCommandWithEnvLine(
|
|
461
|
+
command_line=command_string, env_line=env_string
|
|
462
|
+
),
|
|
463
|
+
metadata=self.metadata(),
|
|
464
|
+
)
|
|
465
|
+
except Exception: # pragma: no cover
|
|
466
|
+
raise IOError("gRPC connection dropped") # pragma: no cover
|
|
467
|
+
|
|
468
|
+
return (response.ret, response.response)
|
|
469
|
+
|
|
470
|
+
# @brief Tell EnShell to start EnSight
|
|
471
|
+
#
|
|
472
|
+
# The string will be sent to EnShell via the EnShellService::run_command()
|
|
473
|
+
# gRPC call. An IOError exception may be thrown
|
|
474
|
+
# if there's a gRPC communication problem. The response
|
|
475
|
+
# is the tuple of the EnShell return code and return string.
|
|
476
|
+
# If ensight_env is used, the format is a single string of
|
|
477
|
+
# environment variable name=value pairs with multiple pairs
|
|
478
|
+
# separated by '\n' characters.
|
|
479
|
+
# @param ensight_args arguments for the ensight command line
|
|
480
|
+
# @param ensight_env optional environment variables to set before running EnSight
|
|
481
|
+
# @return A tuple of (int, string) for (returnCode, returnString)
|
|
482
|
+
def start_ensight(self, ensight_args: Optional[str] = None, ensight_env: Optional[str] = None):
|
|
483
|
+
"""Tell EnShell to start EnSight.
|
|
484
|
+
|
|
485
|
+
The string will be sent to EnShell via the EnShellService::run_command()
|
|
486
|
+
gRPC call. An IOError exception may be thrown
|
|
487
|
+
if there's a gRPC communication problem. The response
|
|
488
|
+
is the tuple of the EnShell return code and return string.
|
|
489
|
+
|
|
490
|
+
Parameters
|
|
491
|
+
----------
|
|
492
|
+
ensight_args : Optional[str], optional
|
|
493
|
+
ensight_args arguments for the ensight command line, by default None
|
|
494
|
+
|
|
495
|
+
Returns
|
|
496
|
+
-------
|
|
497
|
+
Tuple
|
|
498
|
+
A tuple of (int, string) for (returnCode, returnString)
|
|
499
|
+
"""
|
|
500
|
+
self.connect()
|
|
501
|
+
|
|
502
|
+
command_string = "start_app CLIENT -c 127.0.0.1 -enshell"
|
|
503
|
+
if self._security_token:
|
|
504
|
+
command_string += " -security "
|
|
505
|
+
command_string += str(self._security_token)
|
|
506
|
+
if self._grpc_use_tcp_sockets:
|
|
507
|
+
command_string += " -grpc_use_tcp_sockets"
|
|
508
|
+
if self._grpc_allow_network_connections:
|
|
509
|
+
command_string += " -grpc_allow_network_connections"
|
|
510
|
+
if self._grpc_disable_tls:
|
|
511
|
+
command_string += " -grpc_disable_tls"
|
|
512
|
+
# does not make sense to forward this option along
|
|
513
|
+
# if self._grpc_uds_pathname:
|
|
514
|
+
# command_string += " -grpc_uds_pathname "+self._grpc_uds_pathname
|
|
515
|
+
if ensight_args and (ensight_args != ""):
|
|
516
|
+
command_string += " " + ensight_args
|
|
517
|
+
|
|
518
|
+
if ensight_env is None or ensight_env == "": # pragma: no cover
|
|
519
|
+
return self.run_command(command_string)
|
|
520
|
+
else:
|
|
521
|
+
return self.run_command_with_env(command_string, ensight_env) # pragma: no cover
|
|
522
|
+
|
|
523
|
+
def start_ensight_server(
|
|
524
|
+
self, ensight_args: Optional[str] = None, ensight_env: Optional[str] = None
|
|
525
|
+
):
|
|
526
|
+
"""Tell EnShell to start the EnSight server.
|
|
527
|
+
|
|
528
|
+
The string will be sent to EnShell via the EnShellService::run_command()
|
|
529
|
+
gRPC call. An IOError exception may be thrown
|
|
530
|
+
if there's a gRPC communication problem. The response
|
|
531
|
+
is the tuple of the EnShell return code and return string.
|
|
532
|
+
|
|
533
|
+
Parameters
|
|
534
|
+
----------
|
|
535
|
+
ensight_args : Optional[str], optional
|
|
536
|
+
ensight_args arguments for the ensight command line, by default None
|
|
537
|
+
|
|
538
|
+
Returns
|
|
539
|
+
-------
|
|
540
|
+
Tuple
|
|
541
|
+
A tuple of (int, string) for (returnCode, returnString)
|
|
542
|
+
"""
|
|
543
|
+
self.connect()
|
|
544
|
+
command_string = (
|
|
545
|
+
f"start_app OTHER /ansys_inc/v{self.ansys_version()}/CEI/bin/ensight_server"
|
|
546
|
+
)
|
|
547
|
+
if self._security_token:
|
|
548
|
+
command_string += " -security "
|
|
549
|
+
command_string += str(self._security_token)
|
|
550
|
+
if self._grpc_use_tcp_sockets:
|
|
551
|
+
command_string += " -grpc_use_tcp_sockets"
|
|
552
|
+
if self._grpc_allow_network_connections:
|
|
553
|
+
command_string += " -grpc_allow_network_connections"
|
|
554
|
+
if self._grpc_disable_tls:
|
|
555
|
+
command_string += " -grpc_disable_tls"
|
|
556
|
+
# does not make sense to forward this option along
|
|
557
|
+
# if self._grpc_uds_pathname:
|
|
558
|
+
# command_string += " -grpc_uds_pathname "+self._grpc_uds_pathname
|
|
559
|
+
if ensight_args and (ensight_args != ""):
|
|
560
|
+
command_string += " " + ensight_args
|
|
561
|
+
|
|
562
|
+
if ensight_env is None or ensight_env == "": # pragma: no cover
|
|
563
|
+
return self.run_command(command_string)
|
|
564
|
+
else:
|
|
565
|
+
return self.run_command_with_env(command_string, ensight_env) # pragma: no cover
|
|
566
|
+
|
|
567
|
+
# @brief
|
|
568
|
+
#
|
|
569
|
+
# @param cmd The command line
|
|
570
|
+
# @return A tuple of (int, string) for (returnCode, returnString)
|
|
571
|
+
def start_other(self, cmd: str, extra_env: Optional[str] = None):
|
|
572
|
+
"""Tell EnShell to start a non-EnShell aware command.
|
|
573
|
+
|
|
574
|
+
The string will be sent to EnShell via the EnShellService::run_command()
|
|
575
|
+
gRPC call. An IOError exception may be thrown
|
|
576
|
+
if there's a gRPC communication problem. The response
|
|
577
|
+
is the tuple of the EnShell return code and return string.
|
|
578
|
+
|
|
579
|
+
Parameters
|
|
580
|
+
----------
|
|
581
|
+
cmd : str
|
|
582
|
+
_description_
|
|
583
|
+
|
|
584
|
+
Returns
|
|
585
|
+
-------
|
|
586
|
+
_type_
|
|
587
|
+
_description_
|
|
588
|
+
"""
|
|
589
|
+
self.connect()
|
|
590
|
+
command_string = "start_app OTHER " + cmd
|
|
591
|
+
|
|
592
|
+
if extra_env is None or extra_env == "": # pragma: no cover
|
|
593
|
+
return self.run_command(command_string)
|
|
594
|
+
else:
|
|
595
|
+
return self.run_command_with_env(command_string, extra_env) # pragma: no cover
|
|
596
|
+
|
|
597
|
+
def cei_home(self):
|
|
598
|
+
"""Get the value of CEI_HOME from EnShell."""
|
|
599
|
+
self._get_cei_home()
|
|
600
|
+
return self._cei_home
|
|
601
|
+
|
|
602
|
+
def ansys_version(self):
|
|
603
|
+
"""Get the Ansys version from EnShell (e.g. 232)"""
|
|
604
|
+
self._get_cei_home()
|
|
605
|
+
return self._ansys_version
|
|
606
|
+
|
|
607
|
+
def _get_cei_home(self):
|
|
608
|
+
if self._cei_home is not None:
|
|
609
|
+
return
|
|
610
|
+
|
|
611
|
+
self.connect()
|
|
612
|
+
command_string = "show_ceihome"
|
|
613
|
+
ret = self.run_command(command_string)
|
|
614
|
+
# logging.debug(f"{command_string} :: ret = {ret}\n")
|
|
615
|
+
if ret[0] != 0: # pragma: no cover
|
|
616
|
+
self._cei_home = None # pragma: no cover
|
|
617
|
+
raise RuntimeError("Error getting printenv from EnShell") # pragma: no cover
|
|
618
|
+
|
|
619
|
+
# split the newline delimited string into a list of strings
|
|
620
|
+
env_vars = ret[1].strip().split("\n")
|
|
621
|
+
# find the string containing CEI_HOME
|
|
622
|
+
cei_home_line = [x for x in env_vars if "CEI_HOME" in x][0]
|
|
623
|
+
if cei_home_line is None: # pragma: no cover
|
|
624
|
+
raise RuntimeError(
|
|
625
|
+
"Error getting CEI_HOME env var from the Docker container.\n{ret}\n"
|
|
626
|
+
) # pragma: no cover
|
|
627
|
+
|
|
628
|
+
# CEI_HOME is everything after the equal sign
|
|
629
|
+
equal_sign_loc = cei_home_line.find("=")
|
|
630
|
+
if equal_sign_loc < 0: # pragma: no cover
|
|
631
|
+
raise RuntimeError(
|
|
632
|
+
"Error getting CEI_HOME env var from the Docker container.\n{ret}\n"
|
|
633
|
+
) # pragma: no cover
|
|
634
|
+
self._cei_home = cei_home_line[equal_sign_loc + 1 :]
|
|
635
|
+
m = re.search(r"/v(\d\d\d)/", self._cei_home)
|
|
636
|
+
if not m: # pragma: no cover
|
|
637
|
+
self.stop_server() # pragma: no cover
|
|
638
|
+
raise RuntimeError(
|
|
639
|
+
"Can't find version from cei_home in the Docker container.\n{ret}\n"
|
|
640
|
+
) # pragma: no cover
|
|
641
|
+
self._ansys_version = m.group(1)
|