diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..ef070d6c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,34 @@ + +version: 2 +updates: + - package-ecosystem: "pip" # See documentation for possible values + directory: "/" + insecure-external-code-execution: allow + schedule: + interval: "weekly" + labels: + - "maintenance" + - "dependencies" + groups: + general-dependencies: + patterns: + - "*" + exclude-patterns: + - "*sphinx*" + - "numpydoc" + - "pyvista*" + - "pytest*" + test-dependencies: + patterns: + - "pytest*" + doc-dependencies: + patterns: + - "*sphinx*" + - "numpydoc" + pyvista: + patterns: + - "pyvista*" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 00000000..87c50ff1 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,11 @@ +documentation: +- changed-files: + - any-glob-to-any-file: ['doc/source/**/*', 'README.md'] + +maintenance: +- changed-files: + - any-glob-to-any-file: ['.github/**/*', '.flake8', 'pyproject.toml', 'tox.ini', '.pre-commit-config.yaml'] + +testing: +- changed-files: + - any-glob-to-any-file: ['tests/*'] diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 00000000..e54a34ea --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,35 @@ +- name: bug + description: Something isn't working + color: d42a34 + +- name: dependencies + description: Related with project dependencies + color: ffc0cb + +- name: documentation + description: Improvements or additions to documentation + color: 0677ba + +- name: enhancement + description: New features or code improvements + color: FFD827 + +- name: good first issue + description: Easy to solve for newcomers + color: 62ca50 + +- name: maintenance + description: Package and maintenance related + color: f78c37 + +- name: release + description: Anything related to an incoming release + color: ffffff + +- name: testing + description: Anything related to tests + color: BFE4D6 + +- name: security + description: Anything related to security advisories + color: FF0000 \ No newline at end of file diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 0334121c..75344fda 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -18,6 +18,48 @@ concurrency: cancel-in-progress: true jobs: + style: + name: Code style + runs-on: ubuntu-latest + steps: + - name: PyAnsys code style checks + uses: ansys/actions/code-style@v5 + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + vale-config: "doc/.vale.ini" + vale-version: "2.29.6" + + docs-style: + name: Documentation Style Check + runs-on: ubuntu-latest + steps: + - name: PyAnsys documentation style checks + uses: ansys/actions/doc-style@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + smoke-tests: + name: Build and Smoke tests + runs-on: ${{ matrix.os }} + needs: style + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.9', '3.10', '3.11', '3.12'] + should-release: + - ${{ github.event_name == 'push' && contains(github.ref, 'refs/tags') }} + exclude: + - should-release: false + os: macos-latest + steps: + - name: Build wheelhouse and perform smoke test + uses: ansys/actions/build-wheelhouse@v5 + with: + library-name: ${{ env.LIBRARY_NAME }} + operating-system: ${{ matrix.os }} + python-version: ${{ matrix.python-version }} + tests: name: Tests @@ -26,38 +68,36 @@ jobs: env: ANSYSLMD_LICENSE_FILE: 1055@${{ secrets.LICENSE_SERVER }} + steps: - uses: actions/checkout@v4 - - name: "Install" + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + + - name: Create Python venv run: | python -m venv .venv - .venv/Scripts/activate.bat - pip install -e .[dev] - - - name: "Test" + - name: Install packages for tests run: | - .venv/Scripts/activate.bat - - pre-commit run --all-files --show-diff-on-failure + .\.venv\Scripts\Activate.ps1 + python -m pip install --upgrade pip + pip install .[test] - pytest tests --junitxml=build/tests.xml - - - name: "Check Examples" + - name: "Run unit tests" run: | - .venv/Scripts/activate.bat - - pytest test_examples.py --junitxml=build/tests-examples.xml - - - name: Test Report - uses: dorny/test-reporter@v1 - if: success() || failure() # run this step even if previous step failed - with: - name: Pytest Report - path: build/tests.xml # Path to test results - reporter: java-junit + .\.venv\Scripts\Activate.ps1 + pytest tests +# - uses: codecov/codecov-action@v3 +# name: 'Upload coverage to CodeCov' +# env: +# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} +# with: +# files: .cov/xml docs_build: name: Build Documentation @@ -68,33 +108,79 @@ jobs: steps: - uses: actions/checkout@v4 - - name: "Install" + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + + - name: Create Python venv run: | python -m venv .venv - .venv/Scripts/activate.bat - pip install -e .[dev] + + - name: Install packages for documentation build + run: | + .\.venv\Scripts\Activate.bat pip install msvc-runtime + pip install .[doc] - - name: Build Source Documentation + - name: Build Source Documentation (HTML) run: | - .venv/Scripts/activate.bat + .\.venv\Scripts\Activate.bat doc\make.bat html - - name: Zip HTML Documentation before upload - run: python doc\compress_doc.py HTML-Documentation-tag-${{ env.DOC_DEPLOYMENT_IMAGE_TAG }} - - name: Upload HTML Documentation uses: actions/upload-artifact@v3 with: - name: HTML-Documentation-tag-${{ env.DOC_DEPLOYMENT_IMAGE_TAG }} - path: HTML-Documentation-tag-${{ env.DOC_DEPLOYMENT_IMAGE_TAG }}.zip + name: documentation-html + path: doc/_build/html + retention-days: 7 + + - name: Build Source Documentation (PDF) + run: | + .\.venv\Scripts\Activate.bat + doc\make.bat pdf + + - name: Upload PDF documentation + uses: actions/upload-artifact@v4 + with: + name: documentation-pdf + path: doc/_build/latex/*.pdf retention-days: 7 + package: + name: Package library + needs: [tests, docs_build] + runs-on: ubuntu-latest + steps: + - name: Build library source and wheel artifacts + uses: ansys/actions/build-library@v5 + with: + library-name: ${{ env.LIBRARY_NAME }} + python-version: ${{ env.MAIN_PYTHON_VERSION }} + +# Uncomment when ready to release + release: + name: Release project + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + needs: [package] + runs-on: ubuntu-latest + steps: +# - name: Release to the public PyPI repository +# uses: ansys/actions/release-pypi-public@v5 +# with: +# library-name: ${{ env.LIBRARY_NAME }} +# twine-username: "__token__" +# twine-token: ${{ secrets.PYPI_TOKEN }} + + - name: Release to GitHub + uses: ansys/actions/release-github@v5 + with: + library-name: ${{ env.LIBRARY_NAME }} - doc-deploy-dev: + upload_docs_dev: name: "Deploy development documentation" # Deploy development only when merging or pushing to the 'main' branch - if: github.event_name == 'push' && !contains(github.ref, 'refs/tags') + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest needs: docs_build steps: @@ -103,4 +189,17 @@ jobs: doc-artifact-name: 'HTML-Documentation-tag-${{ env.DOC_DEPLOYMENT_IMAGE_TAG }}' decompress-artifact: true cname: ${{ env.DOCUMENTATION_CNAME }} - token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + token: ${{ secrets.GITHUB_TOKEN }} + + upload_docs_release: + name: "Deploy stable documentation" + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'dev') + runs-on: ubuntu-latest + needs: [release] + steps: + - name: Deploy the stable documentation + uses: ansys/actions/doc-deploy-stable@v5 + with: + cname: ${{ env.DOCUMENTATION_CNAME }} + token: ${{ secrets.GITHUB_TOKEN }} + python-version: ${{ env.MAIN_PYTHON_VERSION }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 86c99b76..048cd54c 100644 --- a/.gitignore +++ b/.gitignore @@ -75,7 +75,8 @@ instance/ # Sphinx documentation doc/_build/ - +doc/source/examples +doc/source/api # PyBuilder .pybuilder/ target/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 50aa6766..dcaf2b3d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,33 +1,40 @@ repos: - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.12.1 hooks: - id: black - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + rev: 7.0.0 hooks: - id: flake8 - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 + rev: v2.2.6 hooks: - id: codespell - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-merge-conflict - id: requirements-txt-fixer - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.22.0 + rev: 0.27.3 hooks: - id: check-github-workflows + +- repo: https://github.com/ansys/pre-commit-hooks + rev: v0.2.8 + hooks: + - id: add-license-headers + args: + - --start_year=2023 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..e4a0da58 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,12 @@ +# This is the list of PyRocky's significant contributors. +# +# This file does not necessarily list everyone who has contributed code. +# +# For contributions made under a Corporate CLA, the organization is +# added to this file. +# +# If you have contributed to the repository and wish to be added to this file +# please submit a request. +# +# +ANSYS, Inc. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..c1b3a0f7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# Contributing + +For contributing to this project, please refer to the [PyAnsys Developer's Guide]. + +[PyAnsys Developer's Guide]: https://dev.docs.pyansys.com/how-to/contributing.html \ No newline at end of file diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 00000000..52bdcc1d --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,12 @@ +# Contributors + +## Project Lead + +* [Igor Ghisi](https://github.com/igortg) + +## Individual Contributors + +* [Alejandro Fernández Luces](https://github.com/AlejandroFernandezLuces) +* [Gustavo Corrêa Martins](https://github.com/gcmartins) +* [Jorge Martínez Garrido](https://github.com/jorgepiloto) +* [Roberto Pastor Muela](https://github.com/RobPasMue) diff --git a/README.rst b/README.rst index ef149706..5569985f 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ -PyRocky ansys-rocky-core -=========================== +PyRocky +======= -|pyansys| |MIT| +|pyansys| |MIT| |python| |pypi| |codecov| |MIT| |black| |pre-commit| A Python package to remote control Ansys Rocky. @@ -16,7 +16,7 @@ repository: .. code:: bash - python -m pip install https://github.com/ansys-internal/pyrocky + python -m pip install https://github.com/ansys/pyrocky Getting Started ^^^^^^^^^^^^^^^ @@ -107,3 +107,26 @@ Known Issues :target: https://opensource.org/licenses/MIT :alt: MIT +.. |python| image:: https://img.shields.io/pypi/pyversions/ansys-rocky-core?logo=pypi + :target: https://pypi.org/project/ansys-rocky-core/ + :alt: Python + +.. |pypi| image:: https://img.shields.io/pypi/v/ansys-rocky-core.svg?logo=python&logoColor=white + :target: https://pypi.org/project/ansys-rocky-core + :alt: PyPI + +.. |codecov| image:: https://codecov.io/gh/ansys/pyrocky/graph/badge.svg?token=UZIC7XT5WE + :target: https://codecov.io/gh/ansys/pyrocky + :alt: Codecov + +.. |GH-CI| image:: https://github.com/ansys/pyrocky/actions/workflows/ci_cd.yml/badge.svg + :target: https://github.com/ansys/pyrocky/actions/workflows/ci_cd.yml + :alt: GH-CI + +.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg?style=flat + :target: https://github.com/psf/black + :alt: Black + +.. |pre-commit| image:: https://results.pre-commit.ci/badge/github/ansys/pyrocky/main.svg + :target: https://results.pre-commit.ci/latest/github/ansys/pyrocky/main + :alt: pre-commit.ci diff --git a/doc/Makefile b/doc/Makefile index fd967771..ce66465f 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -13,6 +13,13 @@ help: .PHONY: help Makefile +.install-deps: + @pip freeze | grep -q "sphinx-autoapi @ git+https://github.com/ansys/sphinx-autoapi" && is_custom_sphinx_autoapi_installed="yes" || is_custom_sphinx_autoapi_installed="no" + @if [ "$$is_custom_sphinx_autoapi_installed" != "yes" ]; then \ + pip uninstall --yes sphinx-autoapi; \ + pip install "sphinx-autoapi @ git+https://github.com/ansys/sphinx-autoapi@feat/single-page-stable"; \ + fi + # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile diff --git a/doc/compress_doc.py b/doc/compress_doc.py deleted file mode 100644 index e0982469..00000000 --- a/doc/compress_doc.py +++ /dev/null @@ -1,16 +0,0 @@ -import os.path -from pathlib import Path -import shutil -import sys - - -def compress_doc(name: str) -> None: - path = Path(os.path.realpath(__file__)) - doc_build_path = path.parent / "_build/html" - - shutil.make_archive(name, "zip", doc_build_path) - - -if __name__ == "__main__": - name = sys.argv[1] - compress_doc(name) diff --git a/doc/make.bat b/doc/make.bat index cfdfa1cf..0b80bdf1 100644 --- a/doc/make.bat +++ b/doc/make.bat @@ -10,8 +10,16 @@ if "%SPHINXBUILD%" == "" ( set SOURCEDIR=source set BUILDDIR=_build +REM TODO: these lines of code should be removed once the feature branch is merged +for /f %%i in ('pip freeze ^| findstr /c:"sphinx-autoapi @ git+https://github.com/ansys/sphinx-autoapi"') do set is_custom_sphinx_autoapi_installed=%%i +if NOT "%is_custom_sphinx_autoapi_installed%" == "sphinx-autoapi" ( + pip uninstall --yes sphinx-autoapi + pip install "sphinx-autoapi @ git+https://github.com/ansys/sphinx-autoapi@feat/single-page-stable") +REM TODO: these lines of code should be removed once the feature branch is merged + if "%1" == "" goto help if "%1" == "clean" goto clean +if "%1" == "pdf" goto pdf %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( @@ -37,5 +45,17 @@ goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:pdf + %SPHINXBUILD% -M latex %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + cd "%BUILDDIR%\latex" + for %%f in (*.tex) do ( + pdflatex "%%f" --interaction=nonstopmode) + if NOT EXIST pyrocky.pdf ( + + Echo "no pdf generated!" + exit /b 1) + Echo "pdf generated!" + :end popd diff --git a/doc/source/conf.py b/doc/source/conf.py index 44fede1e..d209f9da 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,17 +1,24 @@ """Sphinx documentation configuration file.""" from datetime import datetime import os +from pathlib import Path -from ansys_sphinx_theme import get_version_match +from ansys_sphinx_theme import ( + ansys_favicon, + get_autoapi_templates_dir_relative_path, + get_version_match, +) from ansys_sphinx_theme import pyansys_logo_black as logo from sphinx_gallery.sorting import FileNameSortKey +from ansys.rocky.core import __version__ + # Project information project = "pyrocky" copyright = f"(c) {datetime.now().year} ANSYS, Inc. All rights reserved" author = "ANSYS, Inc." -release = version = "0.1.dev0" -cname = os.getenv("DOCUMENTATION_CNAME", "docs.pyansys.com") +release = version = __version__ +cname = os.getenv("DOCUMENTATION_CNAME", "rocky.docs.pyansys.com") # Select desired logo, theme, and declare the html title html_logo = logo @@ -38,9 +45,11 @@ "sphinx.ext.autodoc", "sphinx.ext.autosummary", "numpydoc", + "autoapi.extension", "sphinx.ext.intersphinx", "sphinx_copybutton", "sphinx_gallery.gen_gallery", + "sphinx_design", ] # Intersphinx mapping @@ -80,6 +89,7 @@ # static path html_static_path = ["_static"] +html_favicon = ansys_favicon # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -105,3 +115,20 @@ # directory where function granular galleries are stored "backreferences_dir": None, } + +# Configuration for Sphinx autoapi +autoapi_type = "python" +autoapi_dirs = ["../../src/ansys"] +autoapi_root = "api" +autoapi_options = [ + "members", + "undoc-members", + "show-inheritance", + "show-module-summary", + "special-members", +] +autoapi_template_dir = get_autoapi_templates_dir_relative_path(Path(__file__)) +suppress_warnings = ["autoapi.python_import_resolution"] +autoapi_python_use_implicit_namespaces = True +autoapi_keep_files = True +autoapi_render_in_single_page = ["class", "enum", "exception"] diff --git a/doc/source/getting_started/index.rst b/doc/source/getting_started/index.rst index 4a60e401..c25b2dfa 100644 --- a/doc/source/getting_started/index.rst +++ b/doc/source/getting_started/index.rst @@ -13,7 +13,7 @@ repository: .. code:: bash - python -m pip install https://github.com/ansys-internal/pyrocky + python -m pip install https://github.com/ansys/pyrocky Launch PyRocky diff --git a/doc/source/index.rst b/doc/source/index.rst index 54f783b7..058e646c 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,4 +1,74 @@ -.. include:: ../../README.rst +PyRocky +####### +.. grid:: 2 + :gutter: 2 3 3 4 + + .. grid-item-card:: Getting started + :text-align: center + + :material-regular:`start;48px` + + How to install and use PyRocky. + + +++ + .. button-link:: getting_started/index.html + :color: secondary + :expand: + :outline: + :click-parent: + + Getting started + + .. grid-item-card:: User guide + :text-align: center + + :material-regular:`book;48px` + + Initial steps to get started with PyRocky. + + +++ + .. button-link:: user_guide/index.html + :color: secondary + :expand: + :outline: + :click-parent: + + User guide + +.. grid:: 2 + :gutter: 2 3 3 4 + + .. grid-item-card:: Examples + :text-align: center + + :material-regular:`code;48px` + + PyRocky usage examples. + + +++ + .. button-link:: examples/index.html + :color: secondary + :expand: + :outline: + :click-parent: + + Examples + + .. grid-item-card:: API reference + :text-align: center + + :material-regular:`terminal;48px` + + Interface of PyRocky. + + +++ + .. button-link:: api/index.html + :color: secondary + :expand: + :outline: + :click-parent: + + API reference .. toctree:: @@ -8,4 +78,5 @@ getting_started/index user_guide/index examples/index + api/index diff --git a/doc/source/user_guide/index.rst b/doc/source/user_guide/index.rst index da3e54b1..ed705c4c 100644 --- a/doc/source/user_guide/index.rst +++ b/doc/source/user_guide/index.rst @@ -1,7 +1,7 @@ .. _ref_index_user_guide: ========== -User Guide +User guide ========== @@ -24,10 +24,10 @@ You can get the full documentation within Rocky Application (*Help* - *Manuals* *API PrePost*). -Known Issues +Known issues ************** - When opened with UI visible (non-headless), PyRocky cannot deal with confirmation - or error dialogs (for instance, a call to ``CloseProject()`` will ask for confirmation - and PyRocky will freeze until user click `OK` or `Cancel` on the UI). + or error dialogs (for instance, a call to ``CloseProject()`` asks for confirmation + and PyRocky freezes until user click `OK` or `Cancel` on the UI). - Some API methods may not work. diff --git a/doc/styles/Vocab/ANSYS/accept.txt b/doc/styles/Vocab/ANSYS/accept.txt index f59f7712..faa439c2 100644 --- a/doc/styles/Vocab/ANSYS/accept.txt +++ b/doc/styles/Vocab/ANSYS/accept.txt @@ -1,3 +1,7 @@ -ANSYS -Ansys -ansys +(?i)ansys +(?i)VSCode +dialogs +(?i)Rocky +(?i)PrePost +(?i)API +(?i)pyrocky \ No newline at end of file diff --git a/examples/README.txt b/examples/README.txt index d70423d6..13e7b846 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -10,5 +10,5 @@ you can download these examples as Python files or Jupyter notebooks and run the :maxdepth: 1 :hidden: - basic_examples/README.txt + basic_examples/index.rst diff --git a/examples/basic_examples/minimal.py b/examples/basic_examples/minimal.py index 22806d93..8ae241ab 100644 --- a/examples/basic_examples/minimal.py +++ b/examples/basic_examples/minimal.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2024 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. + """.. _ref_minimal: Simple Particle Simulation diff --git a/examples/basic_examples/particle_wall_interaction.py b/examples/basic_examples/particle_wall_interaction.py index 02074a7a..40bb706a 100644 --- a/examples/basic_examples/particle_wall_interaction.py +++ b/examples/basic_examples/particle_wall_interaction.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2024 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. + """.. _ref_particle_wall_interaction: Particle simulation with wall interaction diff --git a/examples/basic_examples/particle_wall_interaction_with_motion.py b/examples/basic_examples/particle_wall_interaction_with_motion.py index cbafe17e..a0dc31ce 100644 --- a/examples/basic_examples/particle_wall_interaction_with_motion.py +++ b/examples/basic_examples/particle_wall_interaction_with_motion.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2024 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. + """.. _ref_particle_wall_interaction_with_motion: Particle simulation with moving wall interaction diff --git a/pyproject.toml b/pyproject.toml index f36e1646..b86635c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,43 +1,57 @@ [build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["flit_core >=3.2,<4"] +build-backend = "flit_core.buildapi" [project] name = "ansys-rocky-core" -version = "0.4.0" -authors = [ - { name="ANSYS, Inc.", email="pyansys.support@ansys.com" }, -] +version = "0.1.dev0" +authors = [{ name="ANSYS, Inc.", email="pyansys.core@ansys.com" }] description = "A Python wrapper for Ansys Rocky PrePost UI" readme = "README.rst" -requires-python = ">=3.8" +requires-python = ">=3.9,<4" +license = { file = "LICENSE" } classifiers = [ - "Development Status :: 4 - Beta", - "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Information Analysis", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] -license = { file = "LICENSE" } dependencies = [ - "importlib-metadata >=4.0", - "Pyro5", - "numpy >=1.19, <2.0", - "ansys-sphinx-theme ==0.9.9", - "numpydoc ==1.5.0", - "Sphinx ==6.2.1", - "sphinx-copybutton ==0.5.1", - "sphinx-gallery ==0.14.0", - "matplotlib ==3.8.2", # required by sphinx-gallery + "importlib-metadata>=4.0", + "Pyro5>=5.13", + "numpy>=1.19, <2.0", ] [project.optional-dependencies] -dev = [ - "pre-commit", - "pytest >=7.4", +tests = [ + "pytest==7.4.4", + "pytest-cov==4.1.0", +] +doc = [ + "ansys-sphinx-theme==0.12.5", + "numpydoc==1.5.0", + "Sphinx==7.2.6", + "sphinx-autoapi==3.0.0", + "sphinx-copybutton==0.5.2", + "sphinx-gallery==0.15.0", + "sphinx-design==0.5.0", + "matplotlib==3.8.2", # required by sphinx-gallery ] [project.urls] -"Homepage" = "https://github.com/pyansys/pyrocky" +Source = "https://github.com/ansys/pyrocky" +Issues = "https://github.com/ansys/pyrocky/" +Discussions = "https://github.com/ansys/pyrocky/discussions" +Documentation = "https://rocky.docs.pyansys.com" +Releases = "https://github.com/ansys/pyrocky/releases" + +[tool.flit.module] +name = "ansys.rocky.core" [tool.black] line-length = 90 @@ -47,4 +61,15 @@ profile = "black" force_sort_within_sections = true line_length = 90 default_section = "THIRDPARTY" -src_paths = ["src", "tests"] +src_paths = ["doc", "src", "tests"] + +[tool.coverage.run] +source = ["ansys.rocky"] + +[tool.coverage.report] +show_missing = true + +[tool.pytest.ini_options] +minversion = "7.1" +addopts = "-ra --cov=ansys.rocky --cov-report html:.cov/html --cov-report xml:.cov/xml --cov-report term -vv" +testpaths = ["tests"] diff --git a/src/ansys/rocky/core/__init__.py b/src/ansys/rocky/core/__init__.py index 5c9e7c03..14960db3 100644 --- a/src/ansys/rocky/core/__init__.py +++ b/src/ansys/rocky/core/__init__.py @@ -1,13 +1,32 @@ +# Copyright (C) 2023 - 2024 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. + +import importlib.metadata as importlib_metadata + from .client import connect_to_rocky from .launcher import launch_rocky -# TODO: Set __version__ -# try: -# import importlib.metadata as importlib_metadata -# except ModuleNotFoundError: -# import importlib_metadata -# -# __version__ = importlib_metadata.version(__name__.replace(".", "-")) +__version__ = importlib_metadata.version(__name__.replace(".", "-")) +"""PyRocky version.""" __all__ = [ diff --git a/src/ansys/rocky/core/client.py b/src/ansys/rocky/core/client.py index 9b13f492..bfc1d97f 100644 --- a/src/ansys/rocky/core/client.py +++ b/src/ansys/rocky/core/client.py @@ -1,19 +1,50 @@ +# Copyright (C) 2023 - 2024 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. + import pickle from typing import Generator import Pyro5.api import serpent +from ansys.rocky.core.exceptions import RockyApiError + _ROCKY_API = None def connect_to_rocky(host: str = "localhost", port: int = 50615) -> "RockyClient": - """ - Connect to a Rocky Application instance. - - :param host: The host name where the application is running. - - :param port: The service port to connect. + """Connect to a Rocky Application instance. + + Parameters + ---------- + host : str, optional + The host name where the application is running, by default "localhost". + port : int, optional + The service port to connect, by default 50615. + + Returns + ------- + RockyClient + A client object to interact with the Rocky Application. """ uri = f"PYRO:rocky.api@{host}:{port}" global _ROCKY_API @@ -23,6 +54,14 @@ def connect_to_rocky(host: str = "localhost", port: int = 50615) -> "RockyClient class RockyClient: + """A client object to interact with the Rocky Application. + + Parameters + ---------- + rocky_api : Pyro5.api.Proxy + The Pyro5 proxy object to interact with the Rocky Application. + """ + def __init__(self, rocky_api): self._api_adapter = rocky_api @@ -35,6 +74,16 @@ def close(self): class _ApiElementProxy: + """A proxy object for API Elements. + + Parameters + ---------- + pyro_api : Pyro5.api.Proxy + The Pyro5 proxy object to interact with the Rocky Application. + pool_id : int + The ID of the API Element. + """ + def __init__(self, pyro_api, pool_id): self._pool_id = pool_id self._pyro_api = pyro_api @@ -48,18 +97,42 @@ def CallProxy(*args, **kwargs): return CallProxy @classmethod - def deserialize(cls, classname, serialized): + def deserialize(cls, classname: str, serialized: dict) -> "_ApiElementProxy": + """Deserialize an API Element Proxy object. + + Parameters + ---------- + serialized : dict + The serialized object. + classname : str + The name of the class to be deserialized, required by superclass but unused. + + Returns + ------- + _ApiElementProxy + The deserialized object. + """ return cls(_ROCKY_API, serialized["_api_element_id"]) @classmethod def serialize(cls, obj) -> dict: + """Serialize an API Element Proxy object. + + Parameters + ---------- + obj : Any + The object to be serialized. + + Returns + ------- + dict + The serialized object. + """ return {"__class__": cls.__name__, "_api_element_id": obj._pool_id} class _ApiListProxy(_ApiElementProxy): - """ - A proxy object for API Elements that implement the sequence interface. - """ + """A proxy object for API Elements that implement the sequence interface.""" def __len__(self) -> int: return self._pyro_api.SendToApiElement(self._pool_id, "__len__") @@ -75,13 +148,41 @@ def __delitem__(self, index: int) -> None: self._pyro_api.SendToSubject(self._pool_id, "__delitem__", index) -def deserialize_api_error(classname, serialized): +def deserialize_api_error(classname: str, serialized: dict) -> RockyApiError: + """Deserialize an API Error. + + Parameters + ---------- + classname : str + The name of the class to be deserialized, required by superclass but unused. + serialized : dict + The serialized object. + + Returns + ------- + RockyApiError + The error in serialized object. + """ return RockyApiError(serialized["message"]) -def deserialize_numpy(classname, serialized): - bytes = serpent.tobytes(serialized["bytes"]) - return pickle.loads(bytes) +def deserialize_numpy(classname, serialized) -> "Any": + """Deserialize a numpy array. + + Parameters + ---------- + classname : str + The name of the class to be deserialized, required by superclass but unused. + serialized : dict + The serialized object. + + Returns + ------- + Any + The deserialized object. + """ + deserialized_bytes = serpent.tobytes(serialized["bytes"]) + return pickle.loads(deserialized_bytes) Pyro5.api.register_dict_to_class("ApiElementProxy", _ApiElementProxy.deserialize) @@ -90,9 +191,3 @@ def deserialize_numpy(classname, serialized): Pyro5.api.register_dict_to_class("ndarray", deserialize_numpy) Pyro5.api.register_class_to_dict(_ApiElementProxy, _ApiElementProxy.serialize) - - -class RockyApiError(Exception): - """ - Exception class representing an error generated in the API layer. - """ diff --git a/src/ansys/rocky/core/examples.py b/src/ansys/rocky/core/examples.py index d77542b0..716daec7 100644 --- a/src/ansys/rocky/core/examples.py +++ b/src/ansys/rocky/core/examples.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2024 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. + import logging import os from typing import Optional @@ -10,11 +32,31 @@ ANSYS_EXAMPLE_DATA_REPO = "https://github.com/ansys/example-data/raw/master" -def _get_file_url(file_name: str, directory: Optional[str] = None) -> str: - """Get file URL.""" +def _get_file_url( + file_name: str, + directory: Optional[str] = None, + file_host: str = ANSYS_EXAMPLE_DATA_REPO, +) -> str: + """Get file from an URL. + + Parameters + ---------- + file_name : str + File to download. + directory : str, optional + Ansys example data repository directory where specified file is located. If not + specified, looks for the file in the root directory of the repository. + file_host : str, optional + URL of the file host, by default ANSYS_EXAMPLE_DATA_REPO. + + Returns + ------- + str + URL of the file. + """ if directory: - return f"{ANSYS_EXAMPLE_DATA_REPO}/{directory}/{file_name}" - return f"{ANSYS_EXAMPLE_DATA_REPO}/{file_name}" + return f"{file_host}/{directory}/{file_name}" + return f"{file_host}/{file_name}" def _retrieve_file( @@ -22,7 +64,22 @@ def _retrieve_file( file_name: str, save_path: str, ) -> str: - """Download specified file from specified URL.""" + """Download specified file from specified URL. + + Parameters + ---------- + url : str + URL of the file to download. + file_name : str + File to download. + save_path : str + Path to download the specified file to. + + Returns + ------- + str + file path of the downloaded file. + """ file_name = os.path.basename(file_name) save_path = os.path.abspath(save_path) local_path = os.path.join(save_path, file_name) diff --git a/src/ansys/rocky/core/exceptions.py b/src/ansys/rocky/core/exceptions.py index 61317475..151bf8e0 100644 --- a/src/ansys/rocky/core/exceptions.py +++ b/src/ansys/rocky/core/exceptions.py @@ -1,2 +1,33 @@ +# Copyright (C) 2023 - 2024 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. + + class PyRockyError(Exception): - """Generic exception for PyRocky API""" + """Generic exception for PyRocky API.""" + + +class RockyLaunchError(PyRockyError): + """Raised for errors occurred during Rocky application launch.""" + + +class RockyApiError(Exception): + """Exception class representing an error generated in the API layer.""" diff --git a/src/ansys/rocky/core/launcher.py b/src/ansys/rocky/core/launcher.py index b74e2a6c..6f305b49 100644 --- a/src/ansys/rocky/core/launcher.py +++ b/src/ansys/rocky/core/launcher.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2024 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. + import contextlib import os from pathlib import Path @@ -8,7 +30,7 @@ from Pyro5.errors import CommunicationError from ansys.rocky.core.client import RockyClient, connect_to_rocky -from ansys.rocky.core.exceptions import PyRockyError +from ansys.rocky.core.exceptions import RockyLaunchError def launch_rocky( @@ -18,6 +40,19 @@ def launch_rocky( """ Launch Rocky executable with PyRocky server enabled, wait Rocky to start up and return a `RockyClient` instance. + + Parameters + ---------- + rocky_exe : Optional[Path], optional + Path to Rocky executable. If not specified, will try to find it in the + environment variables `AWP_ROOT241` and `AWP_ROOT232`. + headless : bool, optional + Whether to launch Rocky in headless mode. Default is `True`. + + Returns + ------- + RockyClient + A `RockyClient` instance connected to the launched Rocky application. """ if rocky_exe is None: for awp_root in ["AWP_ROOT241", "AWP_ROOT232"]: @@ -62,7 +97,3 @@ def launch_rocky( _WAIT_ROCKY_START = 60 - - -class RockyLaunchError(PyRockyError): - """Raised for errors occurred during Rocky application launch""" diff --git a/test_examples.py b/test_examples.py deleted file mode 100644 index d4c0eada..00000000 --- a/test_examples.py +++ /dev/null @@ -1,12 +0,0 @@ -from pathlib import Path -import subprocess -import sys - -import pytest - -EXAMPLES_DIR = Path(__file__).parent / "examples" - - -@pytest.mark.parametrize("example_path", list(EXAMPLES_DIR.glob("*.py"))) -def test_examples(example_path: Path) -> None: - subprocess.check_call([sys.executable, str(example_path.absolute())]) diff --git a/tests/test_examples_download.py b/tests/test_examples_download.py index bb0f0b8f..3cc49365 100644 --- a/tests/test_examples_download.py +++ b/tests/test_examples_download.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2024 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. + from pathlib import Path import tempfile diff --git a/tests/test_pyrocky.py b/tests/test_pyrocky.py index 0f4d0b0d..c05dce44 100644 --- a/tests/test_pyrocky.py +++ b/tests/test_pyrocky.py @@ -1,3 +1,25 @@ +# Copyright (C) 2023 - 2024 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. + import pytest import ansys.rocky.core as pyrocky