ansys-pyensight-core 0.7.6__py3-none-any.whl → 0.7.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansys-pyensight-core might be problematic. Click here for more details.
- ansys/pyensight/core/ensight_grpc.py +430 -411
- ansys/pyensight/core/renderable.py +42 -21
- ansys/pyensight/core/session.py +5 -2
- ansys/pyensight/core/utils/omniverse.py +239 -0
- ansys/pyensight/core/utils/omniverse_dsg_server.py +1354 -0
- ansys/pyensight/core/utils/resources/Materials/000_sky.exr +0 -0
- ansys/pyensight/core/utils/resources/Materials/Fieldstone/Fieldstone_BaseColor.png +0 -0
- ansys/pyensight/core/utils/resources/Materials/Fieldstone/Fieldstone_N.png +0 -0
- ansys/pyensight/core/utils/resources/Materials/Fieldstone/Fieldstone_ORM.png +0 -0
- ansys/pyensight/core/utils/resources/Materials/Fieldstone.mdl +54 -0
- ansys/pyensight/core/utils/variables.py +119 -107
- {ansys_pyensight_core-0.7.6.dist-info → ansys_pyensight_core-0.7.8.dist-info}/METADATA +4 -2
- {ansys_pyensight_core-0.7.6.dist-info → ansys_pyensight_core-0.7.8.dist-info}/RECORD +15 -8
- {ansys_pyensight_core-0.7.6.dist-info → ansys_pyensight_core-0.7.8.dist-info}/LICENSE +0 -0
- {ansys_pyensight_core-0.7.6.dist-info → ansys_pyensight_core-0.7.8.dist-info}/WHEEL +0 -0
|
@@ -1,411 +1,430 @@
|
|
|
1
|
-
"""ensight_grpc module
|
|
2
|
-
|
|
3
|
-
This package defines the EnSightGRPC class which provides a simpler
|
|
4
|
-
interface to the EnSight gRPC interface, including event streams.
|
|
5
|
-
|
|
6
|
-
"""
|
|
7
|
-
import threading
|
|
8
|
-
from typing import Any, Callable, List, Optional, Tuple, Union
|
|
9
|
-
import uuid
|
|
10
|
-
|
|
11
|
-
from ansys.api.pyensight.v0 import ensight_pb2, ensight_pb2_grpc
|
|
12
|
-
import grpc
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class EnSightGRPC(object):
|
|
16
|
-
"""Wrapper around a gRPC connection to an EnSight instance
|
|
17
|
-
|
|
18
|
-
This class provides an asynchronous interface to the EnSight
|
|
19
|
-
core gRPC interface. It can handle remote event
|
|
20
|
-
streams, providing a much simpler interface to the EnSight
|
|
21
|
-
application. The default is to make a connection to an EnSight
|
|
22
|
-
gRPC server on port 12345 on the loopback host.
|
|
23
|
-
|
|
24
|
-
Parameters
|
|
25
|
-
----------
|
|
26
|
-
host: str, optional
|
|
27
|
-
Hostname where there EnSight gRPC server is running.
|
|
28
|
-
port: int, optional
|
|
29
|
-
Port to make the gRPC connection to
|
|
30
|
-
secret_key: str, optional
|
|
31
|
-
Connection secret key
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def __init__(self, host: str = "127.0.0.1", port: int = 12345, secret_key: str = ""):
|
|
35
|
-
self._host = host
|
|
36
|
-
self._port = port
|
|
37
|
-
self._channel = None
|
|
38
|
-
self._stub = None
|
|
39
|
-
self._dsg_stub = None
|
|
40
|
-
self._security_token = secret_key
|
|
41
|
-
self._session_name: str = ""
|
|
42
|
-
# Streaming APIs
|
|
43
|
-
# Event (strings)
|
|
44
|
-
self._event_stream = None
|
|
45
|
-
self._event_thread: Optional[threading.Thread] = None
|
|
46
|
-
self._events: List[Any] = list()
|
|
47
|
-
# Callback for events (self._events not used)
|
|
48
|
-
self._event_callback: Optional[Callable] = None
|
|
49
|
-
self._prefix: Optional[str] = None
|
|
50
|
-
|
|
51
|
-
@property
|
|
52
|
-
def host(self) -> str:
|
|
53
|
-
"""The gRPC server (EnSight) hostname"""
|
|
54
|
-
return self._host
|
|
55
|
-
|
|
56
|
-
def port(self) -> int:
|
|
57
|
-
"""The gRPC server (EnSight) port number"""
|
|
58
|
-
return self._port
|
|
59
|
-
|
|
60
|
-
@property
|
|
61
|
-
def security_token(self) -> str:
|
|
62
|
-
"""The gRPC server (EnSight) secret key
|
|
63
|
-
|
|
64
|
-
EnSight supports a security token in either numeric (-security {int}) or
|
|
65
|
-
string (ENSIGHT_SECURITY_TOKEN environmental variable) form. If EnSight
|
|
66
|
-
is using a security token, all gRPC calls must include this token. This
|
|
67
|
-
call sets the token for all grPC calls made by this class.
|
|
68
|
-
"""
|
|
69
|
-
return self._security_token
|
|
70
|
-
|
|
71
|
-
@security_token.setter
|
|
72
|
-
def security_token(self, name: str) -> None:
|
|
73
|
-
self._security_token = name
|
|
74
|
-
|
|
75
|
-
@property
|
|
76
|
-
def session_name(self) -> str:
|
|
77
|
-
"""The gRPC server session name
|
|
78
|
-
|
|
79
|
-
EnSight gRPC calls can include the session name via 'session_name' metadata.
|
|
80
|
-
A client session may provide a session name via this property.
|
|
81
|
-
"""
|
|
82
|
-
return self._session_name
|
|
83
|
-
|
|
84
|
-
@session_name.setter
|
|
85
|
-
def session_name(self, name: str) -> None:
|
|
86
|
-
self._session_name = name
|
|
87
|
-
|
|
88
|
-
def shutdown(self, stop_ensight: bool = False, force: bool = False) -> None:
|
|
89
|
-
"""Close down the gRPC connection
|
|
90
|
-
|
|
91
|
-
Disconnect all connections to the gRPC server. If stop_ensight is True, send the
|
|
92
|
-
'Exit' command to the EnSight gRPC server.
|
|
93
|
-
|
|
94
|
-
Parameters
|
|
95
|
-
----------
|
|
96
|
-
stop_ensight: bool, optional
|
|
97
|
-
if True, send an 'Exit' command to the gRPC server.
|
|
98
|
-
force: bool, optional
|
|
99
|
-
if stop_ensight and force are true, stop EnSight aggressively
|
|
100
|
-
"""
|
|
101
|
-
if self.is_connected():
|
|
102
|
-
# if requested, send 'Exit'
|
|
103
|
-
if stop_ensight:
|
|
104
|
-
# the gRPC ExitRequest is exactly that, a request in some
|
|
105
|
-
# cases the operation needs to be forced
|
|
106
|
-
if force:
|
|
107
|
-
try:
|
|
108
|
-
self.command("ensight.exit(0)", do_eval=False)
|
|
109
|
-
except IOError:
|
|
110
|
-
# we expect this as the exit can result in the gRPC call failing
|
|
111
|
-
pass
|
|
112
|
-
else:
|
|
113
|
-
if self._stub:
|
|
114
|
-
_ = self._stub.Exit(ensight_pb2.ExitRequest(), metadata=self._metadata())
|
|
115
|
-
# clean up control objects
|
|
116
|
-
self._stub = None
|
|
117
|
-
self._dsg_stub = None
|
|
118
|
-
if self._channel:
|
|
119
|
-
self._channel.close()
|
|
120
|
-
self._channel = None
|
|
121
|
-
|
|
122
|
-
def is_connected(self) -> bool:
|
|
123
|
-
"""Check to see if the gRPC connection is live
|
|
124
|
-
|
|
125
|
-
Returns
|
|
126
|
-
-------
|
|
127
|
-
True if the connection is active.
|
|
128
|
-
"""
|
|
129
|
-
return self._channel is not None
|
|
130
|
-
|
|
131
|
-
def connect(self, timeout: float = 15.0) -> None:
|
|
132
|
-
"""Establish the gRPC connection to EnSight
|
|
133
|
-
|
|
134
|
-
Attempt to connect to an EnSight gRPC server using the host and port
|
|
135
|
-
established by the constructor. Note on failure, this function just
|
|
136
|
-
returns, but is_connected() will return False.
|
|
137
|
-
|
|
138
|
-
Parameters
|
|
139
|
-
----------
|
|
140
|
-
timeout: float
|
|
141
|
-
how long to wait for the connection to timeout
|
|
142
|
-
"""
|
|
143
|
-
if self.is_connected():
|
|
144
|
-
return
|
|
145
|
-
# set up the channel
|
|
146
|
-
self._channel = grpc.insecure_channel(
|
|
147
|
-
"{}:{}".format(self._host, self._port),
|
|
148
|
-
options=[
|
|
149
|
-
("grpc.max_receive_message_length", -1),
|
|
150
|
-
("grpc.max_send_message_length", -1),
|
|
151
|
-
("grpc.testing.fixed_reconnect_backoff_ms", 1100),
|
|
152
|
-
],
|
|
153
|
-
)
|
|
154
|
-
try:
|
|
155
|
-
grpc.channel_ready_future(self._channel).result(timeout=timeout)
|
|
156
|
-
except grpc.FutureTimeoutError:
|
|
157
|
-
self._channel = None
|
|
158
|
-
return
|
|
159
|
-
# hook up the stub interface
|
|
160
|
-
self._stub = ensight_pb2_grpc.EnSightServiceStub(self._channel)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
the
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
#
|
|
317
|
-
#
|
|
318
|
-
return response.value
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
self.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
self._event_thread
|
|
357
|
-
self._event_thread.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
1
|
+
"""ensight_grpc module
|
|
2
|
+
|
|
3
|
+
This package defines the EnSightGRPC class which provides a simpler
|
|
4
|
+
interface to the EnSight gRPC interface, including event streams.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
import threading
|
|
8
|
+
from typing import Any, Callable, List, Optional, Tuple, Union
|
|
9
|
+
import uuid
|
|
10
|
+
|
|
11
|
+
from ansys.api.pyensight.v0 import dynamic_scene_graph_pb2_grpc, ensight_pb2, ensight_pb2_grpc
|
|
12
|
+
import grpc
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EnSightGRPC(object):
|
|
16
|
+
"""Wrapper around a gRPC connection to an EnSight instance
|
|
17
|
+
|
|
18
|
+
This class provides an asynchronous interface to the EnSight
|
|
19
|
+
core gRPC interface. It can handle remote event
|
|
20
|
+
streams, providing a much simpler interface to the EnSight
|
|
21
|
+
application. The default is to make a connection to an EnSight
|
|
22
|
+
gRPC server on port 12345 on the loopback host.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
host: str, optional
|
|
27
|
+
Hostname where there EnSight gRPC server is running.
|
|
28
|
+
port: int, optional
|
|
29
|
+
Port to make the gRPC connection to
|
|
30
|
+
secret_key: str, optional
|
|
31
|
+
Connection secret key
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, host: str = "127.0.0.1", port: int = 12345, secret_key: str = ""):
|
|
35
|
+
self._host = host
|
|
36
|
+
self._port = port
|
|
37
|
+
self._channel = None
|
|
38
|
+
self._stub = None
|
|
39
|
+
self._dsg_stub = None
|
|
40
|
+
self._security_token = secret_key
|
|
41
|
+
self._session_name: str = ""
|
|
42
|
+
# Streaming APIs
|
|
43
|
+
# Event (strings)
|
|
44
|
+
self._event_stream = None
|
|
45
|
+
self._event_thread: Optional[threading.Thread] = None
|
|
46
|
+
self._events: List[Any] = list()
|
|
47
|
+
# Callback for events (self._events not used)
|
|
48
|
+
self._event_callback: Optional[Callable] = None
|
|
49
|
+
self._prefix: Optional[str] = None
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def host(self) -> str:
|
|
53
|
+
"""The gRPC server (EnSight) hostname"""
|
|
54
|
+
return self._host
|
|
55
|
+
|
|
56
|
+
def port(self) -> int:
|
|
57
|
+
"""The gRPC server (EnSight) port number"""
|
|
58
|
+
return self._port
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def security_token(self) -> str:
|
|
62
|
+
"""The gRPC server (EnSight) secret key
|
|
63
|
+
|
|
64
|
+
EnSight supports a security token in either numeric (-security {int}) or
|
|
65
|
+
string (ENSIGHT_SECURITY_TOKEN environmental variable) form. If EnSight
|
|
66
|
+
is using a security token, all gRPC calls must include this token. This
|
|
67
|
+
call sets the token for all grPC calls made by this class.
|
|
68
|
+
"""
|
|
69
|
+
return self._security_token
|
|
70
|
+
|
|
71
|
+
@security_token.setter
|
|
72
|
+
def security_token(self, name: str) -> None:
|
|
73
|
+
self._security_token = name
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def session_name(self) -> str:
|
|
77
|
+
"""The gRPC server session name
|
|
78
|
+
|
|
79
|
+
EnSight gRPC calls can include the session name via 'session_name' metadata.
|
|
80
|
+
A client session may provide a session name via this property.
|
|
81
|
+
"""
|
|
82
|
+
return self._session_name
|
|
83
|
+
|
|
84
|
+
@session_name.setter
|
|
85
|
+
def session_name(self, name: str) -> None:
|
|
86
|
+
self._session_name = name
|
|
87
|
+
|
|
88
|
+
def shutdown(self, stop_ensight: bool = False, force: bool = False) -> None:
|
|
89
|
+
"""Close down the gRPC connection
|
|
90
|
+
|
|
91
|
+
Disconnect all connections to the gRPC server. If stop_ensight is True, send the
|
|
92
|
+
'Exit' command to the EnSight gRPC server.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
stop_ensight: bool, optional
|
|
97
|
+
if True, send an 'Exit' command to the gRPC server.
|
|
98
|
+
force: bool, optional
|
|
99
|
+
if stop_ensight and force are true, stop EnSight aggressively
|
|
100
|
+
"""
|
|
101
|
+
if self.is_connected():
|
|
102
|
+
# if requested, send 'Exit'
|
|
103
|
+
if stop_ensight:
|
|
104
|
+
# the gRPC ExitRequest is exactly that, a request in some
|
|
105
|
+
# cases the operation needs to be forced
|
|
106
|
+
if force:
|
|
107
|
+
try:
|
|
108
|
+
self.command("ensight.exit(0)", do_eval=False)
|
|
109
|
+
except IOError:
|
|
110
|
+
# we expect this as the exit can result in the gRPC call failing
|
|
111
|
+
pass
|
|
112
|
+
else:
|
|
113
|
+
if self._stub:
|
|
114
|
+
_ = self._stub.Exit(ensight_pb2.ExitRequest(), metadata=self._metadata())
|
|
115
|
+
# clean up control objects
|
|
116
|
+
self._stub = None
|
|
117
|
+
self._dsg_stub = None
|
|
118
|
+
if self._channel:
|
|
119
|
+
self._channel.close()
|
|
120
|
+
self._channel = None
|
|
121
|
+
|
|
122
|
+
def is_connected(self) -> bool:
|
|
123
|
+
"""Check to see if the gRPC connection is live
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
True if the connection is active.
|
|
128
|
+
"""
|
|
129
|
+
return self._channel is not None
|
|
130
|
+
|
|
131
|
+
def connect(self, timeout: float = 15.0) -> None:
|
|
132
|
+
"""Establish the gRPC connection to EnSight
|
|
133
|
+
|
|
134
|
+
Attempt to connect to an EnSight gRPC server using the host and port
|
|
135
|
+
established by the constructor. Note on failure, this function just
|
|
136
|
+
returns, but is_connected() will return False.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
timeout: float
|
|
141
|
+
how long to wait for the connection to timeout
|
|
142
|
+
"""
|
|
143
|
+
if self.is_connected():
|
|
144
|
+
return
|
|
145
|
+
# set up the channel
|
|
146
|
+
self._channel = grpc.insecure_channel(
|
|
147
|
+
"{}:{}".format(self._host, self._port),
|
|
148
|
+
options=[
|
|
149
|
+
("grpc.max_receive_message_length", -1),
|
|
150
|
+
("grpc.max_send_message_length", -1),
|
|
151
|
+
("grpc.testing.fixed_reconnect_backoff_ms", 1100),
|
|
152
|
+
],
|
|
153
|
+
)
|
|
154
|
+
try:
|
|
155
|
+
grpc.channel_ready_future(self._channel).result(timeout=timeout)
|
|
156
|
+
except grpc.FutureTimeoutError:
|
|
157
|
+
self._channel = None
|
|
158
|
+
return
|
|
159
|
+
# hook up the stub interface
|
|
160
|
+
self._stub = ensight_pb2_grpc.EnSightServiceStub(self._channel)
|
|
161
|
+
self._dsg_stub = dynamic_scene_graph_pb2_grpc.DynamicSceneGraphServiceStub(self._channel)
|
|
162
|
+
|
|
163
|
+
def _metadata(self) -> List[Tuple[bytes, Union[str, bytes]]]:
|
|
164
|
+
"""Compute the gRPC stream metadata
|
|
165
|
+
|
|
166
|
+
Compute the list to be passed to the gRPC calls for things like security
|
|
167
|
+
and the session name.
|
|
168
|
+
|
|
169
|
+
"""
|
|
170
|
+
ret: List[Tuple[bytes, Union[str, bytes]]] = list()
|
|
171
|
+
s: Union[str, bytes]
|
|
172
|
+
if self._security_token:
|
|
173
|
+
s = self._security_token
|
|
174
|
+
if type(s) == str:
|
|
175
|
+
s = s.encode("utf-8")
|
|
176
|
+
ret.append((b"shared_secret", s))
|
|
177
|
+
if self.session_name:
|
|
178
|
+
s = self.session_name.encode("utf-8")
|
|
179
|
+
ret.append((b"session_name", s))
|
|
180
|
+
return ret
|
|
181
|
+
|
|
182
|
+
def render(
|
|
183
|
+
self,
|
|
184
|
+
width: int = 640,
|
|
185
|
+
height: int = 480,
|
|
186
|
+
aa: int = 1,
|
|
187
|
+
png: bool = True,
|
|
188
|
+
highlighting: bool = False,
|
|
189
|
+
) -> bytes:
|
|
190
|
+
"""Generate a rendering of the current EnSight scene
|
|
191
|
+
|
|
192
|
+
Render the current scene at a specific size and using a specific number of anti-aliasing
|
|
193
|
+
passes. The return value can be a byte array (width*height*3) bytes or a PNG image.
|
|
194
|
+
|
|
195
|
+
Parameters
|
|
196
|
+
----------
|
|
197
|
+
width: int, optional
|
|
198
|
+
width of the image to render
|
|
199
|
+
height: int, optional
|
|
200
|
+
height of the image to render
|
|
201
|
+
aa: int, optional
|
|
202
|
+
number of antialiasing passes to use in generating the image
|
|
203
|
+
png: bool, optional
|
|
204
|
+
if True, the return value is a PNG image bytestream. Otherwise, it is a simple
|
|
205
|
+
bytes object with width*height*3 values.
|
|
206
|
+
highlighting: bool, optional
|
|
207
|
+
if True, selection highlighting will be included in the image.
|
|
208
|
+
|
|
209
|
+
Returns
|
|
210
|
+
-------
|
|
211
|
+
bytes
|
|
212
|
+
bytes object representation of the rendered image
|
|
213
|
+
|
|
214
|
+
Raises
|
|
215
|
+
------
|
|
216
|
+
IOError if the operation fails
|
|
217
|
+
"""
|
|
218
|
+
self.connect()
|
|
219
|
+
ret_type = ensight_pb2.RenderRequest.IMAGE_RAW
|
|
220
|
+
if png:
|
|
221
|
+
ret_type = ensight_pb2.RenderRequest.IMAGE_PNG
|
|
222
|
+
response: Any
|
|
223
|
+
try:
|
|
224
|
+
if self._stub:
|
|
225
|
+
response = self._stub.RenderImage(
|
|
226
|
+
ensight_pb2.RenderRequest(
|
|
227
|
+
type=ret_type,
|
|
228
|
+
image_width=width,
|
|
229
|
+
image_height=height,
|
|
230
|
+
image_aa_passes=aa,
|
|
231
|
+
include_highlighting=highlighting,
|
|
232
|
+
),
|
|
233
|
+
metadata=self._metadata(),
|
|
234
|
+
)
|
|
235
|
+
except Exception:
|
|
236
|
+
raise IOError("gRPC connection dropped")
|
|
237
|
+
return response.value
|
|
238
|
+
|
|
239
|
+
def geometry(self) -> bytes:
|
|
240
|
+
"""Return the current scene geometry in glTF format
|
|
241
|
+
|
|
242
|
+
Package up the geometry currently being viewed in the EnSight session as
|
|
243
|
+
a glTF stream. Return this stream as an array of byte. Note: no
|
|
244
|
+
intermediate files are utilized.
|
|
245
|
+
|
|
246
|
+
Note: currently there is a limitation of glTF files to 2GB
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
bytes object representation of the glTF file
|
|
251
|
+
|
|
252
|
+
Raises
|
|
253
|
+
------
|
|
254
|
+
IOError if the operation fails
|
|
255
|
+
"""
|
|
256
|
+
self.connect()
|
|
257
|
+
response: Any
|
|
258
|
+
try:
|
|
259
|
+
if self._stub:
|
|
260
|
+
response = self._stub.GetGeometry(
|
|
261
|
+
ensight_pb2.GeometryRequest(type=ensight_pb2.GeometryRequest.GEOMETRY_GLB),
|
|
262
|
+
metadata=self._metadata(),
|
|
263
|
+
)
|
|
264
|
+
except Exception:
|
|
265
|
+
raise IOError("gRPC connection dropped")
|
|
266
|
+
return response.value
|
|
267
|
+
|
|
268
|
+
def command(self, command_string: str, do_eval: bool = True, json: bool = False) -> Any:
|
|
269
|
+
"""Send a Python command string to be executed in EnSight
|
|
270
|
+
|
|
271
|
+
The string will be run or evaluated in the EnSight Python interpreter via the
|
|
272
|
+
EnSightService::RunPython() gRPC all. If an exception or other error occurs, this
|
|
273
|
+
function will throw a RuntimeError. If do_eval is False, the return value will be None,
|
|
274
|
+
otherwise it will be the returned string (eval() will not be performed). If json is True,
|
|
275
|
+
the return value will be a JSON representation of the report execution result.
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
command_string: str
|
|
280
|
+
The string to execute
|
|
281
|
+
do_eval: bool, optional
|
|
282
|
+
If True, a return value will be computed and returned
|
|
283
|
+
json: bool, optional
|
|
284
|
+
If True and do_eval is True, the return value will be a JSON representation of
|
|
285
|
+
the evaluated value.
|
|
286
|
+
|
|
287
|
+
Returns
|
|
288
|
+
-------
|
|
289
|
+
Any
|
|
290
|
+
None, a string ready for Python eval() or a JSON string.
|
|
291
|
+
|
|
292
|
+
Raises
|
|
293
|
+
------
|
|
294
|
+
RuntimeError if the operation fails.
|
|
295
|
+
IOError if the communication fails.
|
|
296
|
+
"""
|
|
297
|
+
self.connect()
|
|
298
|
+
flags = ensight_pb2.PythonRequest.EXEC_RETURN_PYTHON
|
|
299
|
+
response: Any
|
|
300
|
+
if json:
|
|
301
|
+
flags = ensight_pb2.PythonRequest.EXEC_RETURN_JSON
|
|
302
|
+
if not do_eval:
|
|
303
|
+
flags = ensight_pb2.PythonRequest.EXEC_NO_RESULT
|
|
304
|
+
try:
|
|
305
|
+
if self._stub:
|
|
306
|
+
response = self._stub.RunPython(
|
|
307
|
+
ensight_pb2.PythonRequest(type=flags, command=command_string),
|
|
308
|
+
metadata=self._metadata(),
|
|
309
|
+
)
|
|
310
|
+
except Exception:
|
|
311
|
+
raise IOError("gRPC connection dropped")
|
|
312
|
+
if response.error < 0:
|
|
313
|
+
raise RuntimeError(response.value)
|
|
314
|
+
if flags == ensight_pb2.PythonRequest.EXEC_NO_RESULT:
|
|
315
|
+
return None
|
|
316
|
+
# This was moved externally so pre-processing could be performed
|
|
317
|
+
# elif flags == ensight_pb2.PythonRequest.EXEC_RETURN_PYTHON:
|
|
318
|
+
# return eval(response.value)
|
|
319
|
+
return response.value
|
|
320
|
+
|
|
321
|
+
def prefix(self) -> str:
|
|
322
|
+
"""Return the unique prefix for this instance.
|
|
323
|
+
|
|
324
|
+
Some EnSight gRPC APIs require a unique prefix so that EnSight can handle
|
|
325
|
+
multiple, simultaneous remote connections. This method will generate a GUID-based
|
|
326
|
+
prefix.
|
|
327
|
+
|
|
328
|
+
Returns
|
|
329
|
+
-------
|
|
330
|
+
str
|
|
331
|
+
A unique (for this session) prefix string of the form: grpc://{uuid}/
|
|
332
|
+
"""
|
|
333
|
+
# prefix URIs will have the format: "grpc://{uuid}/{callbackname}?enum={}&uid={}"
|
|
334
|
+
if self._prefix is None:
|
|
335
|
+
self._prefix = "grpc://" + str(uuid.uuid1()) + "/"
|
|
336
|
+
return self._prefix
|
|
337
|
+
|
|
338
|
+
def event_stream_enable(self, callback: Optional[Callable] = None) -> None:
|
|
339
|
+
"""Enable a simple gRPC-based event stream from EnSight
|
|
340
|
+
|
|
341
|
+
This method makes a EnSightService::GetEventStream() gRPC call into EnSight, returning
|
|
342
|
+
an ensightservice::EventReply stream. The method creates a thread to hold this
|
|
343
|
+
stream open and read new events from it. The thread adds the event strings to
|
|
344
|
+
a list of events stored on this instance. If callback is not None, the object
|
|
345
|
+
will be called with the event string, otherwise they can be retrieved using get_event().
|
|
346
|
+
"""
|
|
347
|
+
if self._event_stream is not None:
|
|
348
|
+
return
|
|
349
|
+
self._event_callback = callback
|
|
350
|
+
self.connect()
|
|
351
|
+
if self._stub:
|
|
352
|
+
self._event_stream = self._stub.GetEventStream(
|
|
353
|
+
ensight_pb2.EventStreamRequest(prefix=self.prefix()),
|
|
354
|
+
metadata=self._metadata(),
|
|
355
|
+
)
|
|
356
|
+
self._event_thread = threading.Thread(target=self._poll_events)
|
|
357
|
+
self._event_thread.daemon = True
|
|
358
|
+
self._event_thread.start()
|
|
359
|
+
|
|
360
|
+
def event_stream_is_enabled(self) -> bool:
|
|
361
|
+
"""Check to see if the event stream is enabled
|
|
362
|
+
|
|
363
|
+
If an event stream has been successfully established via
|
|
364
|
+
event_stream_enable(), then this function returns True.
|
|
365
|
+
|
|
366
|
+
Returns
|
|
367
|
+
-------
|
|
368
|
+
True if a ensightservice::EventReply steam is active
|
|
369
|
+
"""
|
|
370
|
+
return self._event_stream is not None
|
|
371
|
+
|
|
372
|
+
def dynamic_scene_graph_stream(self, client_cmds):
|
|
373
|
+
"""Open up a dynamic scene graph stream
|
|
374
|
+
|
|
375
|
+
Make a DynamicSceneGraphService::GetSceneStream() rpc call and return
|
|
376
|
+
a ensightservice::SceneUpdateCommand stream instance.
|
|
377
|
+
|
|
378
|
+
Parameters
|
|
379
|
+
----------
|
|
380
|
+
client_cmds
|
|
381
|
+
iterator that produces ensightservice::SceneClientCommand objects
|
|
382
|
+
|
|
383
|
+
Returns
|
|
384
|
+
-------
|
|
385
|
+
ensightservice::SceneUpdateCommand stream instance
|
|
386
|
+
"""
|
|
387
|
+
self.connect()
|
|
388
|
+
return self._dsg_stub.GetSceneStream(client_cmds, metadata=self._metadata())
|
|
389
|
+
|
|
390
|
+
def get_event(self) -> Optional[str]:
|
|
391
|
+
"""Retrieve and remove the oldest ensightservice::EventReply string
|
|
392
|
+
|
|
393
|
+
When any of the event streaming systems is enabled, Python threads will receive the
|
|
394
|
+
event records and store them in this instance in an ordered fashion. This method
|
|
395
|
+
retrieves the oldest ensightservice::EventReply string in the queue.
|
|
396
|
+
|
|
397
|
+
Returns
|
|
398
|
+
-------
|
|
399
|
+
None or the oldest event string in the queue.
|
|
400
|
+
"""
|
|
401
|
+
try:
|
|
402
|
+
return self._events.pop(0)
|
|
403
|
+
except IndexError:
|
|
404
|
+
return None
|
|
405
|
+
|
|
406
|
+
def _put_event(self, evt: "ensight_pb2.EventReply") -> None:
|
|
407
|
+
"""Add an event record to the event queue on this instance
|
|
408
|
+
|
|
409
|
+
This method is used by threads to make the events they receive available to
|
|
410
|
+
calling applications via get_event().
|
|
411
|
+
"""
|
|
412
|
+
if self._event_callback:
|
|
413
|
+
self._event_callback(evt.tag)
|
|
414
|
+
return
|
|
415
|
+
self._events.append(evt.tag)
|
|
416
|
+
|
|
417
|
+
def _poll_events(self) -> None:
|
|
418
|
+
"""Internal method to handle event streams
|
|
419
|
+
|
|
420
|
+
This method is called by a Python thread to read events via the established
|
|
421
|
+
ensightservice::EventReply stream.
|
|
422
|
+
"""
|
|
423
|
+
try:
|
|
424
|
+
while self._stub is not None:
|
|
425
|
+
evt = self._event_stream.next()
|
|
426
|
+
self._put_event(evt)
|
|
427
|
+
except Exception:
|
|
428
|
+
# signal that the gRPC connection has broken
|
|
429
|
+
self._event_stream = None
|
|
430
|
+
self._event_thread = None
|