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

feat: First tentative for Plugin Mapdl Mechanism python API #3627

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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/3627.miscellaneous.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
feat: First tentative for Plugin Mapdl Mechanism python API
3 changes: 3 additions & 0 deletions src/ansys/mapdl/core/mapdl_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
from ansys.mapdl.core.parameters import Parameters
from ansys.mapdl.core.solution import Solution
from ansys.mapdl.core.xpl import ansXpl
from ansys.mapdl.core.plugin import ansPlugin

from ansys.mapdl.core.post import PostProcessing

Expand Down Expand Up @@ -321,6 +322,8 @@ def __init__(

self._xpl: Optional[ansXpl] = None # Initialized in mapdl_grpc

self._plugin: Optional[ansPlugin] = None # Initialized in mapdl_grpc

from ansys.mapdl.core.component import ComponentManager

self._componentmanager: ComponentManager = ComponentManager(self)
Expand Down
21 changes: 21 additions & 0 deletions src/ansys/mapdl/core/mapdl_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
from ansys.platform.instancemanagement import Instance as PIM_Instance

from ansys.mapdl.core.database import MapdlDb
from ansys.mapdl.core.plugin import ansPlugin
from ansys.mapdl.core.xpl import ansXpl

TMP_VAR = "__tmpvar__"
Expand Down Expand Up @@ -2799,6 +2800,26 @@
self._xpl = ansXpl(self)
return self._xpl

@property
def plugin(self) -> "ansPlugin":
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def plugin(self) -> "ansPlugin":
def plugin(self) -> ansPlugin:

"""MAPDL plugin handler

Plugin Manager for MAPDL

Examples
--------

>>> from ansys import Mapdl
>>> mapdl = Mapdl()
>>> plugin = mapdl.plugin
>>> plugin.load('PluginDPF')
"""
if self._plugin is None:
from ansys.mapdl.core.plugin import ansPlugin

Check warning on line 2818 in src/ansys/mapdl/core/mapdl_grpc.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/mapdl_grpc.py#L2817-L2818

Added lines #L2817 - L2818 were not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from ansys.mapdl.core.plugin import ansPlugin

It seems to me there is no reason to delay the import. You can delete this line and then apply my previous comment (remove quotes).

Or delete the import at the beginning and leave these lines as it is.


self._plugin = ansPlugin(self)
return self._plugin

Check warning on line 2821 in src/ansys/mapdl/core/mapdl_grpc.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/mapdl_grpc.py#L2820-L2821

Added lines #L2820 - L2821 were not covered by tests

@protect_grpc
def scalar_param(self, pname: str) -> float:
"""Return a scalar parameter as a float.
Expand Down
141 changes: 141 additions & 0 deletions src/ansys/mapdl/core/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Copyright (C) 2016 - 2025 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""Contains the ansPlugin class."""
import json
import pathlib
import weakref

Check warning on line 26 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L24-L26

Added lines #L24 - L26 were not covered by tests

from ansys.api.mapdl.v0 import mapdl_pb2

Check warning on line 28 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L28

Added line #L28 was not covered by tests

from .common_grpc import ANSYS_VALUE_TYPE
from .errors import MapdlRuntimeError
from .misc import random_string

Check warning on line 32 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L30-L32

Added lines #L30 - L32 were not covered by tests
Comment on lines +30 to +32
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rather use absolute import paths:

Suggested change
from .common_grpc import ANSYS_VALUE_TYPE
from .errors import MapdlRuntimeError
from .misc import random_string
from ansys.mapdl.core.common_grpc import ANSYS_VALUE_TYPE
from ansys.mapdl.core.errors import MapdlRuntimeError
from ansys.mapdl.core.misc import random_string



class ansPlugin:

Check warning on line 35 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L35

Added line #L35 was not covered by tests
"""
ANSYS MAPDL Plugin Manager.

Examples
--------
>>> from ansys.mapdl.core import launch_mapdl
>>> mapdl = launch_mapdl()
>>> plugin = mapdl.plugin

Load a plugin in the MAPDL Session
"""

def __init__(self, mapdl):

Check warning on line 48 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L48

Added line #L48 was not covered by tests
"""Initialize the class."""
from ansys.mapdl.core.mapdl_grpc import MapdlGrpc

Check warning on line 50 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L50

Added line #L50 was not covered by tests

if not isinstance(mapdl, MapdlGrpc): # pragma: no cover
raise TypeError("Must be initialized using MapdlGrpc class")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise TypeError("Must be initialized using MapdlGrpc class")
raise TypeError("Must be initialized using an 'MapdlGrpc' object")


self._mapdl_weakref = weakref.ref(mapdl)
self._filename = None
self._open = False

Check warning on line 57 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L55-L57

Added lines #L55 - L57 were not covered by tests

@property
def _mapdl(self):

Check warning on line 60 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L59-L60

Added lines #L59 - L60 were not covered by tests
"""Return the weakly referenced instance of mapdl."""
return self._mapdl_weakref()

Check warning on line 62 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L62

Added line #L62 was not covered by tests

def load(self, plugin_name: str, feature: str = "CMD") -> str:

Check warning on line 64 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L64

Added line #L64 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the default feature is "CMD"?

"""
Loads a plugin into MAPDL.

Parameters
----------
plugin_name : str
Name of the plugin to load.
feature : str
Feature or module to activate in the plugin.

Returns
-------
str
Confirmation message about the loaded plugin.

Raises
------
PluginLoadError
If the plugin fails to load.
Comment on lines +70 to +83
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, I prefer only one tab.

Suggested change
plugin_name : str
Name of the plugin to load.
feature : str
Feature or module to activate in the plugin.
Returns
-------
str
Confirmation message about the loaded plugin.
Raises
------
PluginLoadError
If the plugin fails to load.
plugin_name : str
Name of the plugin to load.
feature : str
Feature or module to activate in the plugin.
Returns
-------
str
Confirmation message about the loaded plugin.
Raises
------
PluginLoadError
If the plugin fails to load.

"""

command = f"*PLUG,LOAD,{plugin_name},{feature}"
response = self._mapdl.run(command)
if "error" in response.lower():
raise PluginLoadError(

Check warning on line 89 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L86-L89

Added lines #L86 - L89 were not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should create this type of exception in ansys.mapdl.core.errors, ideally inheritate from MapdlException or MapdlRuntimeError.

f"Failed to load plugin '{plugin_name}' with feature '{feature}'."
)
return f"Plugin '{plugin_name}' with feature '{feature}' loaded successfully."

Check warning on line 92 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L92

Added line #L92 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you not returned the original MAPDL response response?


def unload(self, plugin_name: str) -> str:

Check warning on line 94 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L94

Added line #L94 was not covered by tests
"""
Unloads a plugin from MAPDL.

Parameters
----------
plugin_name : str
Name of the plugin to unload.

Returns
-------
str
Confirmation message about the unloaded plugin.

Raises
------
PluginUnloadError
If the plugin fails to unload.
"""

command = f"*PLUG,UNLOAD,{plugin_name}"
response = self._mapdl.run(command)
if "error" in response.lower():
raise PluginUnloadError(f"Failed to unload plugin '{plugin_name}'.")
return f"Plugin '{plugin_name}' unloaded successfully."

Check warning on line 118 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L114-L118

Added lines #L114 - L118 were not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same. Why not default MAPDL response?


def list(self) -> list:

Check warning on line 120 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L120

Added line #L120 was not covered by tests
"""
Lists all currently loaded plugins in MAPDL.

Returns
-------
list
A list of loaded plugin names.

Raises
------
RuntimeError
If the plugin list cannot be retrieved.
"""

command = "*PLUG,LIST"
response = self._mapdl.run(command)
if "error" in response.lower():
raise RuntimeError("Failed to retrieve the list of loaded plugins.")

Check warning on line 138 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L135-L138

Added lines #L135 - L138 were not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise RuntimeError("Failed to retrieve the list of loaded plugins.")
from ansys.mapdl.core.errors import MapdlRuntimeError
raise MapdlRuntimeError("Failed to retrieve the list of loaded plugins.")

# Parse response and extract plugin names (assuming response is newline-separated text)
plugins = [line.strip() for line in response.splitlines() if line.strip()]
return plugins

Check warning on line 141 in src/ansys/mapdl/core/plugin.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/mapdl/core/plugin.py#L140-L141

Added lines #L140 - L141 were not covered by tests
Loading