-
Notifications
You must be signed in to change notification settings - Fork 24
FEAT: Add license_manager #1118
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
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
e2ddca9
add license_manager
dipinknair cdabb70
chore: adding changelog file 1118.added.md [dependabot-skip]
pyansys-ci-bot 1278c28
Merge branch 'main' into feat/license
dipinknair 28626fc
warning instead of error
dipinknair 0ce00b7
Merge branch 'feat/license' of https://github.com/ansys/pymechanical …
dipinknair 93a2f94
Merge branch 'main' into feat/license
dipinknair ad59877
chore: adding changelog file 1118.added.md [dependabot-skip]
pyansys-ci-bot 7416c35
Merge branch 'main' into feat/license
dipinknair 334bb08
restore
dipinknair 34ff963
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] b759aa9
update version condition
dipinknair 432780b
Merge branch 'feat/license' of https://github.com/ansys/pymechanical …
dipinknair f2805c6
Merge branch 'main' into feat/license
dipinknair bcb7988
update api name
dipinknair 6228b93
Merge branch 'feat/license' of https://github.com/ansys/pymechanical …
dipinknair 3fbd8b7
remove test.py
dipinknair 34c157d
fix reimport
dipinknair b7ed17a
test to see what all license available
dipinknair 14e5558
add docstring
dipinknair b2fa716
fix style
dipinknair 35bd07b
show licenses
dipinknair f897e77
add tests
dipinknair 5ca3e1a
restore test_app
dipinknair File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add license_manager |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
# Copyright (C) 2022 - 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. | ||
|
||
"""License Manager.""" | ||
from typing import List, Optional, Union | ||
|
||
from ansys.mechanical.core import LOG | ||
|
||
|
||
class LicenseManager: | ||
"""Class to manage licenses in Ansys Mechanical. | ||
|
||
This class provides methods to enable, disable, and check the status of licenses. | ||
It also allows for moving licenses to specific indices in the license preference list. | ||
It is initialized with an instance of the Ansys Mechanical application. | ||
""" | ||
|
||
def __init__(self, app): | ||
"""Initialize the message manager.""" | ||
self._app = app | ||
self._license_preference = self._app.ExtAPI.Application.LicensePreference | ||
import Ansys | ||
|
||
self._license_status = Ansys.Mechanical.DataModel.Enums.LicenseStatus | ||
|
||
def get_all_licenses(self) -> list[str]: | ||
"""Return list of all licenses.""" | ||
return self._license_preference.GetAllLicenses() | ||
|
||
def get_license_status( | ||
self, license_name: str | ||
) -> "Ansys.Mechanical.DataModel.Enums.LicenseStatus": | ||
"""Return status of the specific license. | ||
|
||
Parameters | ||
---------- | ||
license_name : str | ||
Name of the license to check. | ||
|
||
Returns | ||
------- | ||
"Ansys.Mechanical.DataModel.Enums.LicenseStatus" | ||
The status of the license. | ||
""" | ||
LOG.info( | ||
f"{license_name} status: {self._license_preference.GetLicenseStatus(license_name)}" | ||
) | ||
return self._license_preference.GetLicenseStatus(license_name) | ||
|
||
def set_license_status(self, license_name: str, status: bool) -> None: | ||
"""Set the status of a license and save the preference. | ||
|
||
Parameters | ||
---------- | ||
license_name : str | ||
Name of the license to set the status for. | ||
status : bool | ||
True to enable the license, False to disable it. | ||
""" | ||
if status: | ||
self._license_preference.SetLicenseStatus(license_name, self._license_status.Enabled) | ||
LOG.info(f"{license_name} is enabled.") | ||
else: | ||
self._license_preference.SetLicenseStatus(license_name, self._license_status.Disabled) | ||
LOG.info(f"{license_name} is disabled.") | ||
self._license_preference.Save() | ||
|
||
def show(self) -> None: | ||
"""Print all active licenses.""" | ||
for lic in self.get_all_licenses(): | ||
print(f"{lic} - {self._license_preference.GetLicenseStatus(lic)}") | ||
|
||
def disable_session_license(self) -> None: | ||
"""Disable all licenses for current session.""" | ||
self._license_preference.DeActivateLicense() | ||
|
||
def enable_session_license(self, license: Optional[Union[str, List[str]]] = None) -> None: | ||
"""Enable license(s) for the current session. | ||
|
||
Parameters | ||
---------- | ||
license : Optional[Union[str, List[str]]], optional | ||
If None, activates the first enabled license in the priority order. | ||
If a string, activates that specific license. | ||
If a list of strings, activates all specified licenses in the order provided. | ||
""" | ||
from System import String | ||
from System.Collections.Generic import List as DotNetList | ||
|
||
if license is None: | ||
self._license_preference.ActivateLicense() | ||
elif isinstance(license, str): | ||
self._license_preference.ActivateLicense(String(license)) | ||
elif isinstance(license, list): | ||
licenses = DotNetList[String]() | ||
for lic in license: | ||
licenses.Add(String(lic)) | ||
self._license_preference.ActivateLicense(licenses) | ||
else: | ||
raise TypeError("License must be None, a string, or a list of strings.") | ||
LOG.info(f"License(s) {license} enabled for the current session.") | ||
|
||
def move_to_index(self, license_name: str, location: int) -> None: | ||
"""Move a license preference. | ||
|
||
Move license to zero-based index location in the license preference list. | ||
This is useful for setting the preferred license location. | ||
|
||
Parameters | ||
---------- | ||
license_name : str | ||
License name. | ||
location : int | ||
Location to move the license to. | ||
dipinknair marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Examples | ||
-------- | ||
Move Ansys Mechanical Premium to the first location. | ||
|
||
>>> license_manager = LicenseManager(app) | ||
>>> license_manager.move_to_index('Ansys Mechanical Premium', 0) | ||
""" | ||
LOG.info(f"Moving license preference for {license_name} to location {location}") | ||
self._license_preference.MoveLicenseToLocation(license_name, location) | ||
self._license_preference.Save() | ||
|
||
def reset_preference(self) -> None: | ||
"""Reset the license preference. | ||
|
||
This method will reset the license location order and the status of all licenses | ||
to the default state. | ||
""" | ||
LOG.info("Resetting license preferences to default state.") | ||
self._license_preference.Reset() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Copyright (C) 2022 - 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. | ||
|
||
"""License manager test""" | ||
|
||
import pytest | ||
|
||
|
||
@pytest.mark.embedding | ||
def test_license_manager(embedded_app, capsys): | ||
"""Test message manager""" | ||
|
||
test_license = "Ansys Mechanical Premium" | ||
assert len(embedded_app.license_manager.get_all_licenses()) > 0 | ||
assert embedded_app.readonly is False, "App should be editable after enabling session license" | ||
all_licenses = embedded_app.license_manager.get_all_licenses() | ||
assert test_license in all_licenses, "Expected license not found in the list" | ||
|
||
# Enable and disable specific license | ||
status = embedded_app.license_manager.get_license_status(test_license) | ||
assert ( | ||
status == embedded_app.license_manager._license_status.Enabled | ||
), "License should be enabled" | ||
|
||
embedded_app.license_manager.set_license_status(test_license, False) | ||
status = embedded_app.license_manager.get_license_status(test_license) | ||
assert ( | ||
status == embedded_app.license_manager._license_status.Disabled | ||
), "License should be disabled" | ||
|
||
embedded_app.license_manager.set_license_status(test_license, True) | ||
status = embedded_app.license_manager.get_license_status(test_license) | ||
assert ( | ||
status == embedded_app.license_manager._license_status.Enabled | ||
), "License should be enabled" | ||
|
||
license_list = embedded_app.license_manager.get_all_licenses() | ||
assert license_list.index(test_license) == 1, "License should be at index 1" | ||
embedded_app.license_manager.move_to_index(test_license, 0) | ||
license_list = embedded_app.license_manager.get_all_licenses() | ||
assert license_list.index(test_license) == 0, "License should be at index 0" | ||
|
||
embedded_app.license_manager.reset_preference() | ||
license_list = embedded_app.license_manager.get_all_licenses() | ||
assert license_list.index(test_license) == 1, "License should be at index 1 after reset" | ||
|
||
# Enable session license with all cases | ||
embedded_app.license_manager.disable_session_license() | ||
assert embedded_app.readonly is True, "App should be readonly after disabling session license" | ||
embedded_app.license_manager.enable_session_license() | ||
embedded_app.license_manager.disable_session_license() | ||
embedded_app.license_manager.enable_session_license(test_license) | ||
assert embedded_app.readonly is False | ||
embedded_app.license_manager.disable_session_license() | ||
embedded_app.license_manager.enable_session_license( | ||
["Ansys Mechanical Enterprise", test_license] | ||
) | ||
assert embedded_app.readonly is False | ||
|
||
with pytest.raises(TypeError): | ||
embedded_app.license_manager.enable_session_license(1) | ||
|
||
embedded_app.license_manager.show() | ||
captured = capsys.readouterr() | ||
printed_output = captured.out.strip() | ||
assert "Enabled" in printed_output | ||
assert test_license in printed_output |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.