From 5f63bd9c8a4d48339b766d2cf00cb79c3acfdcc3 Mon Sep 17 00:00:00 2001 From: Dave Logie Date: Tue, 10 Mar 2026 16:31:16 -0400 Subject: [PATCH 1/3] add re_upload_files and example script with example output from failed upload. --- examples/re_upload_files/upload_fail.json | 45 ++++++++++++ examples/re_upload_files/upload_files.py | 80 +++++++++++++++++++++ src/ansys/hps/client/jms/api/project_api.py | 31 ++++++++ 3 files changed, 156 insertions(+) create mode 100644 examples/re_upload_files/upload_fail.json create mode 100644 examples/re_upload_files/upload_files.py diff --git a/examples/re_upload_files/upload_fail.json b/examples/re_upload_files/upload_fail.json new file mode 100644 index 000000000..7b8c9c0ff --- /dev/null +++ b/examples/re_upload_files/upload_fail.json @@ -0,0 +1,45 @@ +[ + "c:\\AnsysDev\\rep-evaluator\\test_run\\upload_fail_test\\test_upload_fail\\eval_aapqttqyh0qxrsg-upload_fail_test-test_upload_fail\\work_dir\\tasks\\032fccjmlE2Cu82zqMkq2U\\task_032fccyePv7FNqUlMBuNnn", + [ + { + "access_mode": "transfer", + "collect": true, + "collect_interval": null, + "created_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", + "creation_time": "2026-03-10T16:57:53.457110+00:00", + "evaluation_path": "ps0_out.txt", + "expiry_time": null, + "format": null, + "hash": null, + "id": "032fcdS9aoB7T0DOiswbaJ", + "modification_time": "2026-03-10T16:57:53.457110+00:00", + "modified_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", + "monitor": true, + "name": "ps0_out", + "reference_id": "032fccwqivoTA49fsQyBDN", + "size": null, + "storage_id": "032fcdS9aoB7T0DOiswbaJ_ps0_out", + "type": "text/plain" + }, + { + "access_mode": "transfer", + "collect": true, + "collect_interval": null, + "created_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", + "creation_time": "2026-03-10T16:57:53.457111+00:00", + "evaluation_path": "console_output.txt", + "expiry_time": null, + "format": null, + "hash": null, + "id": "032fcdS9cAQEUnhOZzZgLo", + "modification_time": "2026-03-10T16:57:53.457111+00:00", + "modified_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", + "monitor": true, + "name": "console_output", + "reference_id": "032fccxEkRQ6v2Q4Idkb5L", + "size": null, + "storage_id": "032fcdS9cAQEUnhOZzZgLo_console_output", + "type": "text/plain" + } + ] +] \ No newline at end of file diff --git a/examples/re_upload_files/upload_files.py b/examples/re_upload_files/upload_files.py new file mode 100644 index 000000000..3f97bac19 --- /dev/null +++ b/examples/re_upload_files/upload_files.py @@ -0,0 +1,80 @@ +# Copyright (C) 2022 - 2026 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Example to retry upload of failed Evaluator upload.""" + +import argparse +import logging +import os + +from ansys.hps.client import Client, HPSError +from ansys.hps.client.jms import JmsApi, ProjectApi + +log = logging.getLogger(__name__) + + +def upload_files(client, project_id, upload_file): + """Upload files example.""" + + jms_api = JmsApi(client) + project = jms_api.get_project(id=project_id) + + log.info(f"Project id: {project.id}") + project_api = ProjectApi(client, project.id) + + log.info("=== Example: Uploading output files using ProjectApi.re_upload_files()") + project_api.re_upload_files(upload_file) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-id", "--id", type=str, default="") + parser.add_argument("-f", "--file", type=str, default="") + parser.add_argument("-U", "--url", default="https://127.0.0.1:8443/hps") + parser.add_argument("-u", "--username", default="repadmin") + parser.add_argument("-p", "--password", default="repadmin") + parser.add_argument("-t", "--token", default="") + parser.add_argument("-a", "--account", default="onprem_account") + args = parser.parse_args() + + logger = logging.getLogger() + logging.basicConfig(format="%(message)s", level=logging.DEBUG) + + try: + log.info("Connect to HPC Platform Services") + + if args.token: + client = Client(url=args.url, access_token=args.token) + client.session.headers.update({"accountid": args.account}) + else: + client = Client(url=args.url, username=args.username, password=args.password) + log.info(f"HPS URL: {client.url}") + + file_path = args.file + if not os.path.isabs(file_path): + file_path = os.path.join(os.getcwd(), file_path) + file_path = os.path.abspath(file_path) + + upload_files(client=client, project_id=args.id, upload_file=file_path) + + except HPSError as e: + log.error(str(e)) diff --git a/src/ansys/hps/client/jms/api/project_api.py b/src/ansys/hps/client/jms/api/project_api.py index fa49783e5..60df15fdb 100644 --- a/src/ansys/hps/client/jms/api/project_api.py +++ b/src/ansys/hps/client/jms/api/project_api.py @@ -32,6 +32,7 @@ from ansys.hps.data_transfer.client.api.handler import WaitHandler from ansys.hps.data_transfer.client.models import Operation, OperationState, SrcDst, StoragePath +from pydantic import TypeAdapter from ansys.hps.client.check_version import ( JMS_VERSIONS, @@ -187,6 +188,10 @@ def update_files(self, files: list[File], as_objects=True): """Update files.""" return update_files(self, files, as_objects=as_objects) + def re_upload_files(self, file_path: str, as_objects=True) -> list[File]: + """Re-upload files for failed upload.""" + return re_upload_files(self, file_path, as_objects=as_objects) + def delete_files(self, files: list[File]): """Delete files.""" return self._delete_objects(files, File) @@ -810,6 +815,23 @@ def get_files(project_api: ProjectApi, as_objects=True, content=False, **query_p return files +def _upload_files_from_file(project_api: ProjectApi, filepath: str): + """Upload files directly using the data transfer worker.""" + with open(filepath, encoding="utf-8") as f: + data = json.load(f) + + adapter = TypeAdapter(tuple[str, list[dict]]) + task_directory, file_dicts = adapter.validate_python(data) + + files = [File(**d) for d in file_dicts] + + for f in files: + f.src = os.path.join(task_directory, f.evaluation_path) + + _upload_files(project_api, files) + return files + + def _upload_files(project_api: ProjectApi, files): """Upload files directly using the data transfer worker.""" min_v = JMS_VERSIONS[HpsRelease.v1_2_0] @@ -918,6 +940,15 @@ def update_files(project_api: ProjectApi, files: list[File], as_objects=True) -> ) +def re_upload_files(project_api: ProjectApi, file_path: str, as_objects=True) -> list[File]: + """Upload files from a failed Evaluator upload.""" + files = _upload_files_from_file(project_api, file_path) + # Update file resources in JMS + return update_objects( + project_api.client.session, project_api.url, files, File, as_objects=as_objects + ) + + class _DownloadHandler(WaitHandler): """Handles download operations. From 81f15dcc4487002d9b62889c3ea0a9b5721d5881 Mon Sep 17 00:00:00 2001 From: Dave Logie Date: Wed, 11 Mar 2026 15:38:20 -0400 Subject: [PATCH 2/3] project ID was added to upload file json --- src/ansys/hps/client/jms/api/project_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/hps/client/jms/api/project_api.py b/src/ansys/hps/client/jms/api/project_api.py index 60df15fdb..cde814db8 100644 --- a/src/ansys/hps/client/jms/api/project_api.py +++ b/src/ansys/hps/client/jms/api/project_api.py @@ -820,8 +820,8 @@ def _upload_files_from_file(project_api: ProjectApi, filepath: str): with open(filepath, encoding="utf-8") as f: data = json.load(f) - adapter = TypeAdapter(tuple[str, list[dict]]) - task_directory, file_dicts = adapter.validate_python(data) + adapter = TypeAdapter(tuple[str, str, list[dict]]) + project_id, task_directory, file_dicts = adapter.validate_python(data) files = [File(**d) for d in file_dicts] From e5a2103c15799bf7836c0856ae30222bbeae4f54 Mon Sep 17 00:00:00 2001 From: Dave Logie Date: Thu, 12 Mar 2026 12:26:20 -0400 Subject: [PATCH 3/3] remove change to ProjectApi --- examples/re_upload_files/upload_fail.json | 30 ++++++++-------- examples/re_upload_files/upload_files.py | 40 ++++++++++++++------- src/ansys/hps/client/jms/api/project_api.py | 31 ---------------- 3 files changed, 44 insertions(+), 57 deletions(-) diff --git a/examples/re_upload_files/upload_fail.json b/examples/re_upload_files/upload_fail.json index 7b8c9c0ff..8c2ca49bc 100644 --- a/examples/re_upload_files/upload_fail.json +++ b/examples/re_upload_files/upload_fail.json @@ -1,24 +1,26 @@ -[ - "c:\\AnsysDev\\rep-evaluator\\test_run\\upload_fail_test\\test_upload_fail\\eval_aapqttqyh0qxrsg-upload_fail_test-test_upload_fail\\work_dir\\tasks\\032fccjmlE2Cu82zqMkq2U\\task_032fccyePv7FNqUlMBuNnn", - [ +{ + "project_id": "032giRgQ1EGK0UCx9zKXwF", + "task_id": "032giS16ofqdXqh6sgTR9P", + "task_directory": "C:\\AnsysDev\\rep-evaluator\\test_run\\upload_fail_test\\test_upload_fail\\eval_aapqttqyh0qxrsg-upload_fail_test-test_upload_fail\\work_dir\\tasks\\032giRgQ1EGK0UCx9zKXwF\\task_032giS16ofqdXqh6sgTR9P", + "files": [ { "access_mode": "transfer", "collect": true, "collect_interval": null, "created_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", - "creation_time": "2026-03-10T16:57:53.457110+00:00", + "creation_time": "2026-03-12T15:01:32.919202+00:00", "evaluation_path": "ps0_out.txt", "expiry_time": null, "format": null, "hash": null, - "id": "032fcdS9aoB7T0DOiswbaJ", - "modification_time": "2026-03-10T16:57:53.457110+00:00", + "id": "032giSTY6wKeDuSfcTJ8dW", + "modification_time": "2026-03-12T15:01:32.919202+00:00", "modified_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", "monitor": true, "name": "ps0_out", - "reference_id": "032fccwqivoTA49fsQyBDN", + "reference_id": "032giRvTNjwtBjumAGX0op", "size": null, - "storage_id": "032fcdS9aoB7T0DOiswbaJ_ps0_out", + "storage_id": "032giSTY6wKeDuSfcTJ8dW_ps0_out", "type": "text/plain" }, { @@ -26,20 +28,20 @@ "collect": true, "collect_interval": null, "created_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", - "creation_time": "2026-03-10T16:57:53.457111+00:00", + "creation_time": "2026-03-12T15:01:32.919203+00:00", "evaluation_path": "console_output.txt", "expiry_time": null, "format": null, "hash": null, - "id": "032fcdS9cAQEUnhOZzZgLo", - "modification_time": "2026-03-10T16:57:53.457111+00:00", + "id": "032giSTY7a290fDOn2qepA", + "modification_time": "2026-03-12T15:01:32.919203+00:00", "modified_by": "8f9758f7-8167-46f9-b099-7c5acc152fe2", "monitor": true, "name": "console_output", - "reference_id": "032fccxEkRQ6v2Q4Idkb5L", + "reference_id": "032giRwC13uwPuwqG05O0z", "size": null, - "storage_id": "032fcdS9cAQEUnhOZzZgLo_console_output", + "storage_id": "032giSTY7a290fDOn2qepA_console_output", "type": "text/plain" } ] -] \ No newline at end of file +} \ No newline at end of file diff --git a/examples/re_upload_files/upload_files.py b/examples/re_upload_files/upload_files.py index 3f97bac19..40f728943 100644 --- a/examples/re_upload_files/upload_files.py +++ b/examples/re_upload_files/upload_files.py @@ -23,31 +23,52 @@ """Example to retry upload of failed Evaluator upload.""" import argparse +import json import logging import os from ansys.hps.client import Client, HPSError -from ansys.hps.client.jms import JmsApi, ProjectApi +from ansys.hps.client.jms import File, JmsApi, ProjectApi, Task log = logging.getLogger(__name__) -def upload_files(client, project_id, upload_file): +def upload_files(client, file_path): """Upload files example.""" + if not os.path.isabs(file_path): + file_path = os.path.join(os.getcwd(), file_path) + file_path = os.path.abspath(file_path) + + with open(file_path, encoding="utf-8") as f: + data = json.load(f) + + files = [File(**d) for d in data["files"]] + for f in files: + f.src = os.path.join(data["task_directory"], f.evaluation_path) + jms_api = JmsApi(client) - project = jms_api.get_project(id=project_id) + project = jms_api.get_project(id=data["project_id"]) log.info(f"Project id: {project.id}") project_api = ProjectApi(client, project.id) - log.info("=== Example: Uploading output files using ProjectApi.re_upload_files()") - project_api.re_upload_files(upload_file) + log.info("=== Example: Uploading output files using ProjectApi.update_files()") + project_api.update_files(files) + + task_updates: list[Task] = [] + task_updates.append(Task(id=data["task_id"], eval_status="evaluated")) + + tasks = project_api.update_tasks(task_updates) + + if tasks[0].eval_status == "evaluated": + log.info(f"Files uploaded and Task eval status updated to {tasks[0].eval_status}") + else: + log.info("Files uploaded but Task eval status NOT updated") if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("-id", "--id", type=str, default="") parser.add_argument("-f", "--file", type=str, default="") parser.add_argument("-U", "--url", default="https://127.0.0.1:8443/hps") parser.add_argument("-u", "--username", default="repadmin") @@ -69,12 +90,7 @@ def upload_files(client, project_id, upload_file): client = Client(url=args.url, username=args.username, password=args.password) log.info(f"HPS URL: {client.url}") - file_path = args.file - if not os.path.isabs(file_path): - file_path = os.path.join(os.getcwd(), file_path) - file_path = os.path.abspath(file_path) - - upload_files(client=client, project_id=args.id, upload_file=file_path) + upload_files(client=client, file_path=args.file) except HPSError as e: log.error(str(e)) diff --git a/src/ansys/hps/client/jms/api/project_api.py b/src/ansys/hps/client/jms/api/project_api.py index cde814db8..fa49783e5 100644 --- a/src/ansys/hps/client/jms/api/project_api.py +++ b/src/ansys/hps/client/jms/api/project_api.py @@ -32,7 +32,6 @@ from ansys.hps.data_transfer.client.api.handler import WaitHandler from ansys.hps.data_transfer.client.models import Operation, OperationState, SrcDst, StoragePath -from pydantic import TypeAdapter from ansys.hps.client.check_version import ( JMS_VERSIONS, @@ -188,10 +187,6 @@ def update_files(self, files: list[File], as_objects=True): """Update files.""" return update_files(self, files, as_objects=as_objects) - def re_upload_files(self, file_path: str, as_objects=True) -> list[File]: - """Re-upload files for failed upload.""" - return re_upload_files(self, file_path, as_objects=as_objects) - def delete_files(self, files: list[File]): """Delete files.""" return self._delete_objects(files, File) @@ -815,23 +810,6 @@ def get_files(project_api: ProjectApi, as_objects=True, content=False, **query_p return files -def _upload_files_from_file(project_api: ProjectApi, filepath: str): - """Upload files directly using the data transfer worker.""" - with open(filepath, encoding="utf-8") as f: - data = json.load(f) - - adapter = TypeAdapter(tuple[str, str, list[dict]]) - project_id, task_directory, file_dicts = adapter.validate_python(data) - - files = [File(**d) for d in file_dicts] - - for f in files: - f.src = os.path.join(task_directory, f.evaluation_path) - - _upload_files(project_api, files) - return files - - def _upload_files(project_api: ProjectApi, files): """Upload files directly using the data transfer worker.""" min_v = JMS_VERSIONS[HpsRelease.v1_2_0] @@ -940,15 +918,6 @@ def update_files(project_api: ProjectApi, files: list[File], as_objects=True) -> ) -def re_upload_files(project_api: ProjectApi, file_path: str, as_objects=True) -> list[File]: - """Upload files from a failed Evaluator upload.""" - files = _upload_files_from_file(project_api, file_path) - # Update file resources in JMS - return update_objects( - project_api.client.session, project_api.url, files, File, as_objects=as_objects - ) - - class _DownloadHandler(WaitHandler): """Handles download operations.