diff --git a/.ci/collect_mapdl_logs.sh b/.ci/collect_mapdl_logs.sh index 5e075ae096..57ce2bedaf 100755 --- a/.ci/collect_mapdl_logs.sh +++ b/.ci/collect_mapdl_logs.sh @@ -32,7 +32,8 @@ echo "Collecting docker run log..." cp log.txt ./"$LOG_NAMES"/log.txt || echo "MAPDL run docker log not found." echo "Copying docker launch log..." -cp mapdl_launch.log ./"$LOG_NAMES"/mapdl_launch.log || echo "MAPDL launch docker log not found." +cp mapdl_launch_0.log ./"$LOG_NAMES"/mapdl_launch_0.log || echo "MAPDL launch docker log not found." +cp mapdl_launch_1.log ./"$LOG_NAMES"/mapdl_launch_1.log || echo "MAPDL launch docker log not found." echo "Collecting file structure..." ls -R > ./"$LOG_NAMES"/files_structure.txt || echo "Failed to copy file structure to a file" diff --git a/.ci/start_mapdl.sh b/.ci/start_mapdl.sh index 8870e5fd81..68d028c4a4 100755 --- a/.ci/start_mapdl.sh +++ b/.ci/start_mapdl.sh @@ -13,7 +13,12 @@ export VERSION="$MAJOR$MINOR" echo "MAPDL VERSION: $VERSION" -if [[ $MAPDL_VERSION == *"ubuntu"* ]] ; then +if [[ $MAPDL_VERSION == *"latest-ubuntu"* ]]; then + echo "It is latest-ubuntu. Using 'ansys' script to launch" + export EXEC_PATH=ansys + # export P_SCHEMA=/ansys_inc/ansys/ac4/schema + +elif [[ $MAPDL_VERSION == *"ubuntu"* ]] ; then echo "It is an ubuntu based image" export EXEC_PATH=/ansys_inc/v$VERSION/ansys/bin/mapdl export P_SCHEMA=/ansys_inc/v$VERSION/ansys/ac4/schema @@ -40,7 +45,7 @@ docker run \ -e ANSYS_LOCK="OFF" \ -p "$PYMAPDL_PORT":50052 \ -p "$PYMAPDL_DB_PORT":50055 \ - --shm-size=1gb \ + --shm-size=2gb \ -e I_MPI_SHM_LMT=shm \ -e P_SCHEMA="$P_SCHEMA" \ -w /jobs \ diff --git a/.devcontainer/codespaces-dev/requirements.txt b/.devcontainer/codespaces-dev/requirements.txt index c01ce8f592..33ddaafc5c 100644 --- a/.devcontainer/codespaces-dev/requirements.txt +++ b/.devcontainer/codespaces-dev/requirements.txt @@ -1,5 +1,5 @@ ansys-dpf-core==0.10.1 -autopep8==2.0.4 +autopep8==2.1.0 matplotlib==3.8.3 scipy==1.12.0 pandas==2.2.1 diff --git a/.devcontainer/devcontainer-local/requirements.txt b/.devcontainer/devcontainer-local/requirements.txt index c01ce8f592..33ddaafc5c 100644 --- a/.devcontainer/devcontainer-local/requirements.txt +++ b/.devcontainer/devcontainer-local/requirements.txt @@ -1,5 +1,5 @@ ansys-dpf-core==0.10.1 -autopep8==2.0.4 +autopep8==2.1.0 matplotlib==3.8.3 scipy==1.12.0 pandas==2.2.1 diff --git a/.github/workflows/cache_cleaner.yml b/.github/workflows/cache_cleaner.yml index 7afa87ac59..89decf0584 100644 --- a/.github/workflows/cache_cleaner.yml +++ b/.github/workflows/cache_cleaner.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.2 - name: Cleanup PR caches if: github.event_name != 'workflow_dispatch' @@ -26,9 +26,15 @@ jobs: ## Setting this to not fail the workflow while deleting cache keys. set +e echo "Deleting caches..." - for cacheKey in $cacheKeysForPR + + while [ ! -z "$cacheKeysForPR" ]; do - gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm && echo "Deleting cache with key: $cacheKey" + for cacheKey in $cacheKeysForPR + do + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm && echo "Deleting cache with key: $cacheKey" + done + + cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) done echo "Done" env: @@ -48,9 +54,14 @@ jobs: ## Setting this to not fail the workflow while deleting cache keys. set +e echo "Deleting caches..." - for cacheKey in $cacheKeysForPR + while [ ! -z "$cacheKeysForPR" ]; do - gh actions-cache delete $cacheKey -R $REPO --confirm && echo "Deleting cache with key: $cacheKey" + for cacheKey in $cacheKeysForPR + do + gh actions-cache delete $cacheKey -R $REPO --confirm && echo "Deleting cache with key: $cacheKey" + done + + cacheKeysForPR=$(gh actions-cache list -R $REPO | cut -f 1 ) done echo "Done" env: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2cf711e97..4a9e77d8d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,10 +115,10 @@ jobs: ON_DOCUMENTATION: TRUE steps: - name: "Install Git and checkout project" - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.2 - name: "Login in Github container registry" - uses: docker/login-action@v3.0.0 + uses: docker/login-action@v3.1.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -290,22 +290,49 @@ jobs: strategy: fail-fast: false matrix: - mapdl-version: ['v22.2.1', 'v22.2-ubuntu', 'v23.1.0', 'v23.2.0', 'v24.1.0', 'v24.1-ubuntu-student'] + mapdl-version: [ + 'v22.2.1', + 'v22.2-ubuntu', + 'v23.1.0', + 'v23.1-ubuntu', + 'v23.2.0', + 'v23.2-ubuntu', + 'v24.1.0', + 'v24.1-ubuntu', + 'v24.1-ubuntu-student', + 'v24.2.0', + 'latest-ubuntu', + 'latest-ubuntu-student', + ] extended_testing: - ${{ github.event_name == 'schedule' || ( github.event_name == 'workflow_dispatch' && inputs.run_all_tests ) || ( github.event_name == 'push' && contains(github.ref, 'refs/tags') ) }} exclude: + # In PRs skipping all MAPDL version except student ones (commented out). - extended_testing: false mapdl-version: 'v22.2.1' - extended_testing: false mapdl-version: 'v22.2-ubuntu' - extended_testing: false mapdl-version: 'v23.1.0' + - extended_testing: false + mapdl-version: 'v23.1-ubuntu' - extended_testing: false mapdl-version: 'v23.2.0' - extended_testing: false - mapdl-version: 'v23.1.0' + mapdl-version: 'v23.2-ubuntu' - extended_testing: false mapdl-version: 'v24.1.0' + - extended_testing: false + mapdl-version: 'v24.1-ubuntu' + # - extended_testing: false + # mapdl-version: 'v24.1-ubuntu-student' + - extended_testing: false + mapdl-version: 'v24.2.0' + - extended_testing: false + mapdl-version: 'latest-ubuntu' + # - extended_testing: false + # mapdl-version: 'latest-ubuntu-student' + env: PYMAPDL_PORT: 21000 # default won't work on GitHub runners PYMAPDL_PORT2: 21001 # for the pool testing and default won't work on GitHub runners @@ -320,10 +347,10 @@ jobs: steps: - name: "Install Git and checkout project" - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.2 - name: "Login in Github container registry" - uses: docker/login-action@v3.0.0 + uses: docker/login-action@v3.1.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -482,7 +509,13 @@ jobs: strategy: fail-fast: false matrix: - mapdl-image: ['v23.2-ubuntu', 'v24.1-ubuntu', 'v24.1-ubuntu-student'] + mapdl-image: [ + 'v23.2-ubuntu', + 'v24.1-ubuntu', + 'v24.1-ubuntu-student', + 'latest-ubuntu', + 'latest-ubuntu-student', + ] extended_testing: - ${{ github.event_name == 'schedule' || ( github.event_name == 'workflow_dispatch' && inputs.run_all_tests ) || ( github.event_name == 'push' && contains(github.ref, 'refs/tags') ) }} exclude: @@ -490,6 +523,8 @@ jobs: mapdl-image: 'v23.2-ubuntu' - extended_testing: false mapdl-image: 'v24.1-ubuntu' + - extended_testing: false + mapdl-image: 'latest-ubuntu' container: image: ghcr.io/ansys/mapdl:${{ matrix.mapdl-image }} options: -u=0:0 --oom-kill-disable --memory=6656MB --memory-swap=16896MB --shm-size=1gb --entrypoint /bin/bash @@ -505,7 +540,7 @@ jobs: steps: - name: "Install Git and checkout project" - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.2 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} @@ -608,7 +643,13 @@ jobs: strategy: fail-fast: false matrix: - mapdl-image: ['v23.2-ubuntu', 'v24.1-ubuntu', 'v24.1-ubuntu-student'] + mapdl-image: [ + 'v23.2-ubuntu', + 'v24.1-ubuntu', + 'v24.1-ubuntu-student', + 'latest-ubuntu', + 'latest-ubuntu-student', + ] extended_testing: - ${{ github.event_name == 'schedule' || ( github.event_name == 'workflow_dispatch' && inputs.run_all_tests ) || ( github.event_name == 'push' && contains(github.ref, 'refs/tags') ) }} exclude: @@ -616,6 +657,8 @@ jobs: mapdl-image: 'v23.2-ubuntu' - extended_testing: false mapdl-image: 'v24.1-ubuntu' + - extended_testing: false + mapdl-image: 'latest-ubuntu' container: image: ghcr.io/ansys/mapdl:${{ matrix.mapdl-image }} options: -u=0:0 --oom-kill-disable --memory=6656MB --memory-swap=16896MB --shm-size=1gb --entrypoint /bin/bash @@ -629,7 +672,7 @@ jobs: steps: - name: "Install Git and checkout project" - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.2 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} @@ -665,7 +708,13 @@ jobs: run: | # Because there is no 'ansys-tools-path' we need to input the # executable path with the env var: PYMAPDL_MAPDL_EXEC. - version=$(echo "${{ matrix.mapdl-image }}" | head -c 5 | tail -c 4 | tr -d '.') + + if [[ "${{ matrix.mapdl-image }}" == *"latest-ubuntu"* ]] ; then + version="242" + else + version=$(echo "${{ matrix.mapdl-image }}" | head -c 5 | tail -c 4 | tr -d '.') + fi; + echo "$version" export PYMAPDL_MAPDL_EXEC=/ansys_inc/v"$version"/ansys/bin/ansys"$version" @@ -692,6 +741,7 @@ jobs: test-windows: + # Skipped if: github.repository == '' name: "Local: Build & test on Windows" runs-on: [self-hosted, Windows, pymapdl] @@ -700,7 +750,7 @@ jobs: ON_LOCAL: TRUE steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.1.2 # Skipping because it is installed locally. # - name: Setup Python @@ -826,7 +876,7 @@ jobs: needs: upload-docs-release steps: - name: "Install Git and clone project" - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.2 - name: "Install the package requirements" run: pip install -e . @@ -899,7 +949,7 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v1.0.0 + - uses: actions/checkout@v4.1.2 - name: "Set up Julia" uses: julia-actions/setup-julia@v1 with: diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index c9500aee61..e6a541d5c0 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -18,7 +18,7 @@ jobs: name: Syncer runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.1.2 - uses: micnncim/action-label-syncer@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/linkchecker.yml b/.github/workflows/linkchecker.yml index 499547b10d..280cd3a210 100644 --- a/.github/workflows/linkchecker.yml +++ b/.github/workflows/linkchecker.yml @@ -11,9 +11,9 @@ concurrency: env: ON_CI: True - DOCKER_PACKAGE: ghcr.io/ansys/mapdl - DOCKER_IMAGE_VERSION_DOCS_BUILD: v23.1.0 - MAIN_PYTHON_VERSION: '3.9' + MAPDL_PACKAGE: ghcr.io/ansys/mapdl + MAPDL_IMAGE_VERSION_DOCS_BUILD: v24.1.0 + MAIN_PYTHON_VERSION: '3.10' PYANSYS_OFF_SCREEN: True DPF_START_SERVER: False DPF_PORT: 21002 @@ -31,7 +31,30 @@ jobs: SHELLOPTS: "errexit:pipefail" steps: - name: "Install Git and checkout project" - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.2 + + - name: "Login in Github container registry" + uses: docker/login-action@v3.1.0 + with: + registry: ghcr.io + username: ${{ secrets.GH_USERNAME }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: "DPF server activation" + run: | + $(docker pull ghcr.io/ansys/dpf-core:22.2dev && docker run -d --name dpfserver -p ${{ env.DPF_PORT }}:50052 ghcr.io/ansys/dpf-core:22.2dev && echo "DPF Server active on port ${{ env.DPF_PORT }}.") & + + - name: "Pull, launch, and validate MAPDL service" + id: start_mapdl + env: + LICENSE_SERVER: ${{ secrets.LICENSE_SERVER }} + MAPDL_VERSION: ${{ env.MAPDL_IMAGE_VERSION_DOCS_BUILD }} + DISTRIBUTED_MODE: "dmp" + run: | + export INSTANCE_NAME=MAPDL + .ci/start_mapdl.sh &> mapdl_launch.log & export DOCKER_PID=$! + echo "Launching MAPDL service at PID: $DOCKER_PID" + echo "DOCKER_PID=$(echo $DOCKER_PID)" >> $GITHUB_OUTPUT - name: "Setup Python" uses: actions/setup-python@v5 @@ -53,19 +76,6 @@ jobs: pip install . xvfb-run python -c "from ansys.mapdl import core as pymapdl; print(pymapdl.Report())" - - name: "Login in Github container registry" - uses: docker/login-action@v3.0.0 - with: - registry: ghcr.io - username: ${{ secrets.GH_USERNAME }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: "Pull, launch, and validate MAPDL service" - run: .ci/start_mapdl.sh - env: - LICENSE_SERVER: ${{ secrets.LICENSE_SERVER }} - MAPDL_IMAGE: '${{ env.DOCKER_PACKAGE }}:${{ env.DOCKER_IMAGE_VERSION_DOCS_BUILD }}' - - name: "Retrieve PyMAPDL version" id: version run: | @@ -76,10 +86,9 @@ jobs: run: | pip install .[doc] - - name: "DPF server activation" + - name: "Waiting for the services to be up" run: | - docker pull ghcr.io/ansys/dpf-core:22.2dev - docker run -d --name dpfserver -p ${{ env.DPF_PORT }}:50052 ghcr.io/ansys/dpf-core:22.2dev && echo "DPF Server active on port ${{ env.DPF_PORT }}." + .ci/waiting_services.sh - name: LinkCheck run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ba14650f4b..cf467ac34a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: ) - repo: https://github.com/psf/black - rev: 24.2.0 # If version changes --> modify "blacken-docs" manually as well. + rev: 24.3.0 # If version changes --> modify "blacken-docs" manually as well. hooks: - id: black args: @@ -36,7 +36,7 @@ repos: rev: 1.16.0 hooks: - id: blacken-docs - additional_dependencies: [black==24.2.0] + additional_dependencies: [black==24.3.0] - repo: https://github.com/PyCQA/flake8 rev: 7.0.0 diff --git a/doc/source/api/pool.rst b/doc/source/api/pool.rst index 583b85a6ab..b9134852d7 100644 --- a/doc/source/api/pool.rst +++ b/doc/source/api/pool.rst @@ -8,4 +8,4 @@ Local MAPDL pool .. autosummary:: :toctree: _autosummary - pool.LocalMapdlPool + pool.MapdlPool diff --git a/doc/source/conf.py b/doc/source/conf.py index 14c62d0aad..b68de48c9e 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -212,6 +212,8 @@ "https://mapdl.docs.pyansys.com/*", "https://ansysaccount.b2clogin.com/*", # behind payfirewall "https://ansyshelp.ansys.com/*", # behind payfirewall + "https://forum.ansys.com/forums/*", # It is detected as broken + "https://courses.ansys.com/*", # It is detected as broken ] linkcheck_anchors_ignore = [ # these anchors are picked by linkcheck as broken but they are not. diff --git a/doc/source/user_guide/pool.rst b/doc/source/user_guide/pool.rst index d8e045acca..e520ba1b3c 100644 --- a/doc/source/user_guide/pool.rst +++ b/doc/source/user_guide/pool.rst @@ -3,7 +3,7 @@ Create a pool of MAPDL instances ================================ -PyMAPDL contains the :class:`LocalMapdlPool ` +PyMAPDL contains the :class:`MapdlPool ` class to simplify creating multiple local instances of the :class:`Mapdl ` class for batch processing. This can be used for the batch processing of a @@ -14,8 +14,8 @@ This code creates a pool: .. code:: pycon - >>> from ansys.mapdl.core import LocalMapdlPool - >>> pool = LocalMapdlPool(10) + >>> from ansys.mapdl.core import MapdlPool + >>> pool = MapdlPool(10) 'MAPDL Pool with 10 active instances' >>> pool.exit(block=True) @@ -27,7 +27,7 @@ at the current directory within their own isolated directories: >>> import os >>> my_path = os.getcmd() - >>> pool = LocalMapdlPool(10, nproc=1, run_location=my_path) + >>> pool = MapdlPool(10, nproc=1, run_location=my_path) Creating Pool: 100%|########| 10/10 [00:01<00:00, 1.43it/s] You can access each individual MAPDL instance with this code: @@ -46,7 +46,7 @@ Run a set of input files ------------------------ You can use the pool to run a set of pre-generated input files using the -:func:`run_batch ` method. For +:func:`run_batch ` method. For example, this code would run the first set of 20 verification files: .. code:: pycon @@ -63,7 +63,7 @@ Run a user function You can use the pool to run a custom user function on each MAPDL instance over a set of inputs. As in the example for the -:func:`run_batch ` function, +:func:`run_batch ` function, the following code uses a set of verification files. However, it implements it as a function and outputs the final routine instead of the text output from MAPDL. @@ -103,7 +103,7 @@ Close the PyMAPDL pool ---------------------- You can close the PyMAPDL pool with the -:meth:`pool.exit() ` command. +:meth:`pool.exit() ` command. .. code:: pycon diff --git a/minimum_requirements.txt b/minimum_requirements.txt index 716ad26a51..1d65119cae 100644 --- a/minimum_requirements.txt +++ b/minimum_requirements.txt @@ -1,5 +1,5 @@ ansys-api-mapdl==0.5.1 -importlib-metadata==7.0.2 +importlib-metadata==7.1.0 numpy==1.26.4 platformdirs==4.2.0 psutil==5.9.8 diff --git a/pyproject.toml b/pyproject.toml index 849493fdd6..57b5d43db4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,7 @@ jupyter = [ tests = [ "ansys-dpf-core==0.10.1", - "autopep8==2.0.4", + "autopep8==2.1.0", "matplotlib==3.8.3", "scipy==1.12.0", "pandas==2.2.1", diff --git a/src/ansys/mapdl/core/__init__.py b/src/ansys/mapdl/core/__init__.py index c041fb0962..aadc1dce2b 100644 --- a/src/ansys/mapdl/core/__init__.py +++ b/src/ansys/mapdl/core/__init__.py @@ -120,7 +120,7 @@ from ansys.mapdl.core.mapdl_grpc import MapdlGrpc as Mapdl from ansys.mapdl.core.misc import Information, Report, _check_has_ansys -from ansys.mapdl.core.pool import LocalMapdlPool +from ansys.mapdl.core.pool import MapdlPool from ansys.mapdl.core.theme import MapdlTheme, _apply_default_theme _HAS_ANSYS = _check_has_ansys() diff --git a/src/ansys/mapdl/core/_version.py b/src/ansys/mapdl/core/_version.py index 43f141899d..2b73beb61c 100644 --- a/src/ansys/mapdl/core/_version.py +++ b/src/ansys/mapdl/core/_version.py @@ -41,6 +41,7 @@ # In descending order SUPPORTED_ANSYS_VERSIONS = { + 242: "2024R2", 241: "2024R1", 232: "2023R2", 231: "2023R1", diff --git a/src/ansys/mapdl/core/cli.py b/src/ansys/mapdl/core/cli.py index c0400e645a..208df4033f 100644 --- a/src/ansys/mapdl/core/cli.py +++ b/src/ansys/mapdl/core/cli.py @@ -470,6 +470,10 @@ def start( + " The following argument is not allowed in CLI: 'license_server_check'.\nIgnoring argument." ) + # Ignoring env var if using CLI + if "PYMAPDL_START_INSTANCE" in os.environ: + os.environ.pop("PYMAPDL_START_INSTANCE") + out = launch_mapdl( exec_file=exec_file, just_launch=True, diff --git a/src/ansys/mapdl/core/database/database.py b/src/ansys/mapdl/core/database/database.py index 3323a664d1..5877af5f6e 100644 --- a/src/ansys/mapdl/core/database/database.py +++ b/src/ansys/mapdl/core/database/database.py @@ -37,6 +37,7 @@ from ..mapdl_grpc import MapdlGrpc MINIMUM_MAPDL_VERSION = "21.1" +FAILING_DATABASE_MAPDL = ["24.1", "24.2"] class WithinBeginLevel: @@ -236,9 +237,10 @@ def start(self, timeout=10): ) ## Checking MAPDL versions - mapdl_version = self._mapdl.version - if not server_meets_version( - str(mapdl_version), MINIMUM_MAPDL_VERSION + mapdl_version = str(self._mapdl.version) + if ( + not server_meets_version(mapdl_version, MINIMUM_MAPDL_VERSION) + or mapdl_version in FAILING_DATABASE_MAPDL ): # pragma: no cover from ansys.mapdl.core.errors import MapdlVersionError diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index fd091ae04e..82c91a9ffb 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -221,7 +221,7 @@ def port_in_use(port: Union[int, str], host: str = LOCALHOST) -> bool: def port_in_use_using_socket(port: Union[int, str], host: str) -> bool: - """Returns True when a port is in use at the given host using socket librry. + """Returns True when a port is in use at the given host using socket library. Must actually "bind" the address. Just checking if we can create a socket is insufficient as it's possible to run into permission @@ -283,7 +283,6 @@ def launch_grpc( ram: Optional[int] = None, run_location: str = None, port: int = MAPDL_DEFAULT_PORT, - ip: str = LOCALHOST, additional_switches: str = "", override: bool = True, timeout: int = 20, @@ -599,7 +598,9 @@ def launch_grpc( env_vars = update_env_vars(add_env_vars, replace_env_vars) - LOG.info(f"Running in {ip}:{port} the following command: '{command}'") + LOG.info( + f"Running a local instance at port {port} the following command: '{command}'" + ) LOG.debug("MAPDL starting in background.") process = subprocess.Popen( @@ -802,9 +803,19 @@ def get_start_instance(start_instance: bool = True): Raised when ``PYMAPDL_START_INSTANCE`` is not either true or false (case independent). + Notes + ----- + If the environment variable ``PYMAPDL_START_INSTANCE`` is set, + hence the argument ``start_instance`` is overwritten. + """ if "PYMAPDL_START_INSTANCE" in os.environ and os.environ["PYMAPDL_START_INSTANCE"]: # It should not be empty + if isinstance(start_instance, bool): + warnings.warn( + "The environment variable 'PYMAPDL_START_INSTANCE' is set, " + "hence the argument 'start_instance' is overwritten." + ) start_instance = os.environ["PYMAPDL_START_INSTANCE"] else: LOG.debug( @@ -1167,13 +1178,14 @@ def launch_mapdl( ip : bool, optional Used only when ``start_instance`` is ``False``. If provided, - it will force ``start_instance`` to be ``False``. + and ``start_instance`` (or its correspondent environment variable + ``PYMAPDL_START_INSTANCE``) is ``True`` then, an exception is raised. Specify the IP address of the MAPDL instance to connect to. You can also provide a hostname as an alternative to an IP address. Defaults to ``'127.0.0.1'``. You can also override the default behavior of this keyword argument with the - environment variable ``PYMAPDL_IP=``. - This argument has priority over the environment variable. + environment variable ``PYMAPDL_IP=``. If this environment variable + is empty, it is as it is not set. clear_on_connect : bool, optional Defaults to ``True``, giving you a fresh environment when @@ -1507,8 +1519,28 @@ def launch_mapdl( ms_ = ", ".join([f"'{each}'" for each in kwargs.keys()]) raise ValueError(f"The following arguments are not recognized: {ms_}") - if ip is None: - ip = os.environ.get("PYMAPDL_IP", None) + # Getting IP from env var + ip_env_var = os.environ.get("PYMAPDL_IP", "") + if ip_env_var != "": + if ip: + warnings.warn( + "The env var 'PYMAPDL_IP' is set, hence the 'ip' argument is overwritten." + ) + + ip = ip_env_var + LOG.debug(f"An IP ({ip}) has been set using 'PYMAPDL_IP' env var.") + + ip = None if ip == "" else ip # Making sure the variable is not empty + + # Getting "start_instance" using "True" as default. + if (ip is not None) and (start_instance is None): + # An IP has been supplied. By default, 'start_instance' is equal + # false, unless it is set through the env vars. + start_instance = get_start_instance(start_instance=False) + else: + start_instance = get_start_instance(start_instance=start_instance) + + LOG.debug("Using 'start_instance' equal to %s.", start_instance) if ip is None: if ON_WSL: @@ -1518,8 +1550,9 @@ def launch_mapdl( f"On WSL: Using the following IP address for the Windows OS host: {ip}" ) else: - LOG.debug( - "PyMAPDL could not find the IP address of the Windows host machine." + raise MapdlDidNotStart( + "You seems to be working from WSL.\n" + "Unfortunately, PyMAPDL could not find the IP address of the Windows host machine." ) if not ip: @@ -1533,10 +1566,17 @@ def launch_mapdl( "Because 'PYMAPDL_IP' is not None, an attempt is made to connect to" " a remote session ('START_INSTANCE' is set to 'False')." ) - if not ON_WSL: - start_instance = False - else: + if ON_WSL: LOG.debug("On WSL: Allowing 'start_instance' and 'ip' arguments together.") + else: + if start_instance is True: + raise ValueError( + "When providing a value for the argument 'ip', the argument " + "'start_instance' cannot be 'True'.\n" + "Make sure the corresponding environment variables are not setting " + "those argument values.\n" + "For more information visit https://github.com/ansys/pymapdl/issues/2910" + ) ip = socket.gethostbyname(ip) # Converting ip or hostname to ip @@ -1567,10 +1607,6 @@ def launch_mapdl( version = _verify_version(version) # return a int version or none - # Getting "start_instance" using "True" as default. - start_instance = get_start_instance(start_instance=start_instance) - LOG.debug("Using 'start_instance' equal to %s.", start_instance) - if start_instance: # special handling when building the gallery outside of CI. This # creates an instance of mapdl the first time. @@ -1579,6 +1615,8 @@ def launch_mapdl( # launch an instance of pymapdl if it does not already exist and # we're allowed to start instances if GALLERY_INSTANCE[0] is None: + LOG.debug("Loading first MAPDL instance for gallery building.") + GALLERY_INSTANCE[0] = "Loading..." mapdl = launch_mapdl( start_instance=True, cleanup_on_exit=False, @@ -1589,8 +1627,11 @@ def launch_mapdl( GALLERY_INSTANCE[0] = {"ip": mapdl._ip, "port": mapdl._port} return mapdl - # otherwise, connect to the existing gallery instance if available - elif GALLERY_INSTANCE[0] is not None: + # otherwise, connect to the existing gallery instance if available, but it needs to be fully loaded. + elif GALLERY_INSTANCE[0] != "Loading...": + LOG.debug( + "Connecting to an existing MAPDL instance for gallery building." + ) mapdl = MapdlGrpc( ip=GALLERY_INSTANCE[0]["ip"], port=GALLERY_INSTANCE[0]["port"], @@ -1604,6 +1645,9 @@ def launch_mapdl( mapdl.clear() return mapdl + else: + LOG.debug("Bypassing Gallery building flag for the first time.") + else: LOG.debug("Connecting to an existing instance of MAPDL at %s:%s", ip, port) @@ -1611,9 +1655,6 @@ def launch_mapdl( print(f"There is an existing MAPDL instance at: {ip}:{port}") return - if pymapdl.BUILDING_GALLERY: # pragma: no cover - LOG.debug("Building gallery.") - if _debug_no_launch: return pack_parameters( port, @@ -1656,7 +1697,11 @@ def launch_mapdl( LOG.debug("Using default executable.") # Load cached path - exec_file = get_ansys_path(version=version) if not _debug_no_launch else "" + if _debug_no_launch: + exec_file = "" + else: + exec_file = get_ansys_path(version=version) + if exec_file is None: raise FileNotFoundError( "Invalid exec_file path or cannot load cached " @@ -1787,7 +1832,6 @@ def launch_mapdl( port, actual_run_location, process = launch_grpc( port=port, - ip=ip, add_env_vars=add_env_vars, replace_env_vars=replace_env_vars, **start_parm, diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index 126264f68f..42c1f1dedb 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -34,7 +34,6 @@ import tempfile import time from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Tuple, Union -import warnings from warnings import warn import weakref @@ -57,6 +56,7 @@ from ansys.mapdl.core.errors import ( ComponentNoData, MapdlCommandIgnoredError, + MapdlFileNotFoundError, MapdlInvalidRoutineError, MapdlRuntimeError, ) @@ -1977,7 +1977,7 @@ def run_multiline(self, commands) -> str: """ - warnings.warn( + warn( "'run_multiline()' is being deprecated in future versions.\n Please use 'input_strings'.", DeprecationWarning, ) @@ -2678,7 +2678,13 @@ def _perform_entity_list_selection( def _raise_errors(self, text): # to make sure the following error messages are caught even if a breakline is in between. flat_text = " ".join([each.strip() for each in text.splitlines()]) - base_error_msg = "\n\nIgnore these messages by setting 'ignore_errors'=True" + base_error_msg = "\n\nIgnore these messages by setting 'ignore_errors'=True.\n" + + if "unable to open file" in flat_text or ( + "unable to open" in flat_text and "file" in flat_text + ): + text += base_error_msg + raise MapdlFileNotFoundError(text) if "is not a recognized" in flat_text: text = text.replace("This command will be ignored.", "") @@ -2706,10 +2712,15 @@ def _raise_errors(self, text): if "For element type = " in flat_text and "is invalid." in flat_text: if "is normal behavior when a CDB file is used." in flat_text: - warn(text) + warn(text, UserWarning) else: + text += base_error_msg raise MapdlCommandIgnoredError(text) + if "Cannot create another with the same name" in flat_text: + # When overriding constitutive models. See 'test_tbft' + warn(text, UserWarning) + # flag errors if "*** ERROR ***" in flat_text: self._raise_output_errors(text) diff --git a/src/ansys/mapdl/core/mapdl_extended.py b/src/ansys/mapdl/core/mapdl_extended.py index 9a27e6a8cf..fe18ae9adf 100644 --- a/src/ansys/mapdl/core/mapdl_extended.py +++ b/src/ansys/mapdl/core/mapdl_extended.py @@ -1352,7 +1352,7 @@ def inquire(self, strarray="", func="", arg1="", arg2=""): "RSTFILE", "RSTEXT", "OUTPUT", - "ENVNAME", + "ENV", "TITLE", "EXIST", "DATE", diff --git a/src/ansys/mapdl/core/pool.py b/src/ansys/mapdl/core/pool.py index a8741c418c..b3f29ae45d 100755 --- a/src/ansys/mapdl/core/pool.py +++ b/src/ansys/mapdl/core/pool.py @@ -71,7 +71,7 @@ def available_ports(n_ports: int, starting_port: int = MAPDL_DEFAULT_PORT) -> Li return ports -class LocalMapdlPool: +class MapdlPool: """Create a pool of MAPDL instances. .. note:: @@ -133,8 +133,8 @@ class LocalMapdlPool: Simply create a pool of 10 instances to run in the temporary directory. - >>> from ansys.mapdl.core import LocalMapdlPool - >>> pool = LocalMapdlPool(10) + >>> from ansys.mapdl.core import MapdlPool + >>> pool = MapdlPool(10) Creating Pool: 100%|########| 10/10 [00:01<00:00, 1.43it/s] Create several instances with 1 CPU each running at the current @@ -142,19 +142,19 @@ class LocalMapdlPool: >>> import os >>> my_path = os.getcmd() - >>> pool = LocalMapdlPool(10, nproc=1, run_location=my_path) + >>> pool = MapdlPool(10, nproc=1, run_location=my_path) Creating Pool: 100%|########| 10/10 [00:01<00:00, 1.43it/s] Create a pool while specifying the MAPDL executable in Windows. >>> exec_file = 'C:/Program Files/ANSYS Inc/v212/ansys/bin/winx64/ANSYS212.exe' - >>> pool = LocalMapdlPool(10, exec_file=exec_file) + >>> pool = MapdlPool(10, exec_file=exec_file) Creating Pool: 100%|########| 10/10 [00:01<00:00, 1.43it/s] Create a pool while specifying the MAPDL executable in Linux. >>> exec_file = '/ansys_inc/v211/ansys/bin/ansys211' - >>> pool = LocalMapdlPool(10, exec_file=exec_file) + >>> pool = MapdlPool(10, exec_file=exec_file) Creating Pool: 100%|########| 10/10 [00:01<00:00, 1.43it/s] """ @@ -230,7 +230,7 @@ def __init__( # Checking version if _HAS_ATP: if version_from_path("mapdl", exec_file) < 211: - raise VersionError("LocalMapdlPool requires MAPDL 2021R1 or later.") + raise VersionError("MapdlPool requires MAPDL 2021R1 or later.") self._exec_file = exec_file diff --git a/tests/common.py b/tests/common.py index ebb65b315d..29f0eb492c 100644 --- a/tests/common.py +++ b/tests/common.py @@ -104,7 +104,7 @@ def has_grpc(): def has_dpf(): - return os.environ.get("DPF_PORT", "") + return bool(os.environ.get("DPF_PORT", "")) def is_smp(): diff --git a/tests/conftest.py b/tests/conftest.py index ed3096d3c0..08c5fa1966 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,6 +23,7 @@ from collections import namedtuple import os from pathlib import Path +from shutil import get_terminal_size from sys import platform from _pytest.terminal import TerminalReporter # for terminal customization @@ -204,7 +205,12 @@ def requires_dependency(dependency: str): pymapdl.RUNNING_TESTS = True -from ansys.mapdl.core.errors import MapdlExitedError, MapdlRuntimeError +from ansys.mapdl.core import Mapdl +from ansys.mapdl.core.errors import ( + MapdlConnectionError, + MapdlExitedError, + MapdlRuntimeError, +) from ansys.mapdl.core.examples import vmfiles from ansys.mapdl.core.launcher import get_start_instance, launch_mapdl @@ -238,6 +244,38 @@ def requires_dependency(dependency: str): raise MapdlRuntimeError(ERRMSG) +@pytest.hookimpl(trylast=True) +def pytest_report_header(config, start_path, startdir): + text = [] + text += ["Testing variables".center(get_terminal_size()[0], "-")] + text += [ + f"Session dependent: ON_CI ({ON_CI}), TESTING_MINIMAL ({TESTING_MINIMAL}), SUPPORT_PLOTTING ({SUPPORT_PLOTTING})" + ] + text += [ + f"OS dependent: ON_LINUX ({ON_LINUX}), ON_UBUNTU ({ON_UBUNTU}), ON_WINDOWS ({ON_WINDOWS}), ON_MACOS )({ON_MACOS})" + ] + text += [ + f"MAPDL dependent: ON_LOCAL ({ON_LOCAL}), ON_STUDENT ({ON_STUDENT}), HAS_GRPC ({HAS_GRPC}), HAS_DPF ({HAS_DPF}), IS_SMP ({IS_SMP})" + ] + + text += ["Environment variables".center(get_terminal_size()[0], "-")] + line = "" + for env_var in [ + "PYMAPDL_START_INSTANCE", + "PYMAPDL_PORT", + "PYMAPDL_DB_PORT", + "PYMAPDL_IP", + "DPF_PORT", + "DPF_START_SERVER", + ]: + env_var_value = os.environ.get(env_var, None) + if env_var_value is not None: + line += f"{env_var} ('{env_var_value}'), " + text += [line] + text += ["Pytest configuration".center(get_terminal_size()[0], "-")] + return "\n".join(text) + + ## Changing report line length class MyReporter(TerminalReporter): def short_test_summary(self): @@ -373,26 +411,32 @@ def is_exited(mapdl): except MapdlExitedError: return True - if START_INSTANCE and is_exited(mapdl): + if START_INSTANCE and (is_exited(mapdl) or mapdl._exited): # Backing up the current local configuration local_ = mapdl._local - - # Relaunching MAPDL - mapdl_ = launch_mapdl( - port=mapdl._port, - override=True, - run_location=mapdl._path, - cleanup_on_exit=mapdl._cleanup, - ) - - # Cloning the new mapdl instance channel into the old one. - mapdl._channel = mapdl_._channel - mapdl._multi_connect(timeout=mapdl._timeout) + channel = mapdl._channel + ip = mapdl.ip + port = mapdl.port + try: + # to connect + mapdl = Mapdl(port=port, ip=ip) + + except MapdlConnectionError as err: + # we cannot connect. + # Kill the instance + mapdl.exit() + + # Relaunching MAPDL + mapdl = launch_mapdl( + port=mapdl._port, + override=True, + run_location=mapdl._path, + cleanup_on_exit=mapdl._cleanup, + ) # Restoring the local configuration mapdl._local = local_ - mapdl.gopr() yield # this is where the testing happens # Teardown : fill with any logic you want diff --git a/tests/test_cli.py b/tests/test_cli.py index 9fd8b55602..12200c0e9d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -54,11 +54,18 @@ def do_run(arguments=""): @requires("click") @requires("local") @requires("nostudent") -def test_launch_mapdl_cli(run_cli): - output = run_cli() +@pytest.mark.parametrize("start_instance", [None, True, False]) +def test_launch_mapdl_cli(monkeypatch, run_cli, start_instance): + if start_instance is not None: + monkeypatch.setenv("PYMAPDL_START_INSTANCE", str(start_instance)) + else: + monkeypatch.delenv("PYMAPDL_START_INSTANCE", raising=False) + + # Setting a port so it does not collide with the already running instance for testing + output = run_cli("start --port 50053") - # In local assert "Success: Launched an MAPDL instance " in output + assert "50053" in output # grab ips and port pid = int(re.search(r"\(PID=(\d+)\)", output).groups()[0]) @@ -127,26 +134,26 @@ def test_launch_mapdl_cli_config(run_cli): @requires("nostudent") def test_launch_mapdl_cli_list(run_cli): output = run_cli("list") - assert "running" in output + assert "running" in output or "sleeping" in output assert "Is Instance" in output assert len(output.splitlines()) > 2 assert "ansys" in output.lower() or "mapdl" in output.lower() output = run_cli("list -i") - assert "running" in output + assert "running" in output or "sleeping" in output assert "Is Instance" not in output assert len(output.splitlines()) > 2 assert "ansys" in output.lower() or "mapdl" in output.lower() output = run_cli("list -c") - assert "running" in output + assert "running" in output or "sleeping" in output assert "Command line" in output assert "Is Instance" in output assert len(output.splitlines()) > 2 assert "ansys" in output.lower() or "mapdl" in output.lower() output = run_cli("list -cwd") - assert "running" in output + assert "running" in output or "sleeping" in output assert "Command line" not in output assert "Working directory" in output assert "Is Instance" in output @@ -154,7 +161,7 @@ def test_launch_mapdl_cli_list(run_cli): assert "ansys" in output.lower() or "mapdl" in output.lower() output = run_cli("list -l") - assert "running" in output + assert "running" in output or "sleeping" in output assert "Is Instance" in output assert "Command line" in output assert len(output.splitlines()) > 2 diff --git a/tests/test_database.py b/tests/test_database.py index fe24c729d7..f045af90d8 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -28,7 +28,8 @@ ## Checking MAPDL versions from ansys.mapdl.core.database import MINIMUM_MAPDL_VERSION, DBDef, MapdlDb -from ansys.mapdl.core.errors import MapdlRuntimeError +from ansys.mapdl.core.database.database import FAILING_DATABASE_MAPDL +from ansys.mapdl.core.errors import MapdlRuntimeError, MapdlVersionError from ansys.mapdl.core.misc import random_string from conftest import ON_CI @@ -56,7 +57,7 @@ def db(mapdl): f"This MAPDL version ({mapdl_version}) docker image seems to not support DB, but local does." ) - if mapdl_version == "24.1": + if mapdl_version == "24.1" or mapdl_version == "24.2": pytest.skip( f"This MAPDL version ({mapdl_version}) does not support PyMAPDL Database." ) @@ -72,6 +73,14 @@ def db(mapdl): return mapdl.db +def test_failure_on_non_allowed_versions(mapdl): + if str(mapdl.version) in ["24.1", "24.2"]: + with pytest.raises(MapdlVersionError): + mapdl.db.start() + else: + pytest.skip(f"Should run only on MAPDL 24.1 and 24.2") + + @pytest.fixture(scope="session") def gen_block(mapdl): """Generate nodes and elements in a simple block.""" @@ -109,6 +118,11 @@ def test_database_start_stop(mapdl): f"This MAPDL version ({mapdl_version}) docker image seems to not support DB, but local does." ) + if mapdl_version in FAILING_DATABASE_MAPDL: + pytest.skip( + f"This MAPDL version ({mapdl_version}) docker image does not support Database module." + ) + # verify it can be created twice mapdl.prep7() for _ in range(2): diff --git a/tests/test_examples.py b/tests/test_examples.py index 3f1fe09998..723b417b7b 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -164,28 +164,33 @@ def test_download_tech_demo_data(running_test): @requires("requests") def test_detach_examples_submodule(): - cmd = """ + cmd = ( + """ import sys -assert "ansys.mapdl.core" not in sys.modules -assert "requests" not in sys.modules -assert "ansys.mapdl.core.examples" not in sys.modules +assert 'ansys.mapdl.core' not in sys.modules +assert 'requests' not in sys.modules +assert 'ansys.mapdl.core.examples' not in sys.modules from ansys.mapdl import core as pymapdl -assert "ansys.mapdl.core" in sys.modules -assert "ansys.mapdl.core.examples" not in sys.modules -assert "requests" not in sys.modules +assert 'ansys.mapdl.core' in sys.modules +assert 'ansys.mapdl.core.examples' not in sys.modules +assert 'requests' not in sys.modules from ansys.mapdl.core.examples import vmfiles -assert "ansys.mapdl.core.examples" in sys.modules -assert "requests" in sys.modules +assert 'ansys.mapdl.core.examples' in sys.modules +assert 'requests' in sys.modules -print("Everything went well") -""" +print('Everything went well') +""".strip() + .replace("\n", ";") + .replace(";;", ";") + ) + + cmd_line = f"""python -c "{cmd}" """ - cmd_line = f"""python -c '{cmd}' """ p = Popen(cmd_line, shell=True, stdout=PIPE, stderr=STDOUT) out = p.communicate()[0].decode() diff --git a/tests/test_launcher.py b/tests/test_launcher.py index d2f06a0eb1..780b337ba5 100644 --- a/tests/test_launcher.py +++ b/tests/test_launcher.py @@ -25,6 +25,7 @@ import os import tempfile from time import sleep +import warnings import psutil import pytest @@ -38,6 +39,7 @@ PortAlreadyInUseByAnMAPDLInstance, ) from ansys.mapdl.core.launcher import ( + LOCALHOST, _check_license_argument, _force_smp_student_version, _is_ubuntu, @@ -182,20 +184,21 @@ def test_launch_console(version): @requires("local") @requires("nostudent") -def test_license_type_keyword(): +def test_license_type_keyword(mapdl): checks = [] for license_name, license_description in LICENSES.items(): try: - mapdl = launch_mapdl( + mapdl_ = launch_mapdl( license_type=license_name, start_timeout=start_timeout, + port=mapdl.port + 1, additional_switches=QUICK_LAUNCH_SWITCHES, ) # Using first line to ensure not picking up other stuff. - checks.append(license_description in mapdl.__str__().split("\n")[0]) - mapdl.exit() - del mapdl + checks.append(license_description in mapdl_.__str__().split("\n")[0]) + mapdl_.exit() + del mapdl_ sleep(2) except MapdlDidNotStart as e: @@ -209,43 +212,45 @@ def test_license_type_keyword(): @requires("local") @requires("nostudent") -def test_license_type_keyword_names(): +def test_license_type_keyword_names(mapdl): # This test might became a way to check available licenses, which is not the purpose. successful_check = False for license_name, license_description in LICENSES.items(): - mapdl = launch_mapdl( + mapdl_ = launch_mapdl( license_type=license_name, start_timeout=start_timeout, + port=mapdl.port + 1, additional_switches=QUICK_LAUNCH_SWITCHES, ) # Using first line to ensure not picking up other stuff. successful_check = ( - license_description in mapdl.__str__().split("\n")[0] or successful_check + license_description in mapdl_.__str__().split("\n")[0] or successful_check ) - assert license_description in mapdl.__str__().split("\n")[0] - mapdl.exit() + assert license_description in mapdl_.__str__().split("\n")[0] + mapdl_.exit() assert successful_check # if at least one license is ok, this should be true. @requires("local") @requires("nostudent") -def test_license_type_additional_switch(): +def test_license_type_additional_switch(mapdl): # This test might became a way to check available licenses, which is not the purpose. successful_check = False for license_name, license_description in LICENSES.items(): - mapdl = launch_mapdl( + mapdl_ = launch_mapdl( additional_switches=QUICK_LAUNCH_SWITCHES + " -p " + license_name, start_timeout=start_timeout, + port=mapdl.port + 1, ) # Using first line to ensure not picking up other stuff. successful_check = ( - license_description in mapdl.__str__().split("\n")[0] or successful_check + license_description in mapdl_.__str__().split("\n")[0] or successful_check ) - mapdl.exit() + mapdl_.exit() assert successful_check # if at least one license is ok, this should be true. @@ -266,7 +271,7 @@ def test_license_type_dummy(mapdl): @requires("nostudent") def test_remove_temp_files(mapdl): """Ensure the working directory is removed when run_location is not set.""" - mapdl = launch_mapdl( + mapdl_ = launch_mapdl( port=mapdl.port + 1, remove_temp_files=True, start_timeout=start_timeout, @@ -274,8 +279,8 @@ def test_remove_temp_files(mapdl): ) # possible MAPDL is installed but running in "remote" mode - path = mapdl.directory - mapdl.exit() + path = mapdl_.directory + mapdl_.exit() tmp_dir = tempfile.gettempdir() ans_temp_dir = os.path.join(tmp_dir, "ansys_") @@ -289,17 +294,17 @@ def test_remove_temp_files(mapdl): @requires("nostudent") def test_remove_temp_files_fail(tmpdir, mapdl): """Ensure the working directory is not removed when the cwd is changed.""" - mapdl = launch_mapdl( + mapdl_ = launch_mapdl( port=mapdl.port + 1, remove_temp_files=True, start_timeout=start_timeout, additional_switches=QUICK_LAUNCH_SWITCHES, ) - old_path = mapdl.directory + old_path = mapdl_.directory assert os.path.isdir(str(tmpdir)) - mapdl.cwd(str(tmpdir)) - path = mapdl.directory - mapdl.exit() + mapdl_.cwd(str(tmpdir)) + path = mapdl_.directory + mapdl_.exit() assert os.path.isdir(path) # Checking no changes in the old path @@ -753,3 +758,82 @@ def test_launcher_start_instance(monkeypatch, start_instance): monkeypatch.delenv("PYMAPDL_START_INSTANCE") options = launch_mapdl(start_instance=start_instance, _debug_no_launch=True) assert start_instance == options["start_instance"] + + +@pytest.mark.parametrize("start_instance", [None, True, False]) +@pytest.mark.parametrize("start_instance_envvar", [None, True, False]) +@pytest.mark.parametrize("ip", [None, "", "123.1.1.1"]) +@pytest.mark.parametrize("ip_envvar", [None, "", "123.1.1.1"]) +def test_ip_and_start_instance( + monkeypatch, start_instance, start_instance_envvar, ip, ip_envvar +): + # start_instance=False + # start_instance_envvar=True + # ip="" + # ip_envvar="123.1.1.1" + + # For more information, visit https://github.com/ansys/pymapdl/issues/2910 + if "PYMAPDL_START_INSTANCE" in os.environ: + monkeypatch.delenv("PYMAPDL_START_INSTANCE") + + if start_instance_envvar is not None: + monkeypatch.setenv("PYMAPDL_START_INSTANCE", str(start_instance_envvar)) + if ip_envvar is not None: + monkeypatch.setenv("PYMAPDL_IP", str(ip_envvar)) + + start_instance_is_true = start_instance_envvar is True or ( + start_instance_envvar is None and (start_instance is True) + ) + + ip_is_true = bool(ip_envvar) or ( + (ip_envvar is None or ip_envvar == "") and bool(ip) + ) + + exceptions = start_instance_envvar is None and start_instance is None and ip_is_true + + if (start_instance_is_true and ip_is_true) and not exceptions: + with pytest.raises( + ValueError, + match="When providing a value for the argument 'ip', the argument ", + ): + options = launch_mapdl( + start_instance=start_instance, ip=ip, _debug_no_launch=True + ) + + return # Exit + + if ( + isinstance(start_instance_envvar, bool) and isinstance(start_instance, bool) + ) or (ip_envvar and ip): + with pytest.warns(UserWarning): + options = launch_mapdl( + start_instance=start_instance, ip=ip, _debug_no_launch=True + ) + else: + with warnings.catch_warnings(): + options = launch_mapdl( + start_instance=start_instance, ip=ip, _debug_no_launch=True + ) + + if start_instance_envvar is True: + assert options["start_instance"] is True + elif start_instance_envvar is False: + assert options["start_instance"] is False + else: + if start_instance is None: + if ip_envvar or bool(ip): + assert not options["start_instance"] + else: + assert options["start_instance"] + elif start_instance is True: + assert options["start_instance"] + else: + assert not options["start_instance"] + + if ip_envvar: + assert options["ip"] == ip_envvar + else: + if ip: + assert options["ip"] == ip + else: + assert options["ip"] in (LOCALHOST, "0.0.0.0") diff --git a/tests/test_licensing.py b/tests/test_licensing.py index def8e3a383..2e77a80e98 100644 --- a/tests/test_licensing.py +++ b/tests/test_licensing.py @@ -182,20 +182,21 @@ def test_license_checker(tmpdir, license_checker): @requires("local") @skip_no_lic_bin -def test_check_license_file(tmpdir): +def test_check_license_file(mapdl, tmpdir): timeout = 15 checker = licensing.LicenseChecker(timeout=timeout) # start the license check in the background checker.start(checkout_license=False) try: - mapdl = launch_mapdl( + mapdl_ = launch_mapdl( license_server_check=False, start_timeout=timeout, additional_switches=QUICK_LAUNCH_SWITCHES, + port=mapdl.port + 1, ) - assert mapdl._local - mapdl.exit() + assert mapdl_._local + mapdl_.exit() except IOError: # MAPDL never started assert not checker._license_file_success else: diff --git a/tests/test_mapdl.py b/tests/test_mapdl.py index f013bfd04c..60337e23a3 100644 --- a/tests/test_mapdl.py +++ b/tests/test_mapdl.py @@ -1266,6 +1266,7 @@ def test_get_file_path(mapdl, tmpdir): assert fobject not in mapdl.list_files() assert fobject not in os.listdir() + prev = mapdl._local mapdl._local = True fname_ = mapdl._get_file_path(fobject) assert fname in fname_ @@ -1277,6 +1278,8 @@ def test_get_file_path(mapdl, tmpdir): # If we are not in local, now it should have been uploaded assert fname in mapdl.list_files() + mapdl._local = prev + @pytest.mark.parametrize( "option2,option3,option4", @@ -1286,7 +1289,7 @@ def test_get_file_path(mapdl, tmpdir): ("expdata", "dat", "DIR"), ], ) -def test_tbft(mapdl, tmpdir, option2, option3, option4): +def test_tbft(mapdl, cleared, tmpdir, option2, option3, option4): fname = "expdata.dat" dirpath = tmpdir.mkdir("tmpdir") fpath = dirpath.join(fname) @@ -1305,12 +1308,16 @@ def test_tbft(mapdl, tmpdir, option2, option3, option4): else: option2 = os.path.join(dirpath, option2) - mapdl.prep7(mute=True) + mapdl.prep7() mat_id = mapdl.get_value("MAT", 0, "NUM", "MAX") + 1 - mapdl.tbft("FADD", mat_id, "HYPER", "MOONEY", "3", mute=True) - mapdl.tbft("EADD", mat_id, "UNIA", option2, option3, option4, "", "", "", mute=True) + output = mapdl.tbft("FADD", mat_id, "HYPER", "MOONEY", "3") + assert "Successfully Constructed Material Model" in output + output = mapdl.tbft("EADD", mat_id, "UNIA", option2, option3, option4, "", "", "") + assert "Successfully Constructed Material Model" in output - assert fname in mapdl.list_files() + # with pytest.warns(UserWarning): + # # checking warning if overwriting + # mapdl.tbft("FADD", mat_id, "HYPER", "MOONEY", "3") def test_tbft_not_found(mapdl): @@ -1485,8 +1492,9 @@ def test_mpfunctions(mapdl, cube_solve, capsys): mapdl.mpread(fname="dummy", ext="dummy", lib="something") # Test suppliying a dir path when in remote - with pytest.raises(IOError): - mapdl.mpwrite("/test_dir/test", "mp") + if not ON_LOCAL: + with pytest.raises(IOError): + mapdl.mpwrite("/test_dir/test", "mp") def test_mapdl_str(mapdl): @@ -1515,7 +1523,7 @@ def test_file_command_local(mapdl, cube_solve, tmpdir): with pytest.raises(FileNotFoundError): mapdl.file("potato") - assert rst_file in mapdl.list_files() + assert os.path.basename(rst_file) in mapdl.list_files() rst_fpath = os.path.join(mapdl.directory, rst_file) # change directory @@ -1851,7 +1859,7 @@ def test_cache_pids(mapdl): mapdl._cache_pids() # Recache pids for each in mapdl._pids: - assert "ansys" in "".join(psutil.Process(each).cmdline()) + assert "ansys" in "".join(psutil.Process(each).cmdline()).lower() @requires("local") @@ -1942,7 +1950,9 @@ def test_igesin_whitespace(mapdl, cleared, tmpdir): @requires("nostudent") def test_save_on_exit(mapdl, cleared): mapdl2 = launch_mapdl( - license_server_check=False, additional_switches=QUICK_LAUNCH_SWITCHES + license_server_check=False, + additional_switches=QUICK_LAUNCH_SWITCHES, + port=mapdl.port + 1, ) mapdl2.parameters["my_par"] = "initial_value" @@ -1957,10 +1967,12 @@ def test_save_on_exit(mapdl, cleared): mapdl2.exit() mapdl2 = launch_mapdl( - license_server_check=False, additional_switches=QUICK_LAUNCH_SWITCHES + license_server_check=False, + additional_switches=QUICK_LAUNCH_SWITCHES, + port=mapdl.port + 1, ) mapdl2.resume(db_path) - if mapdl.version >= 24.1: + if mapdl.version >= 24.2: assert mapdl2.parameters["my_par"] == "initial_value" else: # This fails in earlier versions of MAPDL @@ -1974,7 +1986,9 @@ def test_save_on_exit(mapdl, cleared): mapdl2.exit(save=True) mapdl2 = launch_mapdl( - license_server_check=False, additional_switches=QUICK_LAUNCH_SWITCHES + license_server_check=False, + additional_switches=QUICK_LAUNCH_SWITCHES, + port=mapdl.port + 1, ) mapdl2.resume(db_path) assert mapdl2.parameters["my_par"] == "new_initial_value" @@ -2244,7 +2258,7 @@ def test_inquire_invalid(mapdl): def test_inquire_default(mapdl): mapdl.title = "heeeelloo" - assert mapdl.directory == mapdl.inquire() + assert Path(mapdl.directory) == Path(mapdl.inquire()) def test_vwrite_error(mapdl): diff --git a/tests/test_pool.py b/tests/test_pool.py index daa178bc60..25b8e100c7 100644 --- a/tests/test_pool.py +++ b/tests/test_pool.py @@ -37,7 +37,7 @@ else: EXEC_FILE = os.environ.get("PYMAPDL_MAPDL_EXEC") -from ansys.mapdl.core import LocalMapdlPool, examples +from ansys.mapdl.core import MapdlPool, examples from ansys.mapdl.core.errors import VersionError from conftest import QUICK_LAUNCH_SWITCHES, requires @@ -72,7 +72,7 @@ def pool(tmpdir_factory): if ON_LOCAL: - mapdl_pool = LocalMapdlPool( + mapdl_pool = MapdlPool( 2, license_server_check=False, run_location=run_path, @@ -85,7 +85,7 @@ def pool(tmpdir_factory): else: port2 = os.environ.get("PYMAPDL_PORT2", 50057) - mapdl_pool = LocalMapdlPool( + mapdl_pool = MapdlPool( 2, license_server_check=False, start_instance=False, @@ -117,7 +117,7 @@ def pool(tmpdir_factory): @skip_requires_194 def test_invalid_exec(): with pytest.raises(VersionError): - LocalMapdlPool( + MapdlPool( 4, nproc=NPROC, exec_file="/usr/ansys_inc/v194/ansys/bin/mapdl", @@ -268,7 +268,7 @@ def test_directory_names_default(pool): @requires("local") @skip_if_ignore_pool def test_directory_names_custom_string(tmpdir): - pool = LocalMapdlPool( + pool = MapdlPool( 2, exec_file=EXEC_FILE, run_location=tmpdir, @@ -296,7 +296,7 @@ def myfun(i): else: return "Other_instance" - pool = LocalMapdlPool( + pool = MapdlPool( 3, exec_file=EXEC_FILE, nproc=NPROC, @@ -315,7 +315,7 @@ def myfun(i): def test_num_instances(): with pytest.raises(ValueError, match="least 1 instance"): - pool = LocalMapdlPool( + pool = MapdlPool( 0, exec_file=EXEC_FILE, nproc=NPROC, @@ -325,7 +325,7 @@ def test_num_instances(): @skip_if_ignore_pool def test_only_one_instance(): - pool = LocalMapdlPool( + pool = MapdlPool( 1, exec_file=EXEC_FILE, nproc=NPROC, diff --git a/tests/test_xpl.py b/tests/test_xpl.py index 6c98705f63..c6f26dbad5 100644 --- a/tests/test_xpl.py +++ b/tests/test_xpl.py @@ -80,6 +80,11 @@ def test_read_asarray(xpl): def test_save(xpl): + if xpl._mapdl.version == 24.2: + pytest.xfail( + "There is a bug (977113) on v242 which makes saving using XPL to fail." + ) + xpl.save() with pytest.raises(MapdlCommandIgnoredError): xpl.list()