diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index e3f3e4f0d..6b9774ebf 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -174,6 +174,22 @@ jobs: else echo "matrix={\"mechanical-version\":['${{ needs.revn-variations.outputs.test_docker_image_version }}'],\"experimental\":[false]}" >> $GITHUB_OUTPUT fi + container-stability-check: + runs-on: ubuntu-latest + needs: [revn-variations] + outputs: + container_stable_exit: ${{ steps.check_stability.outputs.container_stable_exit }} + steps: + - id: check_stability + run: | + sudo apt update + sudo apt install bc -y + CONTAINER_VERSION=$(echo "${{ needs.revn-variations.outputs.test_docker_image_version }}" | grep -o -E '[0-9]+(\.[0-9]+)?' | head -n 1) + if (( $(echo "$CONTAINER_VERSION > 24.2" | bc -l) )); then + echo "container_stable_exit=true" >> $GITHUB_OUTPUT + else + echo "container_stable_exit=false" >> $GITHUB_OUTPUT + fi remote-connect: name: Remote connect testing and coverage - Mechanical ${{ matrix.mechanical-version }} @@ -222,7 +238,7 @@ jobs: pytest-extra-args: '-s --junitxml remote_results${{ env.MAIN_PYTHON_VERSION}}.xml' - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 + uses: mikepenz/action-junit-report@v5 if: always() with: report_paths: '**/remote_results*.xml' @@ -269,7 +285,7 @@ jobs: name: Embedding testing and coverage runs-on: ubuntu-latest timeout-minutes: 10 - needs: [smoke-tests, revn-variations] + needs: [smoke-tests, revn-variations, container-stability-check] container: image: ${{ needs.revn-variations.outputs.test_container }} options: --entrypoint /bin/bash @@ -304,7 +320,11 @@ jobs: PYTHONUNBUFFERED: 1 run: | . /env/bin/activate - xvfb-run mechanical-env pytest -m embedding -s --junitxml test_results${{ matrix.python-version }}.xml || true + if [ "${{ needs.container-stability-check.outputs.container_stable_exit }}" = "true" ]; then + xvfb-run mechanical-env pytest -m embedding -s --junitxml test_results${{ matrix.python-version }}.xml + else + xvfb-run mechanical-env pytest -m embedding -s --junitxml test_results${{ matrix.python-version }}.xml || true + fi - name: Upload coverage results uses: actions/upload-artifact@v4 @@ -325,7 +345,7 @@ jobs: retention-days: 7 - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 + uses: mikepenz/action-junit-report@v5 if: always() with: report_paths: '**/test_results*.xml' @@ -395,7 +415,7 @@ jobs: retention-days: 7 - name: Publish Test Report - uses: mikepenz/action-junit-report@v4 + uses: mikepenz/action-junit-report@v5 if: always() with: report_paths: '**/test_results*.xml' @@ -411,7 +431,7 @@ jobs: container: image: ${{ needs.revn-variations.outputs.test_container }} options: --entrypoint /bin/bash - needs: [ style, revn-variations] + needs: [ style, revn-variations, container-stability-check] strategy: fail-fast: false matrix: @@ -447,10 +467,14 @@ jobs: unset PYMECHANICAL_PORT unset PYMECHANICAL_START_INSTANCE . /env/bin/activate - pytest -m remote_session_launch -s --junitxml launch_test_results${{ matrix.python-version }}.xml || true + if [ "${{ needs.container-stability-check.outputs.container_stable_exit }}" = "true" ]; then + pytest -m remote_session_launch -s --junitxml launch_test_results${{ matrix.python-version }}.xml + else + pytest -m remote_session_launch -s --junitxml launch_test_results${{ matrix.python-version }}.xml || true + fi - name: Publish Launch Test Report - uses: mikepenz/action-junit-report@v4 + uses: mikepenz/action-junit-report@v5 if: always() with: report_paths: '**/launch_test_results*.xml' @@ -481,9 +505,9 @@ jobs: name: Documentation runs-on: ubuntu-latest container: - image: ${{ needs.revn-variations.outputs.stable_container }} + image: ${{ needs.revn-variations.outputs.test_container }} options: --entrypoint /bin/bash - needs: [style, doc-style, revn-variations] + needs: [style, doc-style, revn-variations, container-stability-check] steps: @@ -545,10 +569,14 @@ jobs: unset PYMECHANICAL_START_INSTANCE output_file=doc_$1_output.txt - xvfb-run mechanical-env make -C doc $1 > $output_file 2>&1 || true - cat $output_file - echo done running make - validate_output $output_file + if [ "${{ needs.container-stability-check.outputs.container_stable_exit }}" = "true" ]; then + xvfb-run mechanical-env make -C doc $1 + else + xvfb-run mechanical-env make -C doc $1 > $output_file 2>&1 || true + cat $output_file + echo done running make + validate_output $output_file + fi } # Validate that the html or pdf build succeeded diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c6ad77a4c..e333711d1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -41,7 +41,7 @@ repos: args: ["--ignore-words", "doc/styles/config/vocabularies/ANSYS/accept.txt", "-w"] - repo: https://github.com/ansys/pre-commit-hooks - rev: v0.4.3 + rev: v0.4.4 hooks: - id: add-license-headers args: diff --git a/doc/changelog.d/963.maintenance.md b/doc/changelog.d/963.maintenance.md new file mode 100644 index 000000000..a6b550420 --- /dev/null +++ b/doc/changelog.d/963.maintenance.md @@ -0,0 +1 @@ +update CHANGELOG for v0.11.9 \ No newline at end of file diff --git a/doc/changelog.d/965.maintenance.md b/doc/changelog.d/965.maintenance.md new file mode 100644 index 000000000..b238e087b --- /dev/null +++ b/doc/changelog.d/965.maintenance.md @@ -0,0 +1 @@ +Modify how job success is verified for CI/CD \ No newline at end of file diff --git a/doc/changelog.d/966.maintenance.md b/doc/changelog.d/966.maintenance.md new file mode 100644 index 000000000..107cc77ef --- /dev/null +++ b/doc/changelog.d/966.maintenance.md @@ -0,0 +1 @@ +Bump mikepenz/action-junit-report from 4 to 5 \ No newline at end of file diff --git a/doc/changelog.d/967.maintenance.md b/doc/changelog.d/967.maintenance.md new file mode 100644 index 000000000..fb4a912cf --- /dev/null +++ b/doc/changelog.d/967.maintenance.md @@ -0,0 +1 @@ +Bump grpcio from 1.67.0 to 1.67.1 in the core group \ No newline at end of file diff --git a/doc/changelog.d/968.maintenance.md b/doc/changelog.d/968.maintenance.md new file mode 100644 index 000000000..46cb383cb --- /dev/null +++ b/doc/changelog.d/968.maintenance.md @@ -0,0 +1 @@ +Bump the doc group with 2 updates \ No newline at end of file diff --git a/doc/changelog.d/969.maintenance.md b/doc/changelog.d/969.maintenance.md new file mode 100644 index 000000000..29df49383 --- /dev/null +++ b/doc/changelog.d/969.maintenance.md @@ -0,0 +1 @@ +Bump pytest-cov from 5.0.0 to 6.0.0 \ No newline at end of file diff --git a/doc/changelog.d/971.maintenance.md b/doc/changelog.d/971.maintenance.md new file mode 100644 index 000000000..1905364bf --- /dev/null +++ b/doc/changelog.d/971.maintenance.md @@ -0,0 +1 @@ +Update docs build action container \ No newline at end of file diff --git a/doc/changelog.d/972.documentation.md b/doc/changelog.d/972.documentation.md new file mode 100644 index 000000000..6474743c5 --- /dev/null +++ b/doc/changelog.d/972.documentation.md @@ -0,0 +1 @@ +add Mechanical API link to Mechanical Scripting page \ No newline at end of file diff --git a/doc/changelog.d/974.fixed.md b/doc/changelog.d/974.fixed.md new file mode 100644 index 000000000..528e24028 --- /dev/null +++ b/doc/changelog.d/974.fixed.md @@ -0,0 +1 @@ +Update embedding script tests \ No newline at end of file diff --git a/doc/changelog.d/977.maintenance.md b/doc/changelog.d/977.maintenance.md new file mode 100644 index 000000000..c655a0905 --- /dev/null +++ b/doc/changelog.d/977.maintenance.md @@ -0,0 +1 @@ +pre-commit automatic update \ No newline at end of file diff --git a/doc/changelog.d/979.added.md b/doc/changelog.d/979.added.md new file mode 100644 index 000000000..babdcd2c1 --- /dev/null +++ b/doc/changelog.d/979.added.md @@ -0,0 +1 @@ +Version input type check \ No newline at end of file diff --git a/doc/changelog.d/980.added.md b/doc/changelog.d/980.added.md new file mode 100644 index 000000000..feb48b43a --- /dev/null +++ b/doc/changelog.d/980.added.md @@ -0,0 +1 @@ +Adding new method for connecting to Mechanical instance \ No newline at end of file diff --git a/doc/changelog.d/981.maintenance.md b/doc/changelog.d/981.maintenance.md new file mode 100644 index 000000000..47c9b5c59 --- /dev/null +++ b/doc/changelog.d/981.maintenance.md @@ -0,0 +1 @@ +Bump grpcio from 1.67.1 to 1.68.0 in the core group \ No newline at end of file diff --git a/doc/changelog.d/982.maintenance.md b/doc/changelog.d/982.maintenance.md new file mode 100644 index 000000000..46cb383cb --- /dev/null +++ b/doc/changelog.d/982.maintenance.md @@ -0,0 +1 @@ +Bump the doc group with 2 updates \ No newline at end of file diff --git a/doc/source/cheatsheet/cheat_sheet.qmd b/doc/source/cheatsheet/cheat_sheet.qmd index a3b0d01bb..a500813c2 100644 --- a/doc/source/cheatsheet/cheat_sheet.qmd +++ b/doc/source/cheatsheet/cheat_sheet.qmd @@ -75,12 +75,12 @@ ansys-mechanical -r 242 --port 10000 -g ## Manually connect to the Mechanical session ```{python} #| eval: false -import ansys.mechanical.core as pymechanical +from ansys.mechanical.core import connect_to_mechanical # Connect locally -mechanical = pymechanical.Mechanical(port=10000) +mechanical = connect_to_mechanical(port=10000) # Or # Connect remotely, to the IP address or hostname -mechanical = pymechanical.Mechanical( +mechanical = connect_to_mechanical( "192.168.0.1", port=10000 ) ``` diff --git a/doc/source/links.rst b/doc/source/links.rst index 589b90e68..40bf1f4ba 100644 --- a/doc/source/links.rst +++ b/doc/source/links.rst @@ -19,7 +19,8 @@ .. _Chapter 7: https://ansyshelp.ansys.com/account/secured?returnurl=/Views/Secured/corp/%%VERSION%%/en/installation/win_silent.html .. # Mechanical related -.. _Mechanical scripting interface: https://developer.ansys.com/docs/mechanical-scripting-interface/api/index.md +.. _Mechanical API Documentation: https://scripting.mechanical.docs.pyansys.com/version/dev/api/index.html +.. _Mechanical scripting interface APIs: https://developer.ansys.com/docs/mechanical-scripting-interface/api/index.md .. _ACT API Reference Guide: https://ansyshelp.ansys.com/account/secured?returnurl=/Views/Secured/corp/v242/en/act_ref/act_ref.html .. _Mechanical API known issues and limitations: https://ansyshelp.ansys.com/account/secured?returnurl=/Views/Secured/corp/%%VERSION%%/en/act_script/mech_apis_KIL.html?q=known%20issues .. _ACT known issues and limitations: https://ansyshelp.ansys.com/account/secured?returnurl=/Views/Secured/corp/%%VERSION%%/en/act_dev/act_dev_knownissues.html diff --git a/doc/source/user_guide_scripting/index.rst b/doc/source/user_guide_scripting/index.rst index 2280a98e7..808d51e95 100644 --- a/doc/source/user_guide_scripting/index.rst +++ b/doc/source/user_guide_scripting/index.rst @@ -23,8 +23,11 @@ You could already perform scripting of Mechanical with Python from inside Mechanical. PyMechanical leverages the same APIs but allows you to run your automation from outside Mechanical. -For comprehensive information on these APIs, see the `Scripting in Mechanical Guide`_ in the -Ansys Help. +.. note:: + + For comprehensive information on these APIs, see the `Scripting in Mechanical Guide`_ in the + Ansys Help portal, the `Mechanical scripting interface APIs`_ in the Developer Portal, or the + `Mechanical API Documentation`_. Recording --------- diff --git a/pyproject.toml b/pyproject.toml index 75fea8b83..d59d96e39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "flit_core.buildapi" [project] # Check https://flit.readthedocs.io/en/latest/pyproject_toml.html for all available sections name = "ansys-mechanical-core" -version = "0.11.9" +version = "0.11.10" description = "A python wrapper for Ansys Mechanical" readme = "README.rst" requires-python = ">=3.10,<4.0" @@ -51,23 +51,23 @@ Changelog = "https://mechanical.docs.pyansys.com/version/stable/changelog.html" [project.optional-dependencies] tests = [ "pytest==8.3.3", - "pytest-cov==5.0.0", + "pytest-cov==6.0.0", "pytest-print==1.0.2", "psutil==6.1.0" ] doc = [ "sphinx==8.1.3", - "ansys-sphinx-theme[autoapi]==1.1.7", - "grpcio==1.67.0", + "ansys-sphinx-theme[autoapi]==1.2.1", + "grpcio==1.68.0", "imageio-ffmpeg==0.5.1", "imageio==2.36.0", "jupyter_sphinx==0.5.3", "jupyterlab>=3.2.8", "matplotlib==3.9.2", - "numpy==2.1.2", + "numpy==2.1.3", "numpydoc==1.8.0", "pandas==2.2.3", - "panel==1.5.3", + "panel==1.5.4", "plotly==5.24.1", "pypandoc==1.14", "pytest-sphinx==0.6.3", diff --git a/src/ansys/mechanical/core/__init__.py b/src/ansys/mechanical/core/__init__.py index b16c3c325..d96a539db 100644 --- a/src/ansys/mechanical/core/__init__.py +++ b/src/ansys/mechanical/core/__init__.py @@ -50,6 +50,7 @@ from ansys.mechanical.core.mechanical import ( change_default_mechanical_path, close_all_local_instances, + connect_to_mechanical, get_mechanical_path, launch_mechanical, ) diff --git a/src/ansys/mechanical/core/embedding/app.py b/src/ansys/mechanical/core/embedding/app.py index 14f0aed1e..4efb85e48 100644 --- a/src/ansys/mechanical/core/embedding/app.py +++ b/src/ansys/mechanical/core/embedding/app.py @@ -137,6 +137,13 @@ def __init__(self, db_file=None, private_appdata=False, **kwargs): if len(INSTANCES) > 0: raise Exception("Cannot have more than one embedded mechanical instance!") version = kwargs.get("version") + if version is not None: + try: + version = int(version) + except ValueError: + raise ValueError( + f"The version must be an integer or that can be converted to an integer." + ) self._version = initializer.initialize(version) configuration = kwargs.get("config", _get_default_addin_configuration()) diff --git a/src/ansys/mechanical/core/mechanical.py b/src/ansys/mechanical/core/mechanical.py index ec4303152..55c7bc5fd 100644 --- a/src/ansys/mechanical/core/mechanical.py +++ b/src/ansys/mechanical/core/mechanical.py @@ -2242,3 +2242,86 @@ def launch_mechanical( raise exception return mechanical + + +def connect_to_mechanical( + ip=None, + port=None, + loglevel="ERROR", + log_file=False, + log_mechanical=None, + connect_timeout=120, + clear_on_connect=False, + cleanup_on_exit=False, + keep_connection_alive=True, +) -> Mechanical: + """Connect to an existing Mechanical server instance. + + Parameters + ---------- + ip : str, optional + IP address for connecting to an existing Mechanical instance. The + IP address defaults to ``"127.0.0.1"``. + port : int, optional + Port to listen on for an existing Mechanical instance. The default is ``None``, + in which case ``10000`` is used. You can override the + default behavior of this parameter with the + ``PYMECHANICAL_PORT=`` environment variable. + loglevel : str, optional + Level of messages to print to the console. + Options are: + + - ``"WARNING"``: Prints only Ansys warning messages. + - ``"ERROR"``: Prints only Ansys error messages. + - ``"INFO"``: Prints all Ansys messages. + + The default is ``WARNING``. + log_file : bool, optional + Whether to copy the messages to a file named ``logs.log``, which is + located where the Python script is executed. The default is ``False``. + log_mechanical : str, optional + Path to the output file on the local disk to write every script + command to. The default is ``None``. However, you might set + ``"log_mechanical='pymechanical_log.txt'"`` to write all commands that are + sent to Mechanical via PyMechanical to this file. You can then use these + commands to run a script within Mechanical without PyMechanical. + connect_timeout : float, optional + Maximum allowable time in seconds to connect to the Mechanical server. + The default is ``120``. + clear_on_connect : bool, optional + Whether to clear the Mechanical instance when connecting. The default is ``False``. + When ``True``, a fresh environment is provided when you connect to Mechanical. + cleanup_on_exit : bool, optional + Whether to exit Mechanical when Python exits. The default is ``False``. + When ``False``, Mechanical is not exited when the garbage for this Mechanical + instance is collected. + keep_connection_alive : bool, optional + Whether to keep the gRPC connection alive by running a background thread + and making dummy calls for remote connections. The default is ``True``. + + Returns + ------- + ansys.mechanical.core.mechanical.Mechanical + Instance of Mechanical. + + Examples + -------- + Connect to an existing Mechanical instance at IP address ``192.168.1.30`` on port + ``50001``.. + + + >>> from ansys.mechanical.core import connect_to_mechanical + >>> pymech = connect_to_mechanical(ip='192.168.1.30', port=50001) + """ + return launch_mechanical( + start_instance=False, + loglevel=loglevel, + log_file=log_file, + log_mechanical=log_mechanical, + start_timeout=connect_timeout, + port=port, + ip=ip, + clear_on_connect=clear_on_connect, + cleanup_on_exit=cleanup_on_exit, + keep_connection_alive=keep_connection_alive, + ) diff --git a/tests/conftest.py b/tests/conftest.py index dec82b8f3..74de05054 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -54,6 +54,8 @@ # Check if Mechanical is installed # NOTE: checks in this order to get the newest installed version +# Ignore functions starts with `test` from scripts folder +collect_ignore = ["scripts"] valid_rver = [str(each) for each in SUPPORTED_MECHANICAL_VERSIONS] @@ -277,7 +279,7 @@ def connect_to_mechanical_instance(port=None, clear_on_connect=False): # ip needs to be passed or start instance takes precedence # typical for container scenarios use connect # and needs to be treated as remote scenarios - mechanical = pymechanical.launch_mechanical( + mechanical = pymechanical.connect_to_mechanical( ip=hostname, port=port, clear_on_connect=clear_on_connect, cleanup_on_exit=False ) return mechanical diff --git a/tests/embedding/test_background.py b/tests/embedding/test_background.py index 6562a6f92..4c0c3176c 100644 --- a/tests/embedding/test_background.py +++ b/tests/embedding/test_background.py @@ -27,46 +27,26 @@ import pytest - -def _run_background_app_test_process( - rootdir: str, run_subprocess, pytestconfig, testname: str, pass_expected: bool = None -) -> typing.Tuple[bytes, bytes]: - """Run the process and return stdout and stderr after it finishes.""" - version = pytestconfig.getoption("ansys_version") - script = os.path.join(rootdir, "tests", "scripts", "background_app_test.py") - process, stdout, stderr = run_subprocess( - [sys.executable, script, version, testname], None, pass_expected - ) - return stdout, stderr - - -def _assert_success(stdout: str, pass_expected: bool) -> bool: - """Check whether the process ran to completion from its stdout - - Duplicate of the `_assert_success` function in test_logger.py - """ - - if pass_expected: - assert "@@success@@" in stdout - else: - assert "@@success@@" not in stdout +from .test_logger import _assert_success def _run_background_app_test( run_subprocess, rootdir: str, pytestconfig, testname: str, pass_expected: bool = True -) -> str: - """Test stderr logging using a subprocess. +) -> typing.Tuple[bytes, bytes]: + """Run the process and return stdout and stderr after it finishes.""" - Also ensure that the subprocess either passes or fails based on pass_expected + version = pytestconfig.getoption("ansys_version") + script = os.path.join(rootdir, "tests", "scripts", "background_app_test.py") - Returns the stderr of the subprocess as a string. - """ subprocess_pass_expected = pass_expected - if pass_expected == True and os.name != "nt": - subprocess_pass_expected = False - stdout, stderr = _run_background_app_test_process( - rootdir, run_subprocess, pytestconfig, testname, subprocess_pass_expected + if pass_expected and os.name != "nt": + if int(version) < 251 or testname == "multiple_instances": + subprocess_pass_expected = False + + process, stdout, stderr = run_subprocess( + [sys.executable, script, version, testname], None, subprocess_pass_expected ) + if not subprocess_pass_expected: stdout = stdout.decode() _assert_success(stdout, pass_expected) @@ -75,6 +55,7 @@ def _run_background_app_test( @pytest.mark.embedding_scripts +@pytest.mark.embedding_backgroundapp def test_background_app_multiple_instances(rootdir, run_subprocess, pytestconfig): """Multiple instances of background app can be used.""" stderr = _run_background_app_test( @@ -87,6 +68,7 @@ def test_background_app_multiple_instances(rootdir, run_subprocess, pytestconfig @pytest.mark.embedding_scripts +@pytest.mark.embedding_backgroundapp def test_background_app_use_stopped(rootdir, run_subprocess, pytestconfig): """Multiple instances of background app cannot be used after an instance is stopped.""" stderr = _run_background_app_test( @@ -96,6 +78,7 @@ def test_background_app_use_stopped(rootdir, run_subprocess, pytestconfig): @pytest.mark.embedding_scripts +@pytest.mark.embedding_backgroundapp def test_background_app_initialize_stopped(rootdir, run_subprocess, pytestconfig): """Multiple instances of background app cannot be used after an instance is stopped.""" stderr = _run_background_app_test( diff --git a/tests/embedding/test_logger.py b/tests/embedding/test_logger.py index 2b29d705c..239b5dcca 100644 --- a/tests/embedding/test_logger.py +++ b/tests/embedding/test_logger.py @@ -45,18 +45,31 @@ def _unset_var(env, var) -> None: return env -def _run_embedding_log_test_process( - rootdir: str, run_subprocess, pytestconfig, testname: str, pass_expected: bool = None +def _run_embedding_log_test( + run_subprocess, + rootdir: str, + pytestconfig, + testname: str, + pass_expected: bool = True, ) -> typing.Tuple[bytes, bytes]: """Runs the process and returns it after it finishes""" version = pytestconfig.getoption("ansys_version") embedded_py = os.path.join(rootdir, "tests", "scripts", "embedding_log_test.py") + + subprocess_pass_expected = pass_expected + if pass_expected == True and os.name != "nt" and int(version) < 251: + subprocess_pass_expected = False + process, stdout, stderr = run_subprocess( [sys.executable, embedded_py, version, testname], _get_env_without_logging_variables(), - pass_expected, + subprocess_pass_expected, ) - return stdout, stderr + if not subprocess_pass_expected: + stdout = stdout.decode() + _assert_success(stdout, pass_expected) + stderr = stderr.decode() + return stderr def _assert_success(stdout: str, pass_expected: bool) -> int: @@ -74,31 +87,8 @@ def _assert_success(stdout: str, pass_expected: bool) -> int: assert "@@success@@" not in stdout -def _run_embedding_log_test( - run_subprocess, rootdir: str, pytestconfig, testname: str, pass_expected: bool = True -) -> str: - """Test stderr logging using a subprocess. - - Also ensure that the subprocess either passes or fails based on pass_expected - Mechanical logging all goes into the process stderr at the C level, but capturing - that from python isn't possible because python's stderr stream isn't aware of content - that doesn't come from python (or its C/API) - - Returns the stderr - """ - subprocess_pass_expected = pass_expected - if pass_expected == True and os.name != "nt": - subprocess_pass_expected = False - stdout, stderr = _run_embedding_log_test_process( - rootdir, run_subprocess, pytestconfig, testname, subprocess_pass_expected - ) - stdout = stdout.decode() - stderr = stderr.decode() - _assert_success(stdout, pass_expected) - return stderr - - @pytest.mark.embedding_scripts +@pytest.mark.embedding_logging def test_logging_write_log_before_init(rootdir, run_subprocess, pytestconfig): """Test that an error is thrown when trying to log before initializing""" stderr = _run_embedding_log_test( @@ -108,28 +98,37 @@ def test_logging_write_log_before_init(rootdir, run_subprocess, pytestconfig): @pytest.mark.embedding_scripts +@pytest.mark.embedding_logging def test_logging_write_info_after_initialize_with_error_level( rootdir, run_subprocess, pytestconfig ): """Test that no output is written when an info is logged when configured at the error level.""" stderr = _run_embedding_log_test( - run_subprocess, rootdir, pytestconfig, "log_info_after_initialize_with_error_level" + run_subprocess, + rootdir, + pytestconfig, + "log_info_after_initialize_with_error_level", ) assert "0xdeadbeef" not in stderr @pytest.mark.parametrize("addin_configuration", ["Mechanical", "WorkBench"]) @pytest.mark.embedding_scripts +@pytest.mark.embedding_logging @pytest.mark.minimum_version(241) def test_addin_configuration(rootdir, run_subprocess, pytestconfig, addin_configuration): """Test that mechanical can start with both the Mechanical and WorkBench configuration.""" stderr = _run_embedding_log_test( - run_subprocess, rootdir, pytestconfig, f"log_configuration_{addin_configuration}" + run_subprocess, + rootdir, + pytestconfig, + f"log_configuration_{addin_configuration}", ) assert f"{addin_configuration} configuration!" in stderr @pytest.mark.embedding_scripts +@pytest.mark.embedding_logging def test_logging_write_error_after_initialize_with_info_level( rootdir, run_subprocess, pytestconfig ): @@ -141,11 +140,17 @@ def test_logging_write_error_after_initialize_with_info_level( @pytest.mark.embedding_scripts +@pytest.mark.embedding_logging def test_logging_level_before_and_after_initialization(rootdir, run_subprocess, pytestconfig): """Test logging level API before and after initialization.""" - stdout, stderr = _run_embedding_log_test_process( - rootdir, run_subprocess, pytestconfig, "log_check_can_log_message" + _run_embedding_log_test(run_subprocess, rootdir, pytestconfig, "log_check_can_log_message") + + +@pytest.mark.embedding_scripts +@pytest.mark.embedding_logging +def test_logging_all_level(rootdir, run_subprocess, pytestconfig): + """Test all logging level after initialization.""" + stderr = _run_embedding_log_test( + run_subprocess, rootdir, pytestconfig, "log_check_all_log_level" ) - stdout = stdout.decode() - stderr = stderr.decode() - _assert_success(stdout, True) + assert all(keyword in stderr for keyword in ["debug", "warning", "info", "error", "fatal"])