Skip to content

Commit

Permalink
Feat/Boundary conditions listing wrappers (#819)
Browse files Browse the repository at this point in the history
* Changed signal termination

* Adding CommandOutput class.

* Substituting the output in mapdl_grpc for custom class.

* Making sure all the methods call the parent class (str)

* Testing simplied version

* Added unit tests

* Added unit tests

* Fixing the style

* Fixing grammar.

* Fixing grammar.

* Merge branch 'feat/richer-command-output' of https://github.com/pyansys/pymapdl into feat/richer-command-output

* Add test_class unit

* Using first implementation because the second fail because of the modified `__getattribute_`

* Changing implementation to not overwrite __class__.

* Fixing sphinx building by rewriting __class__ method to not be overwriten.

* Style check.

* changing the API, cmd=command, and command= full command (cmd + args)

* Adding CommandOutputDataframe class.

* Small changes.

* Big restructure.

Now we detect the underlying data array based on a predefined magic word (start of data) and an empty line (end of data).

* Added check if output is modified by /verify

* Added docstrings to classes.

* Moved fixtures to main conf file

* Changed class name, added supported commands.

Added support to Elist and Nlist

* Added test units.

* Added more unit test.

* Fixing style.

* small changes.

* small change.

* incorrect package name.

* UserString Implementation

* Simplification of unit test.

* Simplification of unit test.

* Using str as base class.

* removed unused import.

* Generalization of 'CommandListing' based on function 'paprnt.F'.

* Apply suggestions from code review

Co-authored-by: Alex Kaszynski <[email protected]>

* Cleanning some commented code.

Removed @command_checker since we are opting for individual wrapping.

* Added automatical wrapper for listing functions.

* Removed automatical wrapper.

* Fixing style.

* changed method name to `to_list`

* Fixing style

* Added unit test.

* Fixing grammar.

* Added dlist wrapper

* Externalizing @requires_pandas

Added DLIST class

* Fixing conftest?

* Improving unit test to avoid empty object false assertion.

* Fixing unit test

* replacing solve for one which does not change format.

* checking format

* Fixing unit test mess

* testing disabling new test.

* removing unused imports

* removing unused imports

* test

* fixing wrong check against empty array and df

* Removed unused import

* Changing class name.

* Cleaning

* Cleaning again.

* Fixing style.

* Fixing style.

* Update ansys/mapdl/core/commands.py

Co-authored-by: Alex Kaszynski <[email protected]>

* Added output checker

* Adding suggestions.

* Fixing wrong wrapper.

* Improving test.

* Moving the wrapping to main Mapdl, being common to gpc, console and corba.

* Added docstring injector.

* Apply suggestions from code review

* Apply suggestions from code review

* Replacing the check of the pandas package.

Adding short doc string.

* importing pandas lazily

* removed trailing space.

* Added docstring injector to dlist and flist

* removing grpc wrapper

* Adding unit test for docstring injector.

* Added code suggestions.

Co-authored-by: Alex Kaszynski <[email protected]>
  • Loading branch information
germa89 and akaszynski authored Jan 11, 2022
1 parent 93b7881 commit 48f9bc8
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 10 deletions.
52 changes: 49 additions & 3 deletions ansys/mapdl/core/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,20 @@
pip install pandas
"""

MSG_BCListingOutput_to_array = """This command has strings values in some of its columns (such 'UX', 'FX', 'UY', 'TEMP', etc),
so it cannot be converted to Numpy Array.
Please use 'to_list' or 'to_dataframe' instead."""


# Identify where the data start in the output
GROUP_DATA_START = ['NODE', 'ELEM']

# Allowed commands to get output as array or dataframe.
# In theory, these commands should follow the same format.
# Some of them are not documented (already deprecated?)
# So they won't be wrapped.
# So they are not in the Mapdl class,
# so they won't be wrapped.
CMD_LISTING = [
'NLIN', # not documented
'PRCI',
Expand Down Expand Up @@ -66,6 +73,8 @@
'SWLI'
]

CMD_BC_LISTING = ['FLIS', 'DLIS']

# Adding empty lines to match current format.
docstring_injection = """
Returns
Expand Down Expand Up @@ -371,6 +380,16 @@ class Commands(

"""Wrapped MAPDL commands"""

def _requires_pandas(func):
"""Wrapper that check ``HAS_PANDAS``, if not, it will raise an exception."""

def func_wrapper(self, *args, **kwargs):
if HAS_PANDAS:
return func(self, *args, **kwargs)
else:
raise ModuleNotFoundError(MSG_NOT_PANDAS)
return func_wrapper


class CommandOutput(str):
"""Custom string subclass for handling the commands output.
Expand Down Expand Up @@ -556,7 +575,7 @@ def to_array(self):
"""
return np.array(self.to_list(), dtype=float)

def to_dataframe(self):
def to_dataframe(self, data=None, columns=None):
"""Export the command output as a Pandas DataFrame.
Returns
Expand All @@ -567,4 +586,31 @@ def to_dataframe(self):
import pandas as pd
except ModuleNotFoundError:
raise ModuleNotFoundError(MSG_NOT_PANDAS)
return pd.DataFrame(data=self.to_array(), columns=self.get_columns())

if not data:
data = self.to_array()
if not columns:
columns = self.get_columns()

return pd.DataFrame(data=data, columns=data)


class BoundaryConditionsListingOutput(CommandListingOutput):
def to_array(self):
raise ValueError(MSG_BCListingOutput_to_array)

def to_dataframe(self):
df = super().to_dataframe(data=self.to_list())
if 'NODE' in df.columns:
df['NODE'] = df['NODE'].astype(int)

if 'LABEL' in df.columns:
df['LABEL'] = df['LABEL'].astype(str)

if 'REAL' in df.columns:
df['REAL'] = df['REAL'].astype(float)

if 'IMAG' in df.columns:
df['IMAG'] = df['IMAG'].astype(float)

return df
14 changes: 13 additions & 1 deletion ansys/mapdl/core/mapdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from ansys.mapdl.core.errors import MapdlRuntimeError, MapdlInvalidRoutineError
from ansys.mapdl.core.plotting import general_plotter
from ansys.mapdl.core.post import PostProcessing
from ansys.mapdl.core.commands import Commands, CommandListingOutput, CMD_LISTING, inject_docs
from ansys.mapdl.core.commands import Commands, CommandListingOutput, BoundaryConditionsListingOutput, CMD_LISTING, CMD_BC_LISTING, inject_docs
from ansys.mapdl.core.inline_functions import Query
from ansys.mapdl.core import LOG as logger
from ansys.mapdl.reader.rst import Result
Expand Down Expand Up @@ -177,11 +177,23 @@ def inner_wrapper(*args, **kwargs):
return CommandListingOutput(func(*args, **kwargs))
return inner_wrapper

def wrap_BC_listing_function(func):
# Injecting doc string modification
func.__func__.__doc__ = inject_docs(func.__func__.__doc__)
@wraps(func)
def inner_wrapper(*args, **kwargs):
return BoundaryConditionsListingOutput(func(*args, **kwargs))
return inner_wrapper

for name in dir(self):
if name[0:4].upper() in CMD_LISTING:
func = self.__getattribute__(name)
setattr(self, name, wrap_listing_function(func))

if name[0:4].upper() in CMD_BC_LISTING:
func = self.__getattribute__(name)
setattr(self, name, wrap_BC_listing_function(func))

@property
def _name(self): # pragma: no cover
"""Implemented by child class"""
Expand Down
1 change: 0 additions & 1 deletion ansys/mapdl/core/mapdl_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
from ansys.mapdl.core import __version__, _LOCAL_PORTS
from ansys.mapdl.core import check_version


TMP_VAR = '__tmpvar__'
VOID_REQUEST = anskernel.EmptyRequest()

Expand Down
49 changes: 44 additions & 5 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import pytest
import inspect
from ansys.mapdl.core.commands import CommandOutput as CommandOutput

import numpy as np

from ansys.mapdl.core import examples

from ansys.mapdl.core.commands import CommandListingOutput
from ansys.mapdl.core.commands import CommandOutput
from ansys.mapdl.core.commands import CommandOutput, CommandListingOutput, BoundaryConditionsListingOutput
from ansys.mapdl.core.commands import CMD_LISTING, CMD_BC_LISTING

try:
import pandas as pd
Expand Down Expand Up @@ -60,6 +58,8 @@
'kcmplx': 1
}

CMD_DOC_STRING_INJECTOR = CMD_LISTING.copy()
CMD_DOC_STRING_INJECTOR.extend(CMD_BC_LISTING)

@pytest.fixture(scope="module")
def plastic_solve(mapdl):
Expand All @@ -72,6 +72,16 @@ def plastic_solve(mapdl):
mapdl.set(1, 2)
mapdl.mute = False

@pytest.fixture(scope="module")
def beam_solve(mapdl):
mapdl.mute = True
mapdl.finish()
mapdl.clear()
mapdl.input(examples.verif_files.vmfiles["vm10"])

mapdl.post1()
mapdl.set(1, 2)
mapdl.mute = False

def test_cmd_class():
output = """This is the output.
Expand Down Expand Up @@ -105,7 +115,6 @@ def test_inquire_functions(mapdl, func):
assert '=' in output


# @pytest.mark.skipif(not HAS_GRPC, reason="Requires GRPC")
@pytest.mark.parametrize('func,args', [
('prnsol', ('U', 'X')),
('presol', ('S', 'X')),
Expand All @@ -126,3 +135,33 @@ def test_output_listing(mapdl, plastic_solve, func, args):
if HAS_PANDAS:
out_df = out.to_dataframe()
assert isinstance(out_df, pd.DataFrame) and not out_df.empty


@pytest.mark.parametrize('func', ['dlist', 'flist'])
def test_bclist(mapdl, beam_solve, func):
func_ = getattr(mapdl, func)
out = func_()

assert isinstance(out, BoundaryConditionsListingOutput)
assert isinstance(out.to_list(), list) and bool(out.to_list())

with pytest.raises(ValueError):
out.to_array()

if HAS_PANDAS:
out_df = out.to_dataframe()
assert isinstance(out_df, pd.DataFrame) and not out_df.empty


@pytest.mark.parametrize('method', CMD_DOC_STRING_INJECTOR)
def test_docstring_injector(mapdl, method):
"""Check if the docstring has been injected."""
for name in dir(mapdl):
if name[0:4].upper() == method:
func = mapdl.__getattribute__(name)
docstring = func.__doc__ # If '__func__' not present (AttributeError) very likely it has not been wrapped.

assert "Returns" in docstring
assert "``str.to_list()``" in docstring
assert "``str.to_array()``" in docstring
assert "``str.to_dataframe()``" in docstring

0 comments on commit 48f9bc8

Please sign in to comment.