Skip to content

Commit 46e8aa6

Browse files
feat: Migrate report tool
1 parent f3de8be commit 46e8aa6

File tree

7 files changed

+534
-3
lines changed

7 files changed

+534
-3
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
(?i)Ansys
2-
pytest
2+
pytest
3+
ANS

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ classifiers = [
2525
dependencies = [
2626
"platformdirs>=3.6.0",
2727
"click>=8.1.3", # for CLI interface
28+
"scooby>=0.5.12",
2829
]
2930

3031
[project.optional-dependencies]

src/ansys/tools/common/path/applications/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class ApplicationPlugin:
3434
"""Class for application plugins."""
3535

3636
def is_valid_executable_path(self, exe_loc: str) -> bool:
37-
r"""Check if the executable path is valid for the application.
37+
"""Check if the executable path is valid for the application.
3838
3939
Parameters
4040
----------

src/ansys/tools/common/path/path.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def _get_default_windows_base_path() -> Optional[str]: # pragma: no cover
189189

190190

191191
def _is_float(input_string: str) -> bool:
192-
r"""Return true when a string can be converted to a float.
192+
"""Return true when a string can be converted to a float.
193193
194194
Parameters
195195
----------
File renamed without changes.

src/ansys/tools/common/report.py

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
# Copyright (C) 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+
"""
24+
PyAnsys Tools Report.
25+
26+
Module containing the standardized Report class for PyAnsys projects.
27+
"""
28+
29+
import os
30+
import sys
31+
32+
import scooby
33+
34+
__ANSYS_VARS_PREFIX__ = (
35+
"AWP",
36+
"ACP",
37+
"ANS",
38+
"FLUENT",
39+
"MAPDL",
40+
"DPF",
41+
"SIMPLORER",
42+
"SIWAVE",
43+
"CADOE",
44+
)
45+
46+
__PYANSYS_LIBS__ = (
47+
"ansys_sphinx_theme",
48+
"ansys.acp.core",
49+
"ansys.dpf.composites",
50+
"ansys.dpf.core",
51+
"ansys.dpf.post",
52+
"ansys.fluent.core",
53+
"ansys.fluent.visualization",
54+
"ansys.fluent.parametric",
55+
"ansys.geometry.core",
56+
"ansys.hps.client",
57+
"ansys.mapdl.core",
58+
"ansys.mapdl.reader",
59+
"ansys.math.core",
60+
"ansys.mechanical.core",
61+
"ansys.meshing.prime",
62+
"ansys.modelcenter.workflow",
63+
"ansys.motorcad.core",
64+
"ansys.openapi.common",
65+
"ansys.optislang.core",
66+
"ansys.platform.instancemanagement",
67+
"ansys.pyensight.core",
68+
"ansys.rocky.core",
69+
"ansys.seascape",
70+
"ansys.simai.core",
71+
"ansys.systemcoupling.core",
72+
"ansys.turbogrid.core",
73+
"ansys.tools.report",
74+
"ansys.tools.versioning",
75+
"pyaedt",
76+
"pyedb",
77+
"pygranta",
78+
"pytwin",
79+
)
80+
81+
82+
class Report(scooby.Report):
83+
"""Generate a :class:`scooby.Report` instance.
84+
85+
Parameters
86+
----------
87+
additional : list(ModuleType), list(str), optional
88+
List of packages or package names to add to output information.
89+
Defaults to ``None``.
90+
ncol : int, optional
91+
Number of package-columns in html table; only has effect if
92+
``mode='HTML'`` or ``mode='html'``. Defaults to 3.
93+
text_width : int, optional
94+
The text width for non-HTML display modes. Defaults to 80.
95+
sort : bool, optional
96+
Alphabetically sort the packages. Defaults to ``False``.
97+
gpu : bool, optional
98+
Gather information about the GPU. Defaults to ``True`` but if
99+
experiencing rendering issues, pass ``False`` to safely generate
100+
a report.
101+
ansys_vars : list of str, optional
102+
List containing the Ansys environment variables to be reported.
103+
(e.g. ["MYVAR_1", "MYVAR_2" ...]). Defaults to ``None``.
104+
ansys_libs : dict {str : str}, optional
105+
Dictionary containing the Ansys libraries and versions to be reported.
106+
(e.g. {"MyLib" : "v1.2", ...}). Defaults to ``None``.
107+
"""
108+
109+
def __init__(
110+
self,
111+
additional=None,
112+
ncol=3,
113+
text_width=80,
114+
sort=False,
115+
gpu=True,
116+
ansys_vars=None,
117+
ansys_libs=None,
118+
):
119+
"""Report class constructor."""
120+
# Mandatory packages
121+
core = [
122+
"appdirs",
123+
"google.protobuf", # protobuf library
124+
"grpc", # grpcio
125+
"matplotlib",
126+
"numpy",
127+
"pyiges",
128+
"pyvista",
129+
"scipy",
130+
"tqdm",
131+
]
132+
133+
if os.name == "posix":
134+
core.extend(["pexpect"])
135+
136+
# Optional packages
137+
optional = ["matplotlib"]
138+
if sys.version_info[1] < 9:
139+
optional.append("ansys_corba")
140+
141+
# PyAnsys packages + additional ones
142+
if additional:
143+
additional.extend(__PYANSYS_LIBS__)
144+
else:
145+
additional = __PYANSYS_LIBS__
146+
147+
# Information about the GPU - bare except in case there is a rendering
148+
# bug that the user is trying to report.
149+
if gpu:
150+
try:
151+
try:
152+
from pyvista.report import GPUInfo
153+
except ImportError:
154+
from pyvista.utilities.errors import GPUInfo # deprecated in PyVista 0.40
155+
156+
extra_meta = [(t[0], t[1]) for t in GPUInfo().get_info()]
157+
except Exception:
158+
extra_meta = ("GPU Details", "error")
159+
else:
160+
extra_meta = ("GPU Details", "None")
161+
162+
# Store the ANSYS vars and libs
163+
self._ansys_vars = ansys_vars
164+
self._ansys_libs = ansys_libs
165+
166+
scooby.Report.__init__(
167+
self,
168+
additional=additional,
169+
core=core,
170+
optional=optional,
171+
ncol=ncol,
172+
text_width=text_width,
173+
sort=sort,
174+
extra_meta=extra_meta,
175+
)
176+
177+
def project_info(self):
178+
"""Return information regarding the Ansys environment and installation.
179+
180+
Returns
181+
-------
182+
str
183+
The project information (env variables and installation)
184+
"""
185+
# List installed Ansys
186+
lines = ["", "Ansys Environment Report", "-" * 79, "\n"]
187+
lines.append("\n".join(["Ansys Installation", "******************"]))
188+
if not self._ansys_libs:
189+
lines.append("No Ansys installations provided")
190+
else:
191+
lines.append("Version Location")
192+
lines.append("------------------")
193+
for key in sorted(self._ansys_libs.keys()):
194+
lines.append(f"{key} {self._ansys_libs[key]}")
195+
install_info = "\n".join(lines)
196+
197+
env_info_lines = [
198+
"\n\n\nAnsys Environment Variables",
199+
"***************************",
200+
]
201+
n_var = 0
202+
if self._ansys_vars is not None:
203+
for key, value in os.environ.items():
204+
if key in self._ansys_vars:
205+
env_info_lines.append(f"{key:<30} {value}")
206+
n_var += 1
207+
208+
# Loop over all environment variables
209+
for key, value in os.environ.items():
210+
# Now, check if it is an Ansys default variable
211+
if self._is_ansys_var(key):
212+
# If found, check if it is already available or not
213+
if (self._ansys_vars is None) or (key not in self._ansys_vars):
214+
env_info_lines.append(f"{key:<30} {value}")
215+
n_var += 1
216+
217+
# Finally, if no env vars were found, just append None
218+
if not n_var:
219+
env_info_lines.append("None")
220+
env_info = "\n".join(env_info_lines)
221+
222+
return install_info + env_info
223+
224+
def _is_ansys_var(self, env_var):
225+
"""
226+
Determine if an env. variable belongs to the set of ANSYS default env. variables.
227+
228+
Parameters
229+
----------
230+
env_var : str
231+
The environment variable to be evaluated.
232+
233+
Returns
234+
-------
235+
bool
236+
``True`` when successful, ``False`` when failed.
237+
"""
238+
# Loop over the Ansys default variables prefixes
239+
for prefix in __ANSYS_VARS_PREFIX__:
240+
# Check if the "prefix" substring is found
241+
if env_var.startswith(prefix):
242+
return True
243+
244+
def __repr__(self):
245+
"""Print out the report.
246+
247+
Returns
248+
-------
249+
str
250+
Report statement.
251+
"""
252+
add_text = "-" * 79 + "\nPyAnsys Software and Environment Report"
253+
254+
report = add_text + super().__repr__() + self.project_info()
255+
return report.replace("-" * 80, "-" * 79) # hotfix for scooby

0 commit comments

Comments
 (0)