From fa4fe95e8665c2505f5f4f8f5a5e2784e4f1dff9 Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Fri, 1 Aug 2025 06:59:37 +0200 Subject: [PATCH 1/9] add hps 1.3 release option --- .github/workflows/ci_cd.yml | 1 + .github/workflows/nightly.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index a8f44dbc8..882009f53 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -10,6 +10,7 @@ on: - 'v1.0.2' - 'v1.1.1' - 'v1.2.0' + - 'v1.3.45' - 'latest-dev' hps-feature: description: HPS feature to test against diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3e2cd2c7e..4cda04370 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -10,6 +10,7 @@ on: - 'v1.0.2' - 'v1.1.1' - 'v1.2.0' + - 'v1.3.45' - 'latest-dev' schedule: From 2d1f06ca2be583c87538f9ce0bfb31c4df86ffd9 Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Fri, 1 Aug 2025 07:26:44 +0200 Subject: [PATCH 2/9] update versions dict --- src/ansys/hps/client/check_version.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ansys/hps/client/check_version.py b/src/ansys/hps/client/check_version.py index c4fca0f53..d52779bd7 100644 --- a/src/ansys/hps/client/check_version.py +++ b/src/ansys/hps/client/check_version.py @@ -40,6 +40,7 @@ class HpsRelease(Enum): v1_0_2 = "1.0.2" v1_1_1 = "1.1.1" v1_2_0 = "1.2.0" + v1_3_45 = "1.3.45" """HPS to JMS version mapping.""" @@ -47,6 +48,7 @@ class HpsRelease(Enum): HpsRelease.v1_0_2: "1.0.12", HpsRelease.v1_1_1: "1.0.20", HpsRelease.v1_2_0: "1.1.4", + HpsRelease.v1_3_45: "1.1.60", } @@ -55,6 +57,7 @@ class HpsRelease(Enum): HpsRelease.v1_0_2: "1.0.0", HpsRelease.v1_1_1: "1.1.5", HpsRelease.v1_2_0: "1.1.10", + HpsRelease.v1_3_45: "1.1.71", } From e31a045487d332068c2e250bde5239be63781bde Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Wed, 6 Aug 2025 09:16:10 +0200 Subject: [PATCH 3/9] update compatibility table --- doc/source/getting_started/index.rst | 57 ++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/doc/source/getting_started/index.rst b/doc/source/getting_started/index.rst index f6688b221..9d1a3dc04 100644 --- a/doc/source/getting_started/index.rst +++ b/doc/source/getting_started/index.rst @@ -66,20 +66,53 @@ Compatibility with HPS releases The following table summarizes the compatibility between PyHPS versions and HPS releases. -+------------------------------+-------------------------------+-------------------------------+------------------------------+ -| PyHPS version / HPS release | ``1.0.2`` | ``1.1.1`` | ``1.2.0`` | -+==============================+===============================+===============================+==============================+ -| ``0.7.X`` | :octicon:`check-circle-fill` | :octicon:`check-circle-fill` | :octicon:`check-circle-fill` | -+------------------------------+-------------------------------+-------------------------------+------------------------------+ -| ``0.8.X`` | :octicon:`check-circle-fill` | :octicon:`check-circle-fill` | :octicon:`check-circle-fill` | -+------------------------------+-------------------------------+-------------------------------+------------------------------+ -| ``0.9.X`` | :octicon:`check-circle` | :octicon:`check-circle-fill` | :octicon:`check-circle-fill` | -+------------------------------+-------------------------------+-------------------------------+------------------------------+ -| ``0.10.X`` | :octicon:`x` | :octicon:`x` | :octicon:`check-circle-fill` | -+------------------------------+-------------------------------+-------------------------------+------------------------------+ +.. list-table:: + :header-rows: 1 + :widths: 40 15 15 15 15 + + * - PyHPS version / HPS release + - ``1.0.2`` + - ``1.1.1`` + - ``1.2.0`` + - ``1.3.45`` + * - ``0.7.X`` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` `[1] <#note-1>`__ + * - ``0.8.X`` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` `[1] <#note-1>`__ + * - ``0.9.X`` + - :octicon:`check-circle` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` `[1] <#note-1>`__ + * - ``0.10.X`` + - :octicon:`x` + - :octicon:`x` + - :octicon:`check-circle-fill` + - :octicon:`check-circle-fill` `[1] <#note-1>`__ + * - ``0.11.X`` + - :octicon:`x` + - :octicon:`x` + - :octicon:`check-circle-fill` `[2] <#note-2>`__ + - :octicon:`check-circle-fill` + Legend: - :octicon:`check-circle-fill` Compatible - :octicon:`check-circle` Backward compatible (new features exposed in PyHPS may not be available in older HPS releases) -- :octicon:`x` Incompatible \ No newline at end of file +- :octicon:`x` Incompatible + +.. _note-1: + +**[1]** HPS 1.3.45 introduces breaking changes to the schema for task definition templates. +When using PyHPS versions < 0.11.X, functionalities related to task definition templates may not work correctly. + +.. _note-2: + +**[2]** In PyHPS 0.11.X, functionalities related to task definition templates are only compatible with HPS 1.3.45 and later. \ No newline at end of file From bc79e53c7ba4c14aa9aa9b3a56fbc44b2cee4d20 Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Wed, 6 Aug 2025 09:16:43 +0200 Subject: [PATCH 4/9] update name of precommit linter --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee96dc0c4..ce6fa66aa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: rev: v0.12.5 hooks: # Run the linter. - - id: ruff + - id: ruff-check args: [ --fix ] # Run the formatter. - id: ruff-format From 9adc58b3fd5af9a4f9e575144cdce8e1c3894b3e Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Wed, 6 Aug 2025 09:29:41 +0200 Subject: [PATCH 5/9] add backward compatibility tests --- .github/workflows/ci_cd.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 882009f53..8636cf395 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -60,6 +60,20 @@ jobs: hps-version: ${{ inputs.hps-version || 'latest-dev' }} hps-feature: ${{ inputs.hps-feature || 'main' }} + backward-compatibility-tests: + strategy: + matrix: + hps-version: ['v1.2.0'] + fail-fast: false + uses: ./.github/workflows/tests.yml + secrets: inherit + with: + python-version: '3.10' + toxenv: 'py310' + runner: 'ubuntu-latest' + hps-version: ${{ matrix.hps-version }} + hps-feature: 'main' + docs: name: Documentation runs-on: ubuntu-latest From 2cbd23a0f37feee0686c927f45ef1007d73b575a Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Wed, 6 Aug 2025 11:55:17 +0200 Subject: [PATCH 6/9] Fix retro compatibility tests --- src/ansys/hps/client/__init__.py | 2 +- src/ansys/hps/client/jms/api/jms_api.py | 5 +++++ tests/conftest.py | 25 ++++++++++++++++++--- tests/jms/test_job_definitions.py | 7 ++++-- tests/jms/test_task_definition_templates.py | 7 ++++-- tests/test_examples.py | 7 +++++- 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/ansys/hps/client/__init__.py b/src/ansys/hps/client/__init__.py index 7a52afe44..bcde191c2 100644 --- a/src/ansys/hps/client/__init__.py +++ b/src/ansys/hps/client/__init__.py @@ -25,7 +25,7 @@ from .auth import AuthApi from .authenticate import authenticate, determine_auth_url from .client import Client -from .exceptions import APIError, ClientError, HPSError +from .exceptions import APIError, ClientError, HPSError, VersionCompatibilityError from .jms import JmsApi, ProjectApi from .rms import RmsApi from .warnings import UnverifiedHTTPSRequestsWarning diff --git a/src/ansys/hps/client/jms/api/jms_api.py b/src/ansys/hps/client/jms/api/jms_api.py index 6eb986139..a4c78d3a4 100644 --- a/src/ansys/hps/client/jms/api/jms_api.py +++ b/src/ansys/hps/client/jms/api/jms_api.py @@ -140,6 +140,8 @@ def restore_project(self, path: str) -> Project: ################################################################ # Task Definition Templates + + @version_required(min_version=JMS_VERSIONS[HpsRelease.v1_3_45]) def get_task_definition_templates( self, as_objects=True, **query_params ) -> list[TaskDefinitionTemplate]: @@ -148,6 +150,7 @@ def get_task_definition_templates( self.client.session, self.url, TaskDefinitionTemplate, as_objects, **query_params ) + @version_required(min_version=JMS_VERSIONS[HpsRelease.v1_3_45]) def create_task_definition_templates( self, templates: list[TaskDefinitionTemplate], as_objects=True, **query_params ) -> list[TaskDefinitionTemplate]: @@ -161,6 +164,7 @@ def create_task_definition_templates( **query_params, ) + @version_required(min_version=JMS_VERSIONS[HpsRelease.v1_3_45]) def update_task_definition_templates( self, templates: list[TaskDefinitionTemplate], as_objects=True, **query_params ) -> list[TaskDefinitionTemplate]: @@ -178,6 +182,7 @@ def delete_task_definition_templates(self, templates: list[TaskDefinitionTemplat """Delete task definition templates.""" return delete_objects(self.client.session, self.url, templates, TaskDefinitionTemplate) + @version_required(min_version=JMS_VERSIONS[HpsRelease.v1_3_45]) def copy_task_definition_templates( self, templates: list[TaskDefinitionTemplate], wait: bool = True ) -> str | list[str]: diff --git a/tests/conftest.py b/tests/conftest.py index 7e0a089a2..39e40d9b9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,7 +26,8 @@ import pytest from keycloak import KeycloakAdmin -from ansys.hps.client import AuthApi, Client, JmsApi +from ansys.hps.client import AuthApi, Client, JmsApi, VersionCompatibilityError +from ansys.hps.client.check_version import JMS_VERSIONS, HpsRelease, check_min_version from ansys.hps.client.jms.resource import Project @@ -60,6 +61,11 @@ def client(url, username, password): return Client(url, username, password, verify=False) +@pytest.fixture +def jms_api(client): + return JmsApi(client) + + @pytest.fixture def keycloak_client(client: Client, keycloak_username, keycloak_password): keycloak_client = KeycloakAdmin( @@ -113,8 +119,21 @@ def build_info_path(): @pytest.fixture -def inactive_temporary_project(client): - jms_api = JmsApi(client) +def inactive_temporary_project(jms_api): proj = jms_api.create_project(Project(name="pyhps_temporary_project", active=False)) yield proj jms_api.delete_project(proj) + + +def xfail_for_hps_version_under(hps_version: HpsRelease, jsm_api: JmsApi, request): + if not check_min_version(jsm_api.version, JMS_VERSIONS[hps_version]): + mark = pytest.mark.xfail( + reason=f"Requires HPS version greater than or equal to {hps_version}", + raises=VersionCompatibilityError, + ) + request.node.add_marker(mark) + + +@pytest.fixture +def has_hps_version_ge_1_3_45(jms_api) -> bool: + return check_min_version(jms_api.version, JMS_VERSIONS[HpsRelease.v1_3_45]) diff --git a/tests/jms/test_job_definitions.py b/tests/jms/test_job_definitions.py index 34d24f7df..a2c8197ca 100644 --- a/tests/jms/test_job_definitions.py +++ b/tests/jms/test_job_definitions.py @@ -58,7 +58,7 @@ def test_job_definition_delete(client): jms_api.delete_project(proj) -def test_task_definition_fields(client): +def test_task_definition_fields(client, has_hps_version_ge_1_3_45): # verify that: # - store_output is defaulted to True when undefined, # - memory and disk_space are correctly stored in bytes @@ -97,7 +97,10 @@ def test_task_definition_fields(client): assert task_def.resource_requirements.compute_resource_set_id == "abc123" assert task_def.modified_by is not missing assert task_def.created_by is not missing - assert task_def.debug + + if has_hps_version_ge_1_3_45: + assert task_def.debug + assert auth_api.get_user(id=task_def.created_by).username == client.username assert auth_api.get_user(id=task_def.modified_by).username == client.username diff --git a/tests/jms/test_task_definition_templates.py b/tests/jms/test_task_definition_templates.py index 51c2a1918..9e4f2a4f7 100644 --- a/tests/jms/test_task_definition_templates.py +++ b/tests/jms/test_task_definition_templates.py @@ -28,6 +28,7 @@ from ansys.hps.client import HPSError from ansys.hps.client.auth import AuthApi +from ansys.hps.client.check_version import HpsRelease from ansys.hps.client.jms import JmsApi from ansys.hps.client.jms.resource import ( HpcResources, @@ -38,6 +39,8 @@ from ansys.hps.client.jms.schema.task_definition_template import TaskDefinitionTemplateSchema from tests.utils import create_new_user_client, delete_user +from ..conftest import xfail_for_hps_version_under + log = logging.getLogger(__name__) @@ -122,8 +125,8 @@ def test_template_deserialization(): assert template.execution_context["my_new_field"].default == "value" -def test_template_integration(client): - jms_api = JmsApi(client) +def test_template_integration(jms_api, request): + xfail_for_hps_version_under(HpsRelease.v1_3_45, jms_api, request) # Test get queries templates = jms_api.get_task_definition_templates() diff --git a/tests/test_examples.py b/tests/test_examples.py index 1091863e2..0127a2028 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -22,6 +22,8 @@ import logging +import pytest + from ansys.hps.client import __ansys_apps_version__ as ansys_version from ansys.hps.client.jms import ( IntParameterDefinition, @@ -141,7 +143,10 @@ def test_python_two_bar_truss_problem_with_exec_script(client): jms_api.delete_project(project) -def test_python_two_bar_truss_params_in_exec_script(client): +def test_python_two_bar_truss_params_in_exec_script(client, has_hps_version_ge_1_3_45): + if not has_hps_version_ge_1_3_45: + pytest.skip("Returning output parameters in the execution script was added in HPS 1.3.45.") + from examples.python_two_bar_truss_params_in_exec_script.project_setup import main num_jobs = 10 From 6bf6626016618e8577c6622b310bad3500d5bf6b Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Wed, 6 Aug 2025 12:16:37 +0200 Subject: [PATCH 7/9] adjust some more tests --- doc/source/getting_started/index.rst | 1 + tests/jms/test_jms_api.py | 11 ++++++----- tests/jms/test_task_definition_templates.py | 15 ++++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/doc/source/getting_started/index.rst b/doc/source/getting_started/index.rst index 9d1a3dc04..07742faec 100644 --- a/doc/source/getting_started/index.rst +++ b/doc/source/getting_started/index.rst @@ -112,6 +112,7 @@ Legend: **[1]** HPS 1.3.45 introduces breaking changes to the schema for task definition templates. When using PyHPS versions < 0.11.X, functionalities related to task definition templates may not work correctly. +See the HPS 1.3.45 release notes for more information on the changes introduced in this version. .. _note-2: diff --git a/tests/jms/test_jms_api.py b/tests/jms/test_jms_api.py index e413c096f..54792410d 100644 --- a/tests/jms/test_jms_api.py +++ b/tests/jms/test_jms_api.py @@ -168,7 +168,7 @@ def test_storage_configuration(client): assert "obj_type" in storage -def test_objects_type_check(client): +def test_objects_type_check(client, has_hps_version_ge_1_3_45): proj_name = "test_objects_type_check" proj = Project(name=proj_name, active=True) @@ -177,10 +177,11 @@ def test_objects_type_check(client): jms_api = JmsApi(client) - with pytest.raises(ClientError) as ex_info: - _ = jms_api.create_task_definition_templates([job]) - assert "Wrong object type" in str(ex_info.value) - assert "got " in str(ex_info.value) + if has_hps_version_ge_1_3_45: + with pytest.raises(ClientError) as ex_info: + _ = jms_api.create_task_definition_templates([job]) + assert "Wrong object type" in str(ex_info.value) + assert "got " in str(ex_info.value) proj = jms_api.create_project(proj, replace=True) project_api = ProjectApi(client, proj.id) diff --git a/tests/jms/test_task_definition_templates.py b/tests/jms/test_task_definition_templates.py index 9e4f2a4f7..60a592c22 100644 --- a/tests/jms/test_task_definition_templates.py +++ b/tests/jms/test_task_definition_templates.py @@ -200,9 +200,11 @@ def test_template_integration(jms_api, request): jms_api.delete_task_definition_templates([new_template]) -def test_template_permissions(client, keycloak_client, is_admin): +def test_template_permissions(client, keycloak_client, is_admin, request): jms_api = JmsApi(client) + xfail_for_hps_version_under(HpsRelease.v1_3_45, jms_api, request) + templates = jms_api.get_task_definition_templates() # a regular deployment should have some default templates @@ -295,8 +297,8 @@ def test_template_permissions(client, keycloak_client, is_admin): delete_user(keycloak_client, user1) -def test_template_permissions_update(client): - jms_api = JmsApi(client) +def test_template_permissions_update(jms_api, request): + xfail_for_hps_version_under(HpsRelease.v1_3_45, jms_api, request) # create new template and check default permissions template = TaskDefinitionTemplate(name="my_template", version=uuid.uuid4()) @@ -320,8 +322,9 @@ def test_template_permissions_update(client): jms_api.delete_task_definition_templates([template]) -def test_template_anyone_permission(client, keycloak_client): +def test_template_anyone_permission(client, keycloak_client, request): jms_api = JmsApi(client) + xfail_for_hps_version_under(HpsRelease.v1_3_45, jms_api, request) # create new template and check default permissions template = TaskDefinitionTemplate(name="my_template", version=uuid.uuid4()) @@ -383,7 +386,9 @@ def test_template_anyone_permission(client, keycloak_client): delete_user(keycloak_client, user1) -def test_template_delete(client, keycloak_client): +def test_template_delete(client, keycloak_client, request): + xfail_for_hps_version_under(HpsRelease.v1_3_45, JmsApi(client), request) + auth_api = AuthApi(client) # create 2 non-admin users From c6f92ab3ee56a1ff5b2fadcae56c1827b9ed16e6 Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Wed, 6 Aug 2025 13:20:34 +0200 Subject: [PATCH 8/9] fix workflow --- .github/workflows/ci_cd.yml | 1 + .github/workflows/tests.yml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 8636cf395..460c2e1a9 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -73,6 +73,7 @@ jobs: runner: 'ubuntu-latest' hps-version: ${{ matrix.hps-version }} hps-feature: 'main' + upload-coverage: false docs: name: Documentation diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 510240173..06b21268e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,6 +26,10 @@ on: docker-compose-profiles: description: Docker compose profiles to use type: string + upload-coverage: + description: Whether to upload coverage results + type: boolean + default: true jobs: From d71debea4024797a3b6be499ccb9114340ff8ffb Mon Sep 17 00:00:00 2001 From: Federico Negri Date: Wed, 6 Aug 2025 13:21:03 +0200 Subject: [PATCH 9/9] add conditions --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 06b21268e..7018112d6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -74,7 +74,7 @@ jobs: - name: Upload coverage results uses: actions/upload-artifact@v4 - if: ${{ inputs.python-version == '3.10' }} + if: ${{ inputs.python-version == '3.10' && inputs.upload-coverage }} with: name: coverage-html path: .cov/html @@ -82,7 +82,7 @@ jobs: - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 - if: ${{ inputs.python-version == '3.10' }} + if: ${{ inputs.python-version == '3.10' && inputs.upload-coverage }} env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: