Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: externalise 'report' features to module #3511

Merged
merged 2 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changelog.d/3511.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
refactor: externalise the 'report' features to another file
3 changes: 2 additions & 1 deletion src/ansys/mapdl/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@

from ansys.mapdl.core.information import Information
from ansys.mapdl.core.mapdl_grpc import MapdlGrpc as Mapdl
from ansys.mapdl.core.misc import Report, _check_has_ansys
from ansys.mapdl.core.misc import _check_has_ansys
from ansys.mapdl.core.pool import MapdlPool
from ansys.mapdl.core.report import Report

###############################################################################
# Convenient imports
Expand Down
271 changes: 1 addition & 270 deletions src/ansys/mapdl/core/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,12 @@
import numpy as np

from ansys.mapdl import core as pymapdl
from ansys.mapdl.core import _HAS_ATP, _HAS_PYANSYS_REPORT, _HAS_PYVISTA, LOG

if _HAS_ATP:
from ansys.tools.path import get_available_ansys_installations

if _HAS_PYANSYS_REPORT:
import ansys.tools.report as pyansys_report

from ansys.mapdl.core import _HAS_PYVISTA, LOG

# path of this module
MODULE_PATH = os.path.dirname(inspect.getfile(inspect.currentframe()))


ANSYS_ENV_VARS = [
"PYMAPDL_START_INSTANCE",
"PYMAPDL_PORT",
"PYMAPDL_IP",
"PYMAPDL_MAPDL_EXEC",
"PYMAPDL_MAPDL_VERSION",
"PYMAPDL_MAX_MESSAGE_LENGTH",
"ON_CI",
"ON_LOCAL",
"P_SCHEMA",
]


class ROUTINES(Enum):
"""MAPDL routines."""

Expand Down Expand Up @@ -117,255 +97,6 @@ def check_valid_routine(routine):
return True


class Plain_Report:
def __init__(self, core, optional=None, additional=None, **kwargs):
"""
Base class for a plain report.


Based on `scooby <https://github.com/banesullivan/scooby>`_ package.

Parameters
----------
additional : iter[str]
List of packages or package names to add to output information.
core : iter[str]
The core packages to list first.
optional : iter[str]
A list of packages to list if they are available. If not available,
no warnings or error will be thrown.
"""

self.additional = additional
self.core = core
self.optional = optional
self.kwargs = kwargs

if os.name == "posix":
self.core.extend(["pexpect"])

# Information about the GPU - bare except in case there is a rendering
# bug that the user is trying to report.
if self.kwargs.get("gpu", False) and _HAS_PYVISTA:
from pyvista import PyVistaDeprecationWarning

try:
from pyvista.utilities.errors import (
GPUInfo, # deprecated in pyvista 0.40.0
)
except (PyVistaDeprecationWarning, ImportError):
from pyvista.report import GPUInfo

try:
self.kwargs["extra_meta"] = [(t[1], t[0]) for t in GPUInfo().get_info()]
except RuntimeError as e: # pragma: no cover
self.kwargs["extra_meta"] = ("GPU Details", f"Error: {str(e)}")
else:
self.kwargs["extra_meta"] = ("GPU Details", "None")

def get_version(self, package):
try:
import importlib.metadata as importlib_metadata
except ModuleNotFoundError: # pragma: no cover
import importlib_metadata

try:
return importlib_metadata.version(package.replace(".", "-"))
except importlib_metadata.PackageNotFoundError:
return "Package not found"

def __repr__(self):
header = [
"-" * 79,
"\n",
"PyMAPDL Software and Environment Report",
"\n",
"Packages Requirements",
"*********************",
]

core = ["\nCore packages", "-------------"]
core.extend(
[
f"{each.ljust(20)}: {self.get_version(each)}"
for each in self.core
if self.get_version(each)
]
)

if self.optional:
optional = ["\nOptional packages", "-----------------"]
optional.extend(
[
f"{each.ljust(20)}: {self.get_version(each)}"
for each in self.optional
if self.get_version(each)
]
)
else:
optional = [""]

if self.additional:
additional = ["\nAdditional packages", "-----------------"]
additional.extend(
[
f"{each.ljust(20)}: {self.get_version(each)}"
for each in self.additional
if self.get_version(each)
]
)
else:
additional = [""]

return "\n".join(header + core + optional + additional) + self.mapdl_info()

def mapdl_info(self):
"""Return information regarding the ansys environment and installation."""
# this is here to avoid circular imports

# List installed Ansys
lines = ["", "Ansys Environment Report", "-" * 79]
lines = ["\n", "Ansys Installation", "******************"]
if _HAS_ATP:
mapdl_install = get_available_ansys_installations()

if not mapdl_install:
lines.append("Unable to locate any Ansys installations")
else:
lines.append("Version Location")
lines.append("------------------")
for key in sorted(mapdl_install.keys()):
lines.append(f"{abs(key)} {mapdl_install[key]}")
else:
mapdl_install = None
lines.append(
"Unable to locate any Ansys installations because 'ansys-tools-path is not installed."
)

install_info = "\n".join(lines)

env_info_lines = [
"\n\n\nAnsys Environment Variables",
"***************************",
]
n_var = 0
for key, value in os.environ.items():
if "AWP" in key or "CADOE" in key or "ANSYS" in key:
env_info_lines.append(f"{key:<30} {value}")
n_var += 1
if not n_var:
env_info_lines.append("None")
env_info = "\n".join(env_info_lines)

return install_info + env_info


# Determine which type of report will be used (depending on the
# available packages)
if _HAS_PYANSYS_REPORT:
base_report_class = pyansys_report.Report
else: # pragma: no cover
base_report_class = Plain_Report


class Report(base_report_class):
"""A class for custom scooby.Report."""

def __init__(
self,
additional=None,
ncol=3,
text_width=80,
sort=False,
gpu=True,
ansys_vars=ANSYS_ENV_VARS,
ansys_libs=None,
):
"""Generate a :class:`scooby.Report` instance.

Parameters
----------
additional : list(ModuleType), list(str)
List of packages or package names to add to output information.

ncol : int, optional
Number of package-columns in html table; only has effect if
``mode='HTML'`` or ``mode='html'``. Defaults to 3.

text_width : int, optional
The text width for non-HTML display modes

sort : bool, optional
Alphabetically sort the packages

gpu : bool
Gather information about the GPU. Defaults to ``True`` but if
experiencing rendering issues, pass ``False`` to safely generate
a report.

ansys_vars : list of str, optional
List containing the Ansys environment variables to be reported.
(e.g. ["MYVAR_1", "MYVAR_2" ...]). Defaults to ``None``. Only used for
the `pyansys-tools-report` package.

ansys_libs : dict {str : str}, optional
Dictionary containing the Ansys libraries and versions to be reported.
(e.g. {"MyLib" : "v1.2", ...}). Defaults to ``None``. Only used for
the `pyansys-tools-report` package.

"""
# Mandatory packages
core = [
"ansys.mapdl.core",
"numpy",
"platformdirs",
"scipy",
"grpc", # grpcio
"ansys.api.mapdl.v0", # ansys-api-mapdl-v0
"ansys.mapdl.reader", # ansys-mapdl-reader
"google.protobuf", # protobuf library
"ansys-math-core",
]

# Optional packages
optional = [
"matplotlib",
"pyvista",
"pyiges",
"tqdm",
"ansys-tools-visualization_interface",
"pandas",
]

if _HAS_PYANSYS_REPORT:
# Combine all packages into one
all_mapdl_packages = core + optional
if additional is not None:
all_mapdl_packages += additional

# Call the pyansys_report.Report constructor
super().__init__(
additional=all_mapdl_packages,
ncol=ncol,
text_width=text_width,
sort=sort,
gpu=gpu,
ansys_vars=ansys_vars,
ansys_libs=ansys_libs,
)
else:
# Call the PlainReport constructor
super().__init__(
additional=additional,
core=core,
optional=optional,
ncol=ncol,
text_width=text_width,
sort=sort,
gpu=gpu,
)


def is_float(input_string):
"""Returns true when a string can be converted to a float"""
try:
Expand Down
Loading
Loading