From 284d0590b7edff75f5a507340578c95fd55076ab Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 16 Dec 2025 14:38:22 -0600 Subject: [PATCH 1/7] Updating ibcdfo branch --- install/install_ibcdfo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/install_ibcdfo.sh b/install/install_ibcdfo.sh index efd5f6dcb5..0ed790f01a 100644 --- a/install/install_ibcdfo.sh +++ b/install/install_ibcdfo.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -git clone --recurse-submodules -b develop https://github.com/POptUS/IBCDFO.git +git clone --recurse-submodules -b main https://github.com/POptUS/IBCDFO.git pushd IBCDFO/minq/py/minq5/ export PYTHONPATH="$PYTHONPATH:$(pwd)" echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV From ff1a6b889e7091b910ce93ef9b14e0d863a14bb9 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Mon, 12 Jan 2026 16:39:14 -0800 Subject: [PATCH 2/7] Fix App Check: Container Path When using the `precedent` to run apps from container images, the executable is not available to check for the host side. This relaxes respective "early" checks to support this workflow. --- libensemble/executors/executor.py | 14 ++++++++++---- libensemble/executors/mpi_executor.py | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libensemble/executors/executor.py b/libensemble/executors/executor.py index d9cf6f428d..dca58deaf5 100644 --- a/libensemble/executors/executor.py +++ b/libensemble/executors/executor.py @@ -673,10 +673,16 @@ def set_worker_info(self, comm=None, workerid=None) -> None: self.workerID = workerid self.comm = comm - def _check_app_exists(self, full_path: str) -> None: + def _check_app_exists(self, app: Application) -> None: """Allows submit function to check if app exists and error if not""" - if not os.path.isfile(full_path): - raise ExecutorException(f"Application does not exist {full_path}") + if app.precedent is not None: + # Could be a container call in precedent. In that case, + # the executable is not available on the host system and + # we just forward what the user provided. + return + + if not os.path.isfile(app.full_path): + raise ExecutorException(f"Application does not exist {app.full_path}") def submit( self, @@ -745,7 +751,7 @@ def submit( task = Task(app, app_args, default_workdir, stdout, stderr, self.workerID, dry_run) if not dry_run: - self._check_app_exists(task.app.full_path) + self._check_app_exists(task.app) runline = task.app.app_cmd.split() if task.app_args is not None: diff --git a/libensemble/executors/mpi_executor.py b/libensemble/executors/mpi_executor.py index 9b167ddaa1..114144291c 100644 --- a/libensemble/executors/mpi_executor.py +++ b/libensemble/executors/mpi_executor.py @@ -317,7 +317,7 @@ def submit( task = Task(app, app_args, default_workdir, stdout, stderr, self.workerID, dry_run) if not dry_run: - self._check_app_exists(task.app.full_path) + self._check_app_exists(task.app) if stage_inout is not None: logger.warning("stage_inout option ignored in this " "executor - runs in-place") From fd3c4412f7e445ffa7344cce825e8017371edae8 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Mon, 12 Jan 2026 17:35:43 -0800 Subject: [PATCH 3/7] Update Tests --- libensemble/tests/unit_tests/test_executor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libensemble/tests/unit_tests/test_executor.py b/libensemble/tests/unit_tests/test_executor.py index df5c8cc32d..830c05ce38 100644 --- a/libensemble/tests/unit_tests/test_executor.py +++ b/libensemble/tests/unit_tests/test_executor.py @@ -909,8 +909,8 @@ def test_non_existent_app(): try: w_exctr.submit(app_name="nonexist") - except ExecutorException as e: - assert e.args[0] == "Application does not exist simdir/non_exist.x" + except FileNotFoundError as e: + assert e.filename == "simdir/non_exist.x" else: assert 0 @@ -930,8 +930,8 @@ def test_non_existent_app_mpi(): try: w_exctr.submit(app_name="nonexist") - except ExecutorException as e: - assert e.args[0] == "Application does not exist simdir/non_exist.x" + except MPIResourcesException: + pass else: assert 0 From 075462de196475fc53318039f2efbbeb885abddf Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 6 Feb 2026 14:06:40 -0800 Subject: [PATCH 4/7] Precendent: Also Check Empty String --- libensemble/executors/executor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libensemble/executors/executor.py b/libensemble/executors/executor.py index 515ee74da5..097dbed7f9 100644 --- a/libensemble/executors/executor.py +++ b/libensemble/executors/executor.py @@ -675,7 +675,7 @@ def set_worker_info(self, comm=None, workerid=None) -> None: def _check_app_exists(self, app: Application) -> None: """Allows submit function to check if app exists and error if not""" - if app.precedent is not None: + if app.precedent is not None and app.precedent != "": # Could be a container call in precedent. In that case, # the executable is not available on the host system and # we just forward what the user provided. From dbc557cdaf50d70741d1425683f67ba47b2f93f0 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 6 Feb 2026 14:07:54 -0800 Subject: [PATCH 5/7] Cleanup --- libensemble/executors/executor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libensemble/executors/executor.py b/libensemble/executors/executor.py index 097dbed7f9..e8a23b22ce 100644 --- a/libensemble/executors/executor.py +++ b/libensemble/executors/executor.py @@ -675,7 +675,7 @@ def set_worker_info(self, comm=None, workerid=None) -> None: def _check_app_exists(self, app: Application) -> None: """Allows submit function to check if app exists and error if not""" - if app.precedent is not None and app.precedent != "": + if app.precedent: # Could be a container call in precedent. In that case, # the executable is not available on the host system and # we just forward what the user provided. From d5d5190f9d57b7f1b56c07c3a2b00dd4b0704c98 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 6 Feb 2026 14:12:59 -0800 Subject: [PATCH 6/7] Undo Test Change --- libensemble/tests/unit_tests/test_executor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libensemble/tests/unit_tests/test_executor.py b/libensemble/tests/unit_tests/test_executor.py index 830c05ce38..df5c8cc32d 100644 --- a/libensemble/tests/unit_tests/test_executor.py +++ b/libensemble/tests/unit_tests/test_executor.py @@ -909,8 +909,8 @@ def test_non_existent_app(): try: w_exctr.submit(app_name="nonexist") - except FileNotFoundError as e: - assert e.filename == "simdir/non_exist.x" + except ExecutorException as e: + assert e.args[0] == "Application does not exist simdir/non_exist.x" else: assert 0 @@ -930,8 +930,8 @@ def test_non_existent_app_mpi(): try: w_exctr.submit(app_name="nonexist") - except MPIResourcesException: - pass + except ExecutorException as e: + assert e.args[0] == "Application does not exist simdir/non_exist.x" else: assert 0 From 0c9ed6ff7966ff975c5f10a306d573675630c7d0 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 6 Feb 2026 14:24:48 -0800 Subject: [PATCH 7/7] Add Test w/ Precedent --- libensemble/tests/unit_tests/test_executor.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libensemble/tests/unit_tests/test_executor.py b/libensemble/tests/unit_tests/test_executor.py index df5c8cc32d..8e988ede4e 100644 --- a/libensemble/tests/unit_tests/test_executor.py +++ b/libensemble/tests/unit_tests/test_executor.py @@ -936,6 +936,25 @@ def test_non_existent_app_mpi(): assert 0 +def test_non_existent_app_precedent(): + """Tests exception on non-existent app is not thrown if precedent is set. + This is common when running apps in containers, where the executable is not + check-able from the host system.""" + from libensemble.executors.executor import Executor + + print(f"\nTest: {sys._getframe().f_code.co_name}\n") + + exctr = Executor() + + # Can register a non-existent app in case created as part of workflow. + exctr.register_app(full_path=non_existent_app, app_name="nonexist") + + w_exctr = Executor.executor # simulate on worker + + # all should be ok + w_exctr.submit(app_name="nonexist", dry_run=True) + + def test_man_signal_unrec_tag(): print(f"\nTest: {sys._getframe().f_code.co_name}\n") @@ -990,5 +1009,6 @@ def test_man_signal_unrec_tag(): test_dry_run() test_non_existent_app() test_non_existent_app_mpi() + test_non_existent_app_precedent() test_man_signal_unrec_tag() teardown_module(__file__)