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.
Files changed (37) hide show
  1. ansys/pyensight/core/__init__.py +41 -0
  2. ansys/pyensight/core/common.py +341 -0
  3. ansys/pyensight/core/deep_pixel_view.html +98 -0
  4. ansys/pyensight/core/dockerlauncher.py +1124 -0
  5. ansys/pyensight/core/dvs.py +872 -0
  6. ansys/pyensight/core/enscontext.py +345 -0
  7. ansys/pyensight/core/enshell_grpc.py +641 -0
  8. ansys/pyensight/core/ensight_grpc.py +874 -0
  9. ansys/pyensight/core/ensobj.py +515 -0
  10. ansys/pyensight/core/launch_ensight.py +296 -0
  11. ansys/pyensight/core/launcher.py +388 -0
  12. ansys/pyensight/core/libuserd.py +2110 -0
  13. ansys/pyensight/core/listobj.py +280 -0
  14. ansys/pyensight/core/locallauncher.py +579 -0
  15. ansys/pyensight/core/py.typed +0 -0
  16. ansys/pyensight/core/renderable.py +880 -0
  17. ansys/pyensight/core/session.py +1923 -0
  18. ansys/pyensight/core/sgeo_poll.html +24 -0
  19. ansys/pyensight/core/utils/__init__.py +21 -0
  20. ansys/pyensight/core/utils/adr.py +111 -0
  21. ansys/pyensight/core/utils/dsg_server.py +1220 -0
  22. ansys/pyensight/core/utils/export.py +606 -0
  23. ansys/pyensight/core/utils/omniverse.py +769 -0
  24. ansys/pyensight/core/utils/omniverse_cli.py +614 -0
  25. ansys/pyensight/core/utils/omniverse_dsg_server.py +1196 -0
  26. ansys/pyensight/core/utils/omniverse_glb_server.py +848 -0
  27. ansys/pyensight/core/utils/parts.py +1221 -0
  28. ansys/pyensight/core/utils/query.py +487 -0
  29. ansys/pyensight/core/utils/readers.py +300 -0
  30. ansys/pyensight/core/utils/resources/Materials/000_sky.exr +0 -0
  31. ansys/pyensight/core/utils/support.py +128 -0
  32. ansys/pyensight/core/utils/variables.py +2019 -0
  33. ansys/pyensight/core/utils/views.py +674 -0
  34. ansys_pyensight_core-0.11.0.dist-info/METADATA +309 -0
  35. ansys_pyensight_core-0.11.0.dist-info/RECORD +37 -0
  36. ansys_pyensight_core-0.11.0.dist-info/WHEEL +4 -0
  37. ansys_pyensight_core-0.11.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,579 @@
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
+ """Local Launcher module.
24
+
25
+ The Local Launcher module provides PyEnSight with the ability to launch an
26
+ EnSight :class:`Session<ansys.pyensight.core.Session>` instance using a
27
+ local Ansys installation.
28
+
29
+ Examples:
30
+ >>> from ansys.pyensight.core import LocalLauncher
31
+ >>> session = LocalLauncher().start()
32
+ """
33
+ import glob
34
+ import logging
35
+ import os.path
36
+ import platform
37
+ import re
38
+ import shutil
39
+ import subprocess
40
+ import tempfile
41
+ import time
42
+ from typing import Optional
43
+ import uuid
44
+ import warnings
45
+
46
+ import ansys.pyensight.core as pyensight
47
+ from ansys.pyensight.core.common import GRPC_WARNING_MESSAGE, find_unused_ports, grpc_version_check
48
+ from ansys.pyensight.core.launcher import Launcher
49
+ import ansys.pyensight.core.session
50
+ import psutil
51
+
52
+
53
+ class LocalLauncher(Launcher):
54
+ """Creates a ``Session`` instance by launching a local copy of EnSight.
55
+
56
+ This class allows you to launch locally a copy of EnSight that supports the
57
+ gRPC interface. It creates and binds a :class:`Session<ansys.pyensight.core.Session>`
58
+ instance to the created gRPC session and returns that instance.
59
+
60
+ Parameters
61
+ ----------
62
+ ansys_installation : str, optional
63
+ Path to the local Ansys installation, including the version
64
+ directory. The default is ``None``, in which case common locations
65
+ are scanned to detect the latest local Ansys installation. The
66
+ ``PYENSIGHT_ANSYS_INSTALLATION`` environmental variable is checked first.
67
+ application : str, optional
68
+ App to launch. The default is ``ensight``, but ``envision`` is
69
+ also an option.
70
+ batch : bool, optional
71
+ Whether to run EnSight (or EnVision) in batch mode. The default
72
+ is ``True``, in which case the full GUI is not presented.
73
+ grpc_use_tcp_sockets :
74
+ If using gRPC, and if True, then allow TCP Socket based connections
75
+ instead of only local connections.
76
+ grpc_allow_network_connections :
77
+ If using gRPC and using TCP Socket based connections, listen on all networks.
78
+ grpc_disable_tls :
79
+ If using gRPC and using TCP Socket based connections, disable TLS.
80
+ grpc_uds_pathname :
81
+ If using gRPC and using Unix Domain Socket based connections, explicitly
82
+ set the pathname to the shared UDS file instead of using the default.
83
+ timeout : float, optional
84
+ Number of seconds to try a gRPC connection before giving up.
85
+ This parameter is defined on the parent ``Launcher`` class,
86
+ where the default is ``120``.
87
+ use_egl : bool, optional
88
+ Whether to use EGL hardware for accelerated graphics. The platform
89
+ must be able to support this hardware. This parameter is defined on
90
+ the parent ``Launcher`` class, where the default is ``False``.
91
+ use_sos : int, optional
92
+ Number of EnSight servers to use for SOS (Server of Server) mode.
93
+ This parameter is defined on the parent ``Launcher`` class, where
94
+ the default is ``None``, in which case SOS mode is not used.
95
+ additional_command_line_options: list, optional
96
+ Additional command line options to be used to launch EnSight.
97
+
98
+ Examples
99
+ --------
100
+ >>> from ansys.pyensight.core import LocalLauncher
101
+ >>> # Create one EnSight session
102
+ >>> session1 = LocalLauncher(ansys_installation='/ansys_inc/v232').start()
103
+ >>> # Create a second session (a new LocalLauncher instance is required)
104
+ >>> session2 = LocalLauncher(ansys_installation='/ansys_inc/v232').start()
105
+
106
+ WARNING:
107
+ Overriding the default values for these options: grpc_use_tcp_sockets, grpc_allow_network_connections,
108
+ and grpc_disable_tls
109
+ can possibly permit control of this computer and any data which resides on it.
110
+ Modification of this configuration is not recommended. Please see the
111
+ documentation for your installed product for additional information.
112
+ """
113
+
114
+ def __init__(
115
+ self,
116
+ ansys_installation: Optional[str] = None,
117
+ application: Optional[str] = "ensight",
118
+ batch: bool = True,
119
+ grpc_use_tcp_sockets: Optional[bool] = False,
120
+ grpc_allow_network_connections: Optional[bool] = False,
121
+ grpc_disable_tls: Optional[bool] = False,
122
+ grpc_uds_pathname: Optional[str] = None,
123
+ **kwargs,
124
+ ) -> None:
125
+ super().__init__(**kwargs)
126
+
127
+ # get the user selected installation directory
128
+ self._install_path: str = self.get_cei_install_directory(ansys_installation)
129
+ # Will this be ensight or envision
130
+ self._application = application
131
+ # EnSight session secret key
132
+ self._secret_key: str = ""
133
+ # temporary directory served by websocketserver
134
+ self._session_directory = None
135
+ # launched process ids
136
+ self._ensight_pid = None
137
+ self._websocketserver_pid = None
138
+ self._webui_pid = None
139
+ # and ports
140
+ self._ports = None
141
+ # Are we running the instance in batch
142
+ self._batch = batch
143
+ self._grpc_use_tcp_sockets = grpc_use_tcp_sockets
144
+ self._grpc_allow_network_connections = grpc_allow_network_connections
145
+ self._grpc_disable_tls = grpc_disable_tls
146
+ self._grpc_uds_pathname = grpc_uds_pathname
147
+
148
+ @property
149
+ def application(self):
150
+ """Type of app to launch. Options are ``ensight`` and ``envision``."""
151
+ return self._application
152
+
153
+ def launch_webui(self, version, popen_common):
154
+ if os.environ.get("PYENSIGHT_FLUIDSONE_PATH"):
155
+ fluids_one_path = os.environ["PYENSIGHT_FLUIDSONE_PATH"]
156
+ else:
157
+ awp_path = os.path.dirname(self._install_path)
158
+ platf = "winx64" if self._is_windows() else "linx64"
159
+ fluids_one_path = os.path.join(awp_path, "FluidsOne", "server", platf, "fluids_one")
160
+ if self._is_windows():
161
+ fluids_one_path += ".exe"
162
+ cmd = [fluids_one_path, "--main-run-mode", "post"]
163
+ path_to_webui = self._install_path
164
+ # Dev environment
165
+ path_to_webui_internal = os.path.join(
166
+ path_to_webui, f"nexus{version}", f"ansys{version}", "ensight", "WebUI", "web", "ui"
167
+ )
168
+ # Ansys environment
169
+ path_to_webui_ansys = os.path.join(os.path.dirname(path_to_webui), "FluidsOne", "web", "ui")
170
+ path_to_webui = path_to_webui_internal
171
+ if os.path.exists(path_to_webui_ansys):
172
+ path_to_webui = path_to_webui_ansys
173
+ cmd += ["--server-listen-port", str(self._ports[5])]
174
+ cmd += ["--server-web-roots", path_to_webui]
175
+ cmd += ["--ensight-grpc-port", str(self._ports[0])]
176
+ cmd += ["--ensight-html-port", str(self._ports[2])]
177
+ cmd += ["--ensight-ws-port", str(self._ports[3])]
178
+ cmd += ["--ensight-session-directory", self._session_directory]
179
+ cmd += ["--ensight-secret-key", self._secret_key]
180
+ cmd += ["--main-show-gui", "'False'"]
181
+ if "PYENSIGHT_DEBUG" in os.environ:
182
+ try:
183
+ if int(os.environ["PYENSIGHT_DEBUG"]) > 0:
184
+ del popen_common["stdout"]
185
+ del popen_common["stderr"]
186
+ except (ValueError, KeyError):
187
+ pass
188
+ popen_common["env"].update(
189
+ {
190
+ "SIMBA_WEBSERVER_TOKEN": self._secret_key,
191
+ "FLUENT_WEBSERVER_TOKEN": self._secret_key,
192
+ }
193
+ )
194
+ self._webui_pid = subprocess.Popen(cmd, **popen_common).pid
195
+
196
+ def _grpc_version_check(self):
197
+ """Check if the gRPC security options apply to the EnSight install."""
198
+ buildinfo = os.path.join(self._install_path, "BUILDINFO.txt")
199
+ if not os.path.exists(buildinfo):
200
+ if not os.path.exists(
201
+ os.path.join(os.path.dirname(self._install_path), "licensingclient")
202
+ ):
203
+ # Dev installation. Assume the gRPC security options are available
204
+ return True
205
+ raise RuntimeError("Couldn't find BUILDINFO file, cannot check installation.")
206
+ with open(buildinfo, "r") as buildinfo_file:
207
+ text = buildinfo_file.read()
208
+ internal_version, ensight_full_version = self._get_versionfrom_buildinfo(text)
209
+ return grpc_version_check(internal_version, ensight_full_version)
210
+
211
+ def start(self) -> "pyensight.Session":
212
+ """Start an EnSight session using the local EnSight installation.
213
+
214
+ This method launches a copy of EnSight locally that supports the
215
+ gRPC interface. It creates and binds a ``Session`` instance to the
216
+ created gRPC session and returns that session.
217
+
218
+ Returns
219
+ -------
220
+ obj
221
+ PyEnSight ``Session`` object instance.
222
+
223
+ Raises
224
+ ------
225
+ RuntimeError:
226
+ If the necessary number of ports could not be allocated.
227
+ """
228
+ self._has_grpc_changes = self._grpc_version_check()
229
+ if not self._has_grpc_changes:
230
+ warnings.warn(GRPC_WARNING_MESSAGE)
231
+ tmp_session = super().start()
232
+ if tmp_session:
233
+ return tmp_session
234
+ if self._ports is None:
235
+ # session directory and UUID
236
+ self._secret_key = str(uuid.uuid1())
237
+ self.session_directory = tempfile.mkdtemp(prefix="pyensight_")
238
+ if (
239
+ not self._grpc_uds_pathname
240
+ and not self._grpc_use_tcp_sockets
241
+ and not self._is_windows()
242
+ ):
243
+ self._grpc_uds_pathname = os.path.join(self.session_directory, "pyensight")
244
+
245
+ # gRPC port, VNC port, websocketserver ws, websocketserver html
246
+ to_avoid = self._find_ports_used_by_other_pyensight_and_ensight()
247
+ num_ports = 5
248
+ if self._launch_webui: # port 6
249
+ num_ports += 1
250
+ if self._vtk_ws_port: # port 6 or 7 depending on launch_webui
251
+ num_ports += 1
252
+ self._ports = find_unused_ports(num_ports, avoid=to_avoid)
253
+ if self._ports is None:
254
+ raise RuntimeError("Unable to allocate local ports for EnSight session")
255
+ is_windows = self._is_windows()
256
+
257
+ # Launch EnSight
258
+ # create the environmental variables
259
+ local_env = os.environ.copy()
260
+ if not local_env.get("ENSIGHT_GRPC_DISABLE_SECURITY_TOKEN"):
261
+ local_env["ENSIGHT_SECURITY_TOKEN"] = self._secret_key
262
+ local_env["WEBSOCKETSERVER_SECURITY_TOKEN"] = self._secret_key
263
+ local_env["ENSIGHT_SESSION_TEMPDIR"] = self.session_directory
264
+ # If for some reason, the ENSIGHT_ANSYS_LAUNCH is set previously,
265
+ # honor that value, otherwise set it to "pyensight". This allows
266
+ # for an environmental setup to set the value to something else
267
+ # (e.g. their "app").
268
+ if "ENSIGHT_ANSYS_LAUNCH" not in local_env:
269
+ local_env["ENSIGHT_ANSYS_LAUNCH"] = "pyensight"
270
+
271
+ # build the EnSight command
272
+ exe = os.path.join(self._install_path, "bin", self.application)
273
+ cmd = [exe]
274
+ if self._batch:
275
+ cmd.append("-batch")
276
+ else:
277
+ cmd.append("-no_start_screen")
278
+ cmd.extend(["-grpc_server", str(self._ports[0])])
279
+ if self._has_grpc_changes:
280
+ if self._grpc_use_tcp_sockets:
281
+ cmd.append("-grpc_use_tcp_sockets")
282
+ if self._grpc_allow_network_connections:
283
+ cmd.append("-grpc_allow_network_connections")
284
+ if self._grpc_disable_tls:
285
+ cmd.append("-grpc_disable_tls")
286
+ if self._grpc_uds_pathname:
287
+ cmd.append("-grpc_uds_pathname")
288
+ cmd.append(self._grpc_uds_pathname)
289
+ vnc_url = f"vnc://%%3Frfb_port={self._ports[1]}%%26use_auth=0"
290
+ cmd.extend(["-vnc", vnc_url])
291
+ cmd.extend(["-ports", str(self._ports[4])])
292
+ if self._additional_command_line_options:
293
+ cmd.extend(self._additional_command_line_options)
294
+
295
+ use_egl = self._use_egl()
296
+
297
+ # to aid in debugging, PYENSIGHT_DEBUG can be set to a non-zero integer
298
+ popen_common = dict(
299
+ stdout=subprocess.DEVNULL,
300
+ stderr=subprocess.DEVNULL,
301
+ cwd=self.session_directory,
302
+ env=local_env,
303
+ )
304
+ if "PYENSIGHT_DEBUG" in os.environ:
305
+ try:
306
+ if int(os.environ["PYENSIGHT_DEBUG"]) > 0:
307
+ del popen_common["stdout"]
308
+ del popen_common["stderr"]
309
+ except ValueError:
310
+ pass
311
+
312
+ if is_windows:
313
+ cmd[0] += ".bat"
314
+ if use_egl:
315
+ cmd.append("-egl")
316
+ if self._use_sos:
317
+ cmd.append("-sos")
318
+ if not self._use_mpi:
319
+ cmd.append("-nservers")
320
+ cmd.append(str(int(self._use_sos)))
321
+ else:
322
+ cmd.append(f"--np={int(self._use_sos)+1}")
323
+ cmd.append(f"--mpi={self._use_mpi}")
324
+ cmd.append(f"--ic={self._interconnect}")
325
+ hosts = ",".join(self._server_hosts)
326
+ cmd.append(f"--cnf={hosts}")
327
+ if self._liben_rest:
328
+ cmd.extend(["-rest_server", str(self._ports[2])])
329
+
330
+ # cmd.append("-minimize_console")
331
+ logging.debug(f"Starting EnSight with : {cmd}\n")
332
+ self._ensight_pid = subprocess.Popen(cmd, **popen_common).pid
333
+
334
+ # Launch websocketserver
335
+
336
+ # find websocketserver script
337
+ found_scripts = glob.glob(
338
+ os.path.join(self._install_path, "nexus*", "nexus_launcher", "websocketserver.py")
339
+ )
340
+ if not found_scripts:
341
+ raise RuntimeError("Unable to find websocketserver script")
342
+ # If more than one nexus directory is found, find the one that corresponds
343
+ # to the version that should be used. Otherwise, just take the first one found.
344
+ # This is likely to only happen for developer installations or build areas.
345
+ idx = 0
346
+ try:
347
+ found_scripts_len = len(found_scripts)
348
+ if found_scripts_len > 1:
349
+ version_str = str(pyensight.__ansys_version__)
350
+ for i in range(found_scripts_len):
351
+ if version_str in found_scripts[i]:
352
+ idx = i
353
+ break
354
+ except Exception:
355
+ pass
356
+ websocket_script = found_scripts[idx]
357
+ version = re.findall(r"nexus(\d+)", websocket_script)[0]
358
+ # build the commandline
359
+ if not self._liben_rest:
360
+ cmd = [os.path.join(self._install_path, "bin", "cpython"), websocket_script]
361
+ if is_windows:
362
+ cmd[0] += ".bat"
363
+ cmd.extend(["--http_directory", self.session_directory])
364
+ # http port
365
+ cmd.extend(["--http_port", str(self._ports[2])])
366
+ # vnc port
367
+ cmd.extend(["--client_port", str(self._ports[1])])
368
+ if self._enable_rest_api:
369
+ # grpc port
370
+ cmd.extend(["--grpc_port", str(self._ports[0])])
371
+ if self._has_grpc_changes:
372
+ if self._grpc_use_tcp_sockets:
373
+ cmd.append("--grpc_use_tcp_sockets")
374
+ if self._grpc_allow_network_connections:
375
+ cmd.append("--grpc_allow_network_connections")
376
+ if self._grpc_disable_tls:
377
+ cmd.append("--grpc_disable_tls")
378
+ if self._grpc_uds_pathname:
379
+ cmd.append("--grpc_uds_pathname")
380
+ cmd.append(self._grpc_uds_pathname)
381
+ # EnVision sessions
382
+ cmd.extend(["--local_session", "envision", "5"])
383
+ if int(version) > 252 and self._rest_ws_separate_loops:
384
+ cmd.append("--separate_loops")
385
+ cmd.extend(["--security_token", self._secret_key])
386
+ # websocket port
387
+ if int(version) > 252 and self._do_not_start_ws:
388
+ cmd.append("-1")
389
+ else:
390
+ cmd.append(str(self._ports[3]))
391
+ logging.debug(f"Starting WSS: {cmd}\n")
392
+ if is_windows:
393
+ startupinfo = subprocess.STARTUPINFO()
394
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
395
+ popen_common["startupinfo"] = startupinfo
396
+ self._websocketserver_pid = subprocess.Popen(cmd, **popen_common).pid
397
+
398
+ # build the session instance
399
+ logging.debug(
400
+ f"Creating session with ports for grpc:{self._ports[0]}\n"
401
+ + f"html:{self._ports[2]} ws:{self._ports[3]}\n"
402
+ + f"key:{self._secret_key}\n"
403
+ )
404
+ use_sos = False
405
+ if self._use_sos:
406
+ use_sos = True
407
+
408
+ # need to use Session like this for mock testing this class
409
+ session = ansys.pyensight.core.session.Session(
410
+ host="127.0.0.1",
411
+ grpc_port=self._ports[0],
412
+ grpc_use_tcp_sockets=self._grpc_use_tcp_sockets,
413
+ grpc_allow_network_connections=self._grpc_allow_network_connections,
414
+ grpc_disable_tls=self._grpc_disable_tls,
415
+ grpc_uds_pathname=self._grpc_uds_pathname,
416
+ html_port=self._ports[2],
417
+ ws_port=self._ports[3],
418
+ install_path=self._install_path,
419
+ secret_key=self._secret_key,
420
+ timeout=self._timeout,
421
+ sos=use_sos,
422
+ rest_api=self._enable_rest_api,
423
+ webui_port=self._ports[5] if self._launch_webui else None,
424
+ disable_grpc_options=not self._has_grpc_changes,
425
+ )
426
+ session.launcher = self
427
+ self._sessions.append(session)
428
+ if self._launch_webui:
429
+ self.launch_webui(version, popen_common)
430
+ return session
431
+
432
+ @staticmethod
433
+ def _kill_process_unix(pid):
434
+ external_kill = ["kill", "-9", str(pid)]
435
+ process = psutil.Popen(external_kill, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
436
+ process.wait()
437
+
438
+ @staticmethod
439
+ def _kill_process_windows(pid):
440
+ external_kill = ["taskkill", "/F", "/PID", str(pid)]
441
+ process = psutil.Popen(external_kill, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
442
+ process.wait()
443
+
444
+ def _kill_process_by_pid(self, pid):
445
+ if self._is_windows():
446
+ self._kill_process_windows(pid)
447
+ else:
448
+ self._kill_process_unix(pid)
449
+
450
+ def _kill_process_tree(self, pid):
451
+ try:
452
+ parent = psutil.Process(pid)
453
+ for child in parent.children(recursive=True):
454
+ try:
455
+ self._kill_process_by_pid(child.pid)
456
+ child.kill()
457
+ except (psutil.AccessDenied, psutil.ZombieProcess, OSError, psutil.NoSuchProcess):
458
+ continue
459
+ self._kill_process_by_pid(parent.pid)
460
+ parent.kill()
461
+ except (psutil.AccessDenied, psutil.ZombieProcess, OSError, psutil.NoSuchProcess):
462
+ pass
463
+
464
+ def stop(self) -> None:
465
+ """Release any additional resources allocated during launching."""
466
+ maximum_wait_secs = 120.0
467
+ start_time = time.time()
468
+ while (time.time() - start_time) < maximum_wait_secs:
469
+ try:
470
+ shutil.rmtree(self.session_directory)
471
+ self._ports = None
472
+ super().stop()
473
+ return
474
+ except PermissionError:
475
+ pass
476
+ except FileNotFoundError:
477
+ pass
478
+ except Exception:
479
+ raise
480
+ raise RuntimeError(f"Unable to remove {self.session_directory} in {maximum_wait_secs}s")
481
+
482
+ def close(self, session):
483
+ """Shut down the launched EnSight session.
484
+
485
+ This method closes all associated sessions and then stops the
486
+ launched EnSight instance.
487
+
488
+ Parameters
489
+ ----------
490
+ session : ``pyensight.Session``
491
+ Session to close.
492
+
493
+ Raises
494
+ ------
495
+ RuntimeError
496
+ If the session was not launched by this launcher.
497
+
498
+ """
499
+ if self._websocketserver_pid:
500
+ self._kill_process_tree(self._websocketserver_pid)
501
+ return super().close(session)
502
+
503
+ @staticmethod
504
+ def get_cei_install_directory(ansys_installation: Optional[str]) -> str:
505
+ """Get the Ansys distribution CEI directory to use.
506
+
507
+ Parameters
508
+ ----------
509
+ ansys_installation : str, optional
510
+ Path to the local Ansys installation, including the version
511
+ directory. The default is ``None``, in which case common locations
512
+ are scanned to detect the latest local Ansys installation. The
513
+ ``PYENSIGHT_ANSYS_INSTALLATION`` environmental variable is checked first.
514
+
515
+ Returns
516
+ -------
517
+ str
518
+ Validated installation directory, which contains ``bin/ensight``.
519
+
520
+ Raises
521
+ ------
522
+ RuntimeError:
523
+ If the installation directory does not point to a
524
+ valid EnSight installation.
525
+ """
526
+ dirs_to_check = []
527
+ if ansys_installation:
528
+ # User passed directory
529
+ dirs_to_check.append(os.path.join(ansys_installation, "CEI"))
530
+ dirs_to_check.append(ansys_installation)
531
+ else:
532
+ # Environmental variable
533
+ if "PYENSIGHT_ANSYS_INSTALLATION" in os.environ:
534
+ env_inst = os.environ["PYENSIGHT_ANSYS_INSTALLATION"]
535
+ dirs_to_check.append(env_inst)
536
+ # Note: PYENSIGHT_ANSYS_INSTALLATION is designed for devel builds
537
+ # where there is no CEI directory, but for folks using it in other
538
+ # ways, we'll add that one too, just in case.
539
+ dirs_to_check.append(os.path.join(env_inst, "CEI"))
540
+ # 'enve' home directory (running in local distro)
541
+ try:
542
+ import enve
543
+
544
+ dirs_to_check.append(enve.home())
545
+ except ModuleNotFoundError:
546
+ pass
547
+ # Look for Ansys install using target version number
548
+ version = pyensight.__ansys_version__
549
+ if f"AWP_ROOT{version}" in os.environ:
550
+ dirs_to_check.append(os.path.join(os.environ[f"AWP_ROOT{version}"], "CEI"))
551
+ # Common, default install locations
552
+ install_dir = f"/ansys_inc/v{version}/CEI"
553
+ if platform.system().startswith("Wind"):
554
+ install_dir = rf"C:\Program Files\ANSYS Inc\v{version}\CEI"
555
+ dirs_to_check.append(install_dir)
556
+
557
+ for install_dir in dirs_to_check:
558
+ launch_file = os.path.join(install_dir, "bin", "ensight")
559
+ if os.path.exists(launch_file):
560
+ return install_dir
561
+
562
+ raise RuntimeError(f"Unable to detect an EnSight installation in: {dirs_to_check}")
563
+
564
+ def _is_system_egl_capable(self) -> bool:
565
+ """Check if the system supports the EGL launch.
566
+
567
+ Returns
568
+ -------
569
+ bool
570
+ ``True`` if the system supports the EGL launch, ``False`` otherwise.
571
+ """
572
+ if self._is_windows():
573
+ return False
574
+ egl_test_path = os.path.join(self._install_path, "bin", "cei_egltest")
575
+ egl_proc = subprocess.Popen([egl_test_path], stdout=subprocess.PIPE)
576
+ _, _ = egl_proc.communicate()
577
+ if egl_proc.returncode == 0:
578
+ return True
579
+ return False
File without changes