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.
@@ -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
+ )