Contribute#
Overall guidance on contributing to a PyAnsys repository appears in Contribute in the PyAnsys Developer’s Guide. Ensure that you are thoroughly familiar with this guide, paying particular attention to Guidelines and Best Practices, before attempting to contribute to PyAEDT.
The following contribution information is specific to PyAEDT.
Clone the repository#
To clone and install the latest version of PyAEDT in development mode, run:
git clone https://github.com/ansys/pyaedt
cd pyaedt
python -m pip install --upgrade pip
pip install -e .
Post issues#
Use the PyAEDT Issues page to submit questions, report bugs, and request new features.
To reach the product support team, email pyansys.core@ansys.com.
View PyAEDT documentation#
Documentation for the latest stable release of PyAEDT is hosted at PyAEDT Documentation.
In the upper right corner of the documentation’s title bar, there is an option for switching from viewing the documentation for the latest stable release to viewing the documentation for the development version or previously released versions.
Code style#
PyAEDT complies with the PyAnsys code style.
pre-commit is applied within the CI/CD to ensure compliance.
The pre-commit
Python package can be installed
and run as follows:
pip install pre-commit
pre-commit run --all-files
You can also install this as a pre-commit hook with:
pre-commit install
This way, it’s not possible for you to push code that fails the style checks. For example:
$ pre-commit install
$ git commit -am "Add my cool feature."
black....................................................................Passed
isort (python)...........................................................Passed
flake8...................................................................Passed
codespell................................................................Passed
debug statements (python)................................................Passed
trim trailing whitespace.................................................Passed
Validate GitHub Workflows................................................Passed
blacken-docs.............................................................Passed
Naming conventions#
Consistency of names helps improve readability and ease of use. Starting with release 0.8 a concerted effort has been made to improve consistency of naming and adherence to :ref:`PEP-8<https://peps.python.org/pep-0008/>`_.
For example, methods used to create or access entities in
AEDT require that a name be passed to the method or function
as an argument.
It is tempting to
include context as part of that variable name. For example, while it is tempting to use
setupname
as an argument to :meth:`Hfss.create_setup`_,
the context “setup” is
explicitly defined by the method name. The variable name
provides
a more compact
description of the variable in this context.
In previous PyAEDT versions, you can also find both setup_name
and setupname
used
for various methods or classes.
Improving naming consistency improves maintainability and readability.
The following table illustrates the recommended conventions:
Old name |
New name |
Example |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Take care to use descriptive names for variables and classes that adhere to PEP-8 and are consistent with conventions already used in PyAEDT.
Log errors#
PyAEDT has an internal logging tool named Messenger
and a log file that is automatically generated in the project
folder.
The following examples demonstrate how Messenger
is used to
write both to the internal AEDT message windows and the log file:
self.logger.error("This is an error message.")
self.logger.warning("This is a warning message.")
self.logger.info("This is an info message.")
These examples demonstrate how to write messages only to the log file:
self.logger.error("This is an error message.")
self.logger.warning("This is a warning message.")
self.logger.info("This is an info message.")
Handle exceptions#
PyAEDT uses a specific decorator, @pyaedt_function_handler
,
to handle exceptions caused by methods and by the AEDT API.
This exception handler decorator makes PyAEDT fault tolerant
to errors that can occur in any method.
For example:
@pyaedt_function_handler()
def my_method(self, var):
pass
Every method can return a value of True
when successful or
False
when failed. When a failure occurs, the error
handler returns information about the error in both the console and
log file.
Here is an example of an error:
----------------------------------------------------------------------------------
PyAEDT error on method create_box: General or AEDT error. Check again
the arguments provided:
position = [0, 0, 0]
dimensions_list = [0, 10, 10]
name = None
material = None
----------------------------------------------------------------------------------
(-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2147024381), None)
File "C:\GIT\repos\AnsysAutomation\PyAEDT\Primitives.py", line 1930, in create_box
o.name = self.oeditor.createbox(vArg1, vArg2)
************************************************************
Method Docstring:
Create a box.
Parameters
----------
...
Hard-coded values#
Do not write hard-coded values to the registry. Instead, use the Configuration service.
Maximum line length#
Best practice is to keep the length at or below 120 characters for code, and comments. Lines longer than this might not display properly on some terminals and tools or might be difficult to follow.
Extension development guide#
This section describes the steps to create and integrate a PyAEDT extension at the project level. Extensions are modular components that add functionality to the AEDT environment via the PyAEDT API. They follow a structured convention to ensure consistency, maintainability, and documentation.
Note
To create an extension at an application level, for example Hfss, the process is similar.
The main difference is that the extension file and documentation should be placed in the
appropriate directory, for example src/ansys/aedt/core/extensions/hfss
and
doc/source/User_guide/pyaedt_extensions_doc/hfss
respectively.
Step 1: Create the extension Python file#
Navigate to the directory src/ansys/aedt/core/extension/project
and create a new Python file for
your extension. The file name should be descriptive and follow the format extension_name.py
, where
extension_name
is a lowercase, hyphen-separated name that describes the extension’s functionality.
The extension file should follow the official
template
and contain at least two classes:
A class that inherits from
ExtensionCommon
and implements the extension’s logic. By inheriting fromExtensionCommon
, the extension’s theme and style are automatically set and can leverage standard extension methods like the theme button handling, access to the AEDT application, and more. The custom content of the extension should be defined in theadd_extension_content
method and should be called in the__init__
method of the class. This method is where you can define the user interface (UI) elements, such as buttons, text fields, and other widgets to display. Below is an example of how to create a basic extension class:
from ansys.aedt.core.extensions import ExtensionCommon, ExtensionData class MyExtension(ExtensionCommon): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.add_extension_content() def add_extension_content(self): # Define your UI elements here pass
2. A data class that inherits from ExtensionCommonData
. This class should define the data that is provided
and computed through the UI. Below is an example of how to create a data class for your extension:
from dataclasses import dataclass from dataclasses import field @dataclass class MyExtensionData(ExtensionCommonData): setup: str = "" assignments: list = field(default_factory=lambda: [])
Splitting the extension logic into two classes allows for better separation of concerns and makes it easier to
test and maintain the code. The first class handles the UI and user interactions, while the second class
manages the data and logic behind the extension. On top of those classes, the file should also define a
main
function that is used to run the core logic behind the extension. This function should ingest an
instance of the data class defined in the second step. Below is an example of how to define the main
function:
def main(extension_data: MyExtensionData): if not data.setup: raise AEDTRuntimeError("No setup provided to the extension.") # Core logic of the extension goes here
Step 2: Add unit tests#
Create a test file in the tests/unit/extensions
directory with the same name as your extension file, but with a
test_
prefix. For example, if your extension file is named my_extension.py
, the test file should be
test_my_extension.py
. This file should mainly contain unit tests for your extension’s UI components. For example
checking that clicking a button triggers the expected action or that the UI elements are correctly initialized.
If your extension requires AEDT to run, you should patch every method that requires AEDT to run, so that the test
can be run without an active AEDT instance. This is important because unit tests should be fast and not depend on
an external application like AEDT. You can use the unittest.mock library to patch methods and classes that
require AEDT. A good example of such a test file is the
test_template_extension.py
file where the instantiation of the Desktop
class is patched to avoid the need for an active AEDT instance. Below
is an example of how to create a unit test for your extension:
Step 3: Add system tests#
Like the previous step, create a test file in the tests/system/extensions
directory with the same name as your
extension file, but with a test_
prefix. However, contrary to unit tests, system tests are meant to be run with
an active AEDT instance. These tests should validate the overall functionality of the extension, ensuring that it
behaves as expected when integrated into the AEDT environment.
Step 4: Add the extension to the catalog#
Add your extension to the catalog by creating a new entry in the
toolkits_catalog.toml
file located in the src/ansys/aedt/core/extensions/project
directory.
The entry should follow the format of existing entries, specifying the name, script, icon, and template.
For example, to add your extension, you would add an entry like this:
[MyExtension] name = "My Extension" script = "my_extension.py" icon = "images/large/my_extension_icon.png" template = "run_pyaedt_toolkit_script"
The path to the image is relative to the directory where your extension is located. For example, if
the extension is located in the src/ansys/aedt/core/extensions/project
directory then, following
the previous code block information, the path to the icon should be
src/ansys/aedt/core/extensions/project/images/large/my_extension_icon.png
.
Step 5: Add the extension to the documentation#
To ensure that your extension is documented, you need to add a new card to the
doc/source/User_guide/extensions.rst
file. This card links to the extension’s documentation page.
The documentation page needs to be created in the doc/source/User_guide/pyaedt_extensions_doc/project
directory and should contain a brief description of the extension, its functionality, and how to use it.
Also, another card should be added to the
doc/source/User_guide/pyaedt_extensions_doc/project/index.rst
file to link to the extension’s documentation page.
This ensures that the extension is discoverable in the documentation from the multiple pages that list all the
extensions available in PyAEDT.