ansys-mechanical-core 0.11.12__py3-none-any.whl → 0.11.13__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/_version.py +48 -48
- ansys/mechanical/core/embedding/app.py +610 -610
- ansys/mechanical/core/embedding/background.py +11 -2
- ansys/mechanical/core/embedding/logger/__init__.py +219 -219
- ansys/mechanical/core/embedding/resolver.py +48 -41
- ansys/mechanical/core/embedding/rpc/__init__.py +36 -0
- ansys/mechanical/core/embedding/rpc/client.py +237 -0
- ansys/mechanical/core/embedding/rpc/server.py +382 -0
- ansys/mechanical/core/embedding/rpc/utils.py +120 -0
- ansys/mechanical/core/embedding/runtime.py +22 -0
- ansys/mechanical/core/feature_flags.py +1 -0
- ansys/mechanical/core/ide_config.py +212 -212
- ansys/mechanical/core/mechanical.py +2343 -2324
- ansys/mechanical/core/misc.py +176 -176
- ansys/mechanical/core/pool.py +712 -712
- ansys/mechanical/core/run.py +321 -321
- {ansys_mechanical_core-0.11.12.dist-info → ansys_mechanical_core-0.11.13.dist-info}/METADATA +35 -23
- {ansys_mechanical_core-0.11.12.dist-info → ansys_mechanical_core-0.11.13.dist-info}/RECORD +21 -17
- {ansys_mechanical_core-0.11.12.dist-info → ansys_mechanical_core-0.11.13.dist-info}/LICENSE +0 -0
- {ansys_mechanical_core-0.11.12.dist-info → ansys_mechanical_core-0.11.13.dist-info}/WHEEL +0 -0
- {ansys_mechanical_core-0.11.12.dist-info → ansys_mechanical_core-0.11.13.dist-info}/entry_points.txt +0 -0
ansys/mechanical/core/run.py
CHANGED
@@ -1,321 +1,321 @@
|
|
1
|
-
# Copyright (C) 2022 - 2025 ANSYS, Inc. and/or its affiliates.
|
2
|
-
# SPDX-License-Identifier: MIT
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in all
|
13
|
-
# copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
|
-
"""Convenience CLI to run mechanical."""
|
24
|
-
|
25
|
-
import asyncio
|
26
|
-
from asyncio.subprocess import PIPE
|
27
|
-
import os
|
28
|
-
import sys
|
29
|
-
import typing
|
30
|
-
import warnings
|
31
|
-
|
32
|
-
import ansys.tools.path as atp
|
33
|
-
import click
|
34
|
-
|
35
|
-
from ansys.mechanical.core.embedding.appdata import UniqueUserProfile
|
36
|
-
from ansys.mechanical.core.feature_flags import get_command_line_arguments, get_feature_flag_names
|
37
|
-
|
38
|
-
DRY_RUN = False
|
39
|
-
"""Dry run constant."""
|
40
|
-
|
41
|
-
# TODO - add logging options (reuse env var based logging initialization)
|
42
|
-
# TODO - add timeout
|
43
|
-
|
44
|
-
|
45
|
-
async def _read_and_display(cmd, env, do_display: bool):
|
46
|
-
"""Read command's stdout and stderr and display them as they are processed."""
|
47
|
-
# start process
|
48
|
-
process = await asyncio.create_subprocess_exec(*cmd, stdout=PIPE, stderr=PIPE, env=env)
|
49
|
-
# read child's stdout/stderr concurrently
|
50
|
-
stdout, stderr = [], [] # stderr, stdout buffers
|
51
|
-
tasks = {
|
52
|
-
asyncio.Task(process.stdout.readline()): (stdout, process.stdout, sys.stdout.buffer),
|
53
|
-
asyncio.Task(process.stderr.readline()): (stderr, process.stderr, sys.stderr.buffer),
|
54
|
-
}
|
55
|
-
while tasks:
|
56
|
-
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
57
|
-
if not done:
|
58
|
-
raise RuntimeError("Subprocess read failed: No tasks completed.")
|
59
|
-
for future in done:
|
60
|
-
buf, stream, display = tasks.pop(future)
|
61
|
-
line = future.result()
|
62
|
-
if line: # not EOF
|
63
|
-
buf.append(line) # save for later
|
64
|
-
if do_display:
|
65
|
-
display.write(line) # display in terminal
|
66
|
-
# schedule to read the next line
|
67
|
-
tasks[asyncio.Task(stream.readline())] = buf, stream, display
|
68
|
-
|
69
|
-
# wait for the process to exit
|
70
|
-
rc = await process.wait()
|
71
|
-
return rc, process, b"".join(stdout), b"".join(stderr)
|
72
|
-
|
73
|
-
|
74
|
-
def _run(args, env, check=False, display=False):
|
75
|
-
if os.name == "nt":
|
76
|
-
loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
|
77
|
-
asyncio.set_event_loop(loop)
|
78
|
-
else:
|
79
|
-
loop = asyncio.get_event_loop()
|
80
|
-
try:
|
81
|
-
rc, process, *output = loop.run_until_complete(_read_and_display(args, env, display))
|
82
|
-
if rc and check:
|
83
|
-
sys.exit("child failed with '{}' exit code".format(rc))
|
84
|
-
finally:
|
85
|
-
if os.name == "nt":
|
86
|
-
loop.close()
|
87
|
-
return process, output
|
88
|
-
|
89
|
-
|
90
|
-
def _cli_impl(
|
91
|
-
project_file: str = None,
|
92
|
-
port: int = 0,
|
93
|
-
debug: bool = False,
|
94
|
-
input_script: str = None,
|
95
|
-
script_args: str = None,
|
96
|
-
exe: str = None,
|
97
|
-
version: int = None,
|
98
|
-
graphical: bool = False,
|
99
|
-
show_welcome_screen: bool = False,
|
100
|
-
private_appdata: bool = False,
|
101
|
-
exit: bool = False,
|
102
|
-
features: str = None,
|
103
|
-
):
|
104
|
-
if project_file and input_script:
|
105
|
-
raise Exception("Cannot open a project file *and* run a script.")
|
106
|
-
|
107
|
-
if (not graphical) and project_file:
|
108
|
-
raise Exception("Cannot open a project file in batch mode.")
|
109
|
-
|
110
|
-
if port:
|
111
|
-
if project_file:
|
112
|
-
raise Exception("Cannot open in server mode with a project file.")
|
113
|
-
if input_script:
|
114
|
-
raise Exception("Cannot open in server mode with an input script.")
|
115
|
-
|
116
|
-
if not input_script and script_args:
|
117
|
-
raise Exception("Cannot add script arguments without an input script.")
|
118
|
-
|
119
|
-
if script_args:
|
120
|
-
if '"' in script_args:
|
121
|
-
raise Exception(
|
122
|
-
"Cannot have double quotes around individual arguments in the --script-args string."
|
123
|
-
)
|
124
|
-
|
125
|
-
# If the input_script and port are missing in batch mode, raise an exception
|
126
|
-
if (not graphical) and (input_script is None) and (not port):
|
127
|
-
raise Exception("An input script, -i, or port, --port, are required in batch mode.")
|
128
|
-
|
129
|
-
args = [exe, "-DSApplet"]
|
130
|
-
if (not graphical) or (not show_welcome_screen):
|
131
|
-
args.append("-AppModeMech")
|
132
|
-
|
133
|
-
if version < 232:
|
134
|
-
args.append("-nosplash")
|
135
|
-
args.append("-notabctrl")
|
136
|
-
|
137
|
-
if not graphical:
|
138
|
-
args.append("-b")
|
139
|
-
|
140
|
-
env: typing.Dict[str, str] = os.environ.copy()
|
141
|
-
if debug:
|
142
|
-
env["WBDEBUG_STOP"] = "1"
|
143
|
-
|
144
|
-
if port:
|
145
|
-
args.append("-grpc")
|
146
|
-
args.append(str(port))
|
147
|
-
|
148
|
-
if project_file:
|
149
|
-
args.append("-file")
|
150
|
-
args.append(project_file)
|
151
|
-
|
152
|
-
if input_script:
|
153
|
-
args.append("-script")
|
154
|
-
args.append(input_script)
|
155
|
-
|
156
|
-
if script_args:
|
157
|
-
args.append("-ScriptArgs")
|
158
|
-
args.append(f'"{script_args}"')
|
159
|
-
|
160
|
-
if (not graphical) and input_script:
|
161
|
-
exit = True
|
162
|
-
if version < 241:
|
163
|
-
warnings.warn(
|
164
|
-
"Please ensure ExtAPI.Application.Close() is at the end of your script. "
|
165
|
-
"Without this command, Batch mode will not terminate.",
|
166
|
-
stacklevel=2,
|
167
|
-
)
|
168
|
-
|
169
|
-
if exit and input_script and version >= 241:
|
170
|
-
args.append("-x")
|
171
|
-
|
172
|
-
profile: UniqueUserProfile = None
|
173
|
-
if private_appdata:
|
174
|
-
new_profile_name = f"Mechanical-{os.getpid()}"
|
175
|
-
profile = UniqueUserProfile(new_profile_name, dry_run=DRY_RUN)
|
176
|
-
profile.update_environment(env)
|
177
|
-
|
178
|
-
if not DRY_RUN:
|
179
|
-
version_name = atp.SUPPORTED_ANSYS_VERSIONS[version]
|
180
|
-
if graphical:
|
181
|
-
mode = "Graphical"
|
182
|
-
else:
|
183
|
-
mode = "Batch"
|
184
|
-
print(f"Starting Ansys Mechanical version {version_name} in {mode} mode...")
|
185
|
-
if port:
|
186
|
-
# TODO - Mechanical doesn't write anything to the stdout in grpc mode
|
187
|
-
# when logging is off.. Ideally we let Mechanical write it, so
|
188
|
-
# the user only sees the message when the server is ready.
|
189
|
-
print(f"Serving on port {port}")
|
190
|
-
|
191
|
-
if features is not None:
|
192
|
-
args.extend(get_command_line_arguments(features.split(";")))
|
193
|
-
|
194
|
-
if DRY_RUN:
|
195
|
-
return args, env
|
196
|
-
else:
|
197
|
-
_run(args, env, False, True)
|
198
|
-
|
199
|
-
if private_appdata:
|
200
|
-
profile.cleanup()
|
201
|
-
|
202
|
-
|
203
|
-
@click.command()
|
204
|
-
@click.help_option("--help", "-h")
|
205
|
-
@click.option(
|
206
|
-
"-p",
|
207
|
-
"--project-file",
|
208
|
-
default=None,
|
209
|
-
help="Opens Mechanical project file (.mechdb). Cannot be mixed with -i",
|
210
|
-
)
|
211
|
-
@click.option(
|
212
|
-
"--private-appdata",
|
213
|
-
default=None,
|
214
|
-
is_flag=True,
|
215
|
-
help="Make the appdata folder private.\
|
216
|
-
This enables you to run parallel instances of Mechanical.",
|
217
|
-
)
|
218
|
-
@click.option(
|
219
|
-
"--port",
|
220
|
-
type=int,
|
221
|
-
help="Start mechanical in server mode with the given port number",
|
222
|
-
)
|
223
|
-
@click.option(
|
224
|
-
"--features",
|
225
|
-
type=str,
|
226
|
-
default=None,
|
227
|
-
help=f"Beta feature flags to set, as a semicolon delimited list.\
|
228
|
-
Options: {get_feature_flag_names()}",
|
229
|
-
)
|
230
|
-
@click.option(
|
231
|
-
"-i",
|
232
|
-
"--input-script",
|
233
|
-
default=None,
|
234
|
-
help="Name of the input Python script. Cannot be mixed with -p",
|
235
|
-
)
|
236
|
-
@click.option(
|
237
|
-
"--script-args",
|
238
|
-
default=None,
|
239
|
-
help='Arguments to pass into the --input-script, -i. \
|
240
|
-
Write the arguments as a string, with each argument \
|
241
|
-
separated by a comma. For example, --script-args "arg1,arg2" \
|
242
|
-
This can only be used with the --input-script argument.',
|
243
|
-
)
|
244
|
-
@click.option(
|
245
|
-
"--exit",
|
246
|
-
is_flag=True,
|
247
|
-
default=None,
|
248
|
-
help="Exit the application after running an input script. \
|
249
|
-
You can only use this command with --input-script argument (-i). \
|
250
|
-
The command defaults to true you are not running the application in graphical mode. \
|
251
|
-
The ``exit`` command is only supported in version 2024 R1 or later.",
|
252
|
-
)
|
253
|
-
@click.option(
|
254
|
-
"-s",
|
255
|
-
"--show-welcome-screen",
|
256
|
-
is_flag=True,
|
257
|
-
default=False,
|
258
|
-
help="Show the welcome screen, where you can select the file to open.\
|
259
|
-
Only affects graphical mode",
|
260
|
-
)
|
261
|
-
@click.option(
|
262
|
-
"--debug",
|
263
|
-
is_flag=True,
|
264
|
-
default=False,
|
265
|
-
help="Show a debug dialog right when the process starts.",
|
266
|
-
)
|
267
|
-
@click.option(
|
268
|
-
"-r",
|
269
|
-
"--revision",
|
270
|
-
default=None,
|
271
|
-
type=int,
|
272
|
-
help='Ansys Revision number, e.g. "251" or "242". If none is specified\
|
273
|
-
, uses the default from ansys-tools-path',
|
274
|
-
)
|
275
|
-
@click.option(
|
276
|
-
"-g",
|
277
|
-
"--graphical",
|
278
|
-
is_flag=True,
|
279
|
-
default=False,
|
280
|
-
help="Graphical mode",
|
281
|
-
)
|
282
|
-
def cli(
|
283
|
-
project_file: str,
|
284
|
-
port: int,
|
285
|
-
debug: bool,
|
286
|
-
input_script: str,
|
287
|
-
script_args: str,
|
288
|
-
revision: int,
|
289
|
-
graphical: bool,
|
290
|
-
show_welcome_screen: bool,
|
291
|
-
private_appdata: bool,
|
292
|
-
exit: bool,
|
293
|
-
features: str,
|
294
|
-
):
|
295
|
-
"""CLI tool to run mechanical.
|
296
|
-
|
297
|
-
USAGE:
|
298
|
-
|
299
|
-
The following example demonstrates the main use of this tool:
|
300
|
-
|
301
|
-
$ ansys-mechanical -r 251 -g
|
302
|
-
|
303
|
-
Starting Ansys Mechanical version 2025R1 in graphical mode...
|
304
|
-
"""
|
305
|
-
exe = atp.get_mechanical_path(allow_input=False, version=revision)
|
306
|
-
version = atp.version_from_path("mechanical", exe)
|
307
|
-
|
308
|
-
return _cli_impl(
|
309
|
-
project_file,
|
310
|
-
port,
|
311
|
-
debug,
|
312
|
-
input_script,
|
313
|
-
script_args,
|
314
|
-
exe,
|
315
|
-
version,
|
316
|
-
graphical,
|
317
|
-
show_welcome_screen,
|
318
|
-
private_appdata,
|
319
|
-
exit,
|
320
|
-
features,
|
321
|
-
)
|
1
|
+
# Copyright (C) 2022 - 2025 ANSYS, Inc. and/or its affiliates.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
"""Convenience CLI to run mechanical."""
|
24
|
+
|
25
|
+
import asyncio
|
26
|
+
from asyncio.subprocess import PIPE
|
27
|
+
import os
|
28
|
+
import sys
|
29
|
+
import typing
|
30
|
+
import warnings
|
31
|
+
|
32
|
+
import ansys.tools.path as atp
|
33
|
+
import click
|
34
|
+
|
35
|
+
from ansys.mechanical.core.embedding.appdata import UniqueUserProfile
|
36
|
+
from ansys.mechanical.core.feature_flags import get_command_line_arguments, get_feature_flag_names
|
37
|
+
|
38
|
+
DRY_RUN = False
|
39
|
+
"""Dry run constant."""
|
40
|
+
|
41
|
+
# TODO - add logging options (reuse env var based logging initialization)
|
42
|
+
# TODO - add timeout
|
43
|
+
|
44
|
+
|
45
|
+
async def _read_and_display(cmd, env, do_display: bool):
|
46
|
+
"""Read command's stdout and stderr and display them as they are processed."""
|
47
|
+
# start process
|
48
|
+
process = await asyncio.create_subprocess_exec(*cmd, stdout=PIPE, stderr=PIPE, env=env)
|
49
|
+
# read child's stdout/stderr concurrently
|
50
|
+
stdout, stderr = [], [] # stderr, stdout buffers
|
51
|
+
tasks = {
|
52
|
+
asyncio.Task(process.stdout.readline()): (stdout, process.stdout, sys.stdout.buffer),
|
53
|
+
asyncio.Task(process.stderr.readline()): (stderr, process.stderr, sys.stderr.buffer),
|
54
|
+
}
|
55
|
+
while tasks:
|
56
|
+
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
57
|
+
if not done:
|
58
|
+
raise RuntimeError("Subprocess read failed: No tasks completed.")
|
59
|
+
for future in done:
|
60
|
+
buf, stream, display = tasks.pop(future)
|
61
|
+
line = future.result()
|
62
|
+
if line: # not EOF
|
63
|
+
buf.append(line) # save for later
|
64
|
+
if do_display:
|
65
|
+
display.write(line) # display in terminal
|
66
|
+
# schedule to read the next line
|
67
|
+
tasks[asyncio.Task(stream.readline())] = buf, stream, display
|
68
|
+
|
69
|
+
# wait for the process to exit
|
70
|
+
rc = await process.wait()
|
71
|
+
return rc, process, b"".join(stdout), b"".join(stderr)
|
72
|
+
|
73
|
+
|
74
|
+
def _run(args, env, check=False, display=False):
|
75
|
+
if os.name == "nt":
|
76
|
+
loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
|
77
|
+
asyncio.set_event_loop(loop)
|
78
|
+
else:
|
79
|
+
loop = asyncio.get_event_loop()
|
80
|
+
try:
|
81
|
+
rc, process, *output = loop.run_until_complete(_read_and_display(args, env, display))
|
82
|
+
if rc and check:
|
83
|
+
sys.exit("child failed with '{}' exit code".format(rc))
|
84
|
+
finally:
|
85
|
+
if os.name == "nt":
|
86
|
+
loop.close()
|
87
|
+
return process, output
|
88
|
+
|
89
|
+
|
90
|
+
def _cli_impl(
|
91
|
+
project_file: str = None,
|
92
|
+
port: int = 0,
|
93
|
+
debug: bool = False,
|
94
|
+
input_script: str = None,
|
95
|
+
script_args: str = None,
|
96
|
+
exe: str = None,
|
97
|
+
version: int = None,
|
98
|
+
graphical: bool = False,
|
99
|
+
show_welcome_screen: bool = False,
|
100
|
+
private_appdata: bool = False,
|
101
|
+
exit: bool = False,
|
102
|
+
features: str = None,
|
103
|
+
):
|
104
|
+
if project_file and input_script:
|
105
|
+
raise Exception("Cannot open a project file *and* run a script.")
|
106
|
+
|
107
|
+
if (not graphical) and project_file:
|
108
|
+
raise Exception("Cannot open a project file in batch mode.")
|
109
|
+
|
110
|
+
if port:
|
111
|
+
if project_file:
|
112
|
+
raise Exception("Cannot open in server mode with a project file.")
|
113
|
+
if input_script:
|
114
|
+
raise Exception("Cannot open in server mode with an input script.")
|
115
|
+
|
116
|
+
if not input_script and script_args:
|
117
|
+
raise Exception("Cannot add script arguments without an input script.")
|
118
|
+
|
119
|
+
if script_args:
|
120
|
+
if '"' in script_args:
|
121
|
+
raise Exception(
|
122
|
+
"Cannot have double quotes around individual arguments in the --script-args string."
|
123
|
+
)
|
124
|
+
|
125
|
+
# If the input_script and port are missing in batch mode, raise an exception
|
126
|
+
if (not graphical) and (input_script is None) and (not port):
|
127
|
+
raise Exception("An input script, -i, or port, --port, are required in batch mode.")
|
128
|
+
|
129
|
+
args = [exe, "-DSApplet"]
|
130
|
+
if (not graphical) or (not show_welcome_screen):
|
131
|
+
args.append("-AppModeMech")
|
132
|
+
|
133
|
+
if version < 232:
|
134
|
+
args.append("-nosplash")
|
135
|
+
args.append("-notabctrl")
|
136
|
+
|
137
|
+
if not graphical:
|
138
|
+
args.append("-b")
|
139
|
+
|
140
|
+
env: typing.Dict[str, str] = os.environ.copy()
|
141
|
+
if debug:
|
142
|
+
env["WBDEBUG_STOP"] = "1"
|
143
|
+
|
144
|
+
if port:
|
145
|
+
args.append("-grpc")
|
146
|
+
args.append(str(port))
|
147
|
+
|
148
|
+
if project_file:
|
149
|
+
args.append("-file")
|
150
|
+
args.append(project_file)
|
151
|
+
|
152
|
+
if input_script:
|
153
|
+
args.append("-script")
|
154
|
+
args.append(input_script)
|
155
|
+
|
156
|
+
if script_args:
|
157
|
+
args.append("-ScriptArgs")
|
158
|
+
args.append(f'"{script_args}"')
|
159
|
+
|
160
|
+
if (not graphical) and input_script:
|
161
|
+
exit = True
|
162
|
+
if version < 241:
|
163
|
+
warnings.warn(
|
164
|
+
"Please ensure ExtAPI.Application.Close() is at the end of your script. "
|
165
|
+
"Without this command, Batch mode will not terminate.",
|
166
|
+
stacklevel=2,
|
167
|
+
)
|
168
|
+
|
169
|
+
if exit and input_script and version >= 241:
|
170
|
+
args.append("-x")
|
171
|
+
|
172
|
+
profile: UniqueUserProfile = None
|
173
|
+
if private_appdata:
|
174
|
+
new_profile_name = f"Mechanical-{os.getpid()}"
|
175
|
+
profile = UniqueUserProfile(new_profile_name, dry_run=DRY_RUN)
|
176
|
+
profile.update_environment(env)
|
177
|
+
|
178
|
+
if not DRY_RUN:
|
179
|
+
version_name = atp.SUPPORTED_ANSYS_VERSIONS[version]
|
180
|
+
if graphical:
|
181
|
+
mode = "Graphical"
|
182
|
+
else:
|
183
|
+
mode = "Batch"
|
184
|
+
print(f"Starting Ansys Mechanical version {version_name} in {mode} mode...")
|
185
|
+
if port:
|
186
|
+
# TODO - Mechanical doesn't write anything to the stdout in grpc mode
|
187
|
+
# when logging is off.. Ideally we let Mechanical write it, so
|
188
|
+
# the user only sees the message when the server is ready.
|
189
|
+
print(f"Serving on port {port}")
|
190
|
+
|
191
|
+
if features is not None:
|
192
|
+
args.extend(get_command_line_arguments(features.split(";")))
|
193
|
+
|
194
|
+
if DRY_RUN:
|
195
|
+
return args, env
|
196
|
+
else:
|
197
|
+
_run(args, env, False, True)
|
198
|
+
|
199
|
+
if private_appdata:
|
200
|
+
profile.cleanup()
|
201
|
+
|
202
|
+
|
203
|
+
@click.command()
|
204
|
+
@click.help_option("--help", "-h")
|
205
|
+
@click.option(
|
206
|
+
"-p",
|
207
|
+
"--project-file",
|
208
|
+
default=None,
|
209
|
+
help="Opens Mechanical project file (.mechdb). Cannot be mixed with -i",
|
210
|
+
)
|
211
|
+
@click.option(
|
212
|
+
"--private-appdata",
|
213
|
+
default=None,
|
214
|
+
is_flag=True,
|
215
|
+
help="Make the appdata folder private.\
|
216
|
+
This enables you to run parallel instances of Mechanical.",
|
217
|
+
)
|
218
|
+
@click.option(
|
219
|
+
"--port",
|
220
|
+
type=int,
|
221
|
+
help="Start mechanical in server mode with the given port number",
|
222
|
+
)
|
223
|
+
@click.option(
|
224
|
+
"--features",
|
225
|
+
type=str,
|
226
|
+
default=None,
|
227
|
+
help=f"Beta feature flags to set, as a semicolon delimited list.\
|
228
|
+
Options: {get_feature_flag_names()}",
|
229
|
+
)
|
230
|
+
@click.option(
|
231
|
+
"-i",
|
232
|
+
"--input-script",
|
233
|
+
default=None,
|
234
|
+
help="Name of the input Python script. Cannot be mixed with -p",
|
235
|
+
)
|
236
|
+
@click.option(
|
237
|
+
"--script-args",
|
238
|
+
default=None,
|
239
|
+
help='Arguments to pass into the --input-script, -i. \
|
240
|
+
Write the arguments as a string, with each argument \
|
241
|
+
separated by a comma. For example, --script-args "arg1,arg2" \
|
242
|
+
This can only be used with the --input-script argument.',
|
243
|
+
)
|
244
|
+
@click.option(
|
245
|
+
"--exit",
|
246
|
+
is_flag=True,
|
247
|
+
default=None,
|
248
|
+
help="Exit the application after running an input script. \
|
249
|
+
You can only use this command with --input-script argument (-i). \
|
250
|
+
The command defaults to true you are not running the application in graphical mode. \
|
251
|
+
The ``exit`` command is only supported in version 2024 R1 or later.",
|
252
|
+
)
|
253
|
+
@click.option(
|
254
|
+
"-s",
|
255
|
+
"--show-welcome-screen",
|
256
|
+
is_flag=True,
|
257
|
+
default=False,
|
258
|
+
help="Show the welcome screen, where you can select the file to open.\
|
259
|
+
Only affects graphical mode",
|
260
|
+
)
|
261
|
+
@click.option(
|
262
|
+
"--debug",
|
263
|
+
is_flag=True,
|
264
|
+
default=False,
|
265
|
+
help="Show a debug dialog right when the process starts.",
|
266
|
+
)
|
267
|
+
@click.option(
|
268
|
+
"-r",
|
269
|
+
"--revision",
|
270
|
+
default=None,
|
271
|
+
type=int,
|
272
|
+
help='Ansys Revision number, e.g. "251" or "242". If none is specified\
|
273
|
+
, uses the default from ansys-tools-path',
|
274
|
+
)
|
275
|
+
@click.option(
|
276
|
+
"-g",
|
277
|
+
"--graphical",
|
278
|
+
is_flag=True,
|
279
|
+
default=False,
|
280
|
+
help="Graphical mode",
|
281
|
+
)
|
282
|
+
def cli(
|
283
|
+
project_file: str,
|
284
|
+
port: int,
|
285
|
+
debug: bool,
|
286
|
+
input_script: str,
|
287
|
+
script_args: str,
|
288
|
+
revision: int,
|
289
|
+
graphical: bool,
|
290
|
+
show_welcome_screen: bool,
|
291
|
+
private_appdata: bool,
|
292
|
+
exit: bool,
|
293
|
+
features: str,
|
294
|
+
):
|
295
|
+
"""CLI tool to run mechanical.
|
296
|
+
|
297
|
+
USAGE:
|
298
|
+
|
299
|
+
The following example demonstrates the main use of this tool:
|
300
|
+
|
301
|
+
$ ansys-mechanical -r 251 -g
|
302
|
+
|
303
|
+
Starting Ansys Mechanical version 2025R1 in graphical mode...
|
304
|
+
"""
|
305
|
+
exe = atp.get_mechanical_path(allow_input=False, version=revision)
|
306
|
+
version = atp.version_from_path("mechanical", exe)
|
307
|
+
|
308
|
+
return _cli_impl(
|
309
|
+
project_file,
|
310
|
+
port,
|
311
|
+
debug,
|
312
|
+
input_script,
|
313
|
+
script_args,
|
314
|
+
exe,
|
315
|
+
version,
|
316
|
+
graphical,
|
317
|
+
show_welcome_screen,
|
318
|
+
private_appdata,
|
319
|
+
exit,
|
320
|
+
features,
|
321
|
+
)
|