From db1619ab8e77d795b40266e6292bbfc625f9cc47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Sat, 15 Feb 2025 16:58:57 +0100 Subject: [PATCH 1/7] Fix info --- executorlib/interactive/dependency.py | 17 +++++++++++++ tests/test_dependencies_executor.py | 35 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/executorlib/interactive/dependency.py b/executorlib/interactive/dependency.py index 9cbbfb35..d0fd0e04 100644 --- a/executorlib/interactive/dependency.py +++ b/executorlib/interactive/dependency.py @@ -65,6 +65,18 @@ def __init__( else: self._generate_dependency_graph = True + @property + def info(self) -> Optional[dict]: + """ + Get the information about the executor. + + Returns: + Optional[dict]: Information about the executor. + """ + f = Future() + self._future_queue.queue.insert(0, {"internal": True, "task": "info", "future": f}) + return f.result() + def submit( # type: ignore self, fn: Callable[..., Any], @@ -168,6 +180,11 @@ def _execute_tasks_with_dependencies( future_queue.task_done() future_queue.join() break + if ( # shutdown the executor + task_dict is not None and "internal" in task_dict and task_dict["internal"] + ): + if task_dict["task"] == "info": + task_dict["future"].set_result(executor.info) elif ( # handle function submitted to the executor task_dict is not None and "fn" in task_dict and "future" in task_dict ): diff --git a/tests/test_dependencies_executor.py b/tests/test_dependencies_executor.py index 3650845a..0201f9b6 100644 --- a/tests/test_dependencies_executor.py +++ b/tests/test_dependencies_executor.py @@ -8,6 +8,7 @@ from executorlib.interfaces.single import create_single_node_executor from executorlib.interactive.dependency import _execute_tasks_with_dependencies from executorlib.standalone.serialize import cloudpickle_register +from executorlib.standalone.interactive.spawner import MpiExecSpawner try: @@ -327,3 +328,37 @@ def test_block_allocation_true_two_workers_loop(self): parameter=lst, ) lst.result() + + +class TestInfo(unittest.TestCase): + def test_info_disable_dependencies_true(self): + with SingleNodeExecutor(disable_dependencies=True) as exe: + self.assertEqual( + exe.info, + { + 'cores': 1, + 'cwd': None, + 'openmpi_oversubscribe': False, + 'cache_directory': None, + 'hostname_localhost': None, + 'spawner': MpiExecSpawner, + 'max_cores': None, + 'max_workers': None, + } + ) + + def test_info_disable_dependencies_false(self): + with SingleNodeExecutor(disable_dependencies=False) as exe: + self.assertEqual( + exe.info, + { + 'cores': 1, + 'cwd': None, + 'openmpi_oversubscribe': False, + 'cache_directory': None, + 'hostname_localhost': None, + 'spawner': MpiExecSpawner, + 'max_cores': None, + 'max_workers': None, + } + ) \ No newline at end of file From 01fa9be71c9028372cb889dea0a8775825da6ff8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:59:22 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- executorlib/interactive/dependency.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/executorlib/interactive/dependency.py b/executorlib/interactive/dependency.py index d0fd0e04..518c12dd 100644 --- a/executorlib/interactive/dependency.py +++ b/executorlib/interactive/dependency.py @@ -74,7 +74,9 @@ def info(self) -> Optional[dict]: Optional[dict]: Information about the executor. """ f = Future() - self._future_queue.queue.insert(0, {"internal": True, "task": "info", "future": f}) + self._future_queue.queue.insert( + 0, {"internal": True, "task": "info", "future": f} + ) return f.result() def submit( # type: ignore From f20e84d3a746194f1ff8256777ca985290d9f8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Sat, 15 Feb 2025 17:04:17 +0100 Subject: [PATCH 3/7] fix type check --- executorlib/interactive/dependency.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/executorlib/interactive/dependency.py b/executorlib/interactive/dependency.py index d0fd0e04..1ad34ef0 100644 --- a/executorlib/interactive/dependency.py +++ b/executorlib/interactive/dependency.py @@ -73,8 +73,9 @@ def info(self) -> Optional[dict]: Returns: Optional[dict]: Information about the executor. """ - f = Future() - self._future_queue.queue.insert(0, {"internal": True, "task": "info", "future": f}) + f: Future = Future() + if isinstance(self._future_queue, queue.Queue): + self._future_queue.queue.insert(0, {"internal": True, "task": "info", "future": f}) return f.result() def submit( # type: ignore From 04174e79d1e465837bb40763564efd007fae67fa Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Sat, 15 Feb 2025 17:11:56 +0100 Subject: [PATCH 4/7] Update tests/test_dependencies_executor.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- tests/test_dependencies_executor.py | 51 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/tests/test_dependencies_executor.py b/tests/test_dependencies_executor.py index 0201f9b6..1af3527f 100644 --- a/tests/test_dependencies_executor.py +++ b/tests/test_dependencies_executor.py @@ -331,34 +331,33 @@ def test_block_allocation_true_two_workers_loop(self): class TestInfo(unittest.TestCase): + """Test cases for the info property of SingleNodeExecutor.""" + + def setUp(self): + """Set up the expected info dictionary.""" + self.expected_info = { + 'cores': 1, + 'cwd': None, + 'openmpi_oversubscribe': False, + 'cache_directory': None, + 'hostname_localhost': None, + 'spawner': MpiExecSpawner, + 'max_cores': None, + 'max_workers': None, + } + def test_info_disable_dependencies_true(self): + """Test info property with dependencies disabled.""" with SingleNodeExecutor(disable_dependencies=True) as exe: - self.assertEqual( - exe.info, - { - 'cores': 1, - 'cwd': None, - 'openmpi_oversubscribe': False, - 'cache_directory': None, - 'hostname_localhost': None, - 'spawner': MpiExecSpawner, - 'max_cores': None, - 'max_workers': None, - } - ) + self.assertEqual(exe.info, self.expected_info) def test_info_disable_dependencies_false(self): + """Test info property with dependencies enabled.""" with SingleNodeExecutor(disable_dependencies=False) as exe: - self.assertEqual( - exe.info, - { - 'cores': 1, - 'cwd': None, - 'openmpi_oversubscribe': False, - 'cache_directory': None, - 'hostname_localhost': None, - 'spawner': MpiExecSpawner, - 'max_cores': None, - 'max_workers': None, - } - ) \ No newline at end of file + self.assertEqual(exe.info, self.expected_info) + + def test_info_error_handling(self): + """Test info property error handling when executor is not running.""" + exe = SingleNodeExecutor() + with self.assertRaises(Exception): + _ = exe.info \ No newline at end of file From 81c4b73ffe14ff2048bc3e43206e6da390f1e1d3 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Sat, 15 Feb 2025 17:13:06 +0100 Subject: [PATCH 5/7] Update test_dependencies_executor.py --- tests/test_dependencies_executor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_dependencies_executor.py b/tests/test_dependencies_executor.py index 1af3527f..4e4780d3 100644 --- a/tests/test_dependencies_executor.py +++ b/tests/test_dependencies_executor.py @@ -359,5 +359,5 @@ def test_info_disable_dependencies_false(self): def test_info_error_handling(self): """Test info property error handling when executor is not running.""" exe = SingleNodeExecutor() - with self.assertRaises(Exception): - _ = exe.info \ No newline at end of file + exe.shutdown(wait=True) + self.assertIsNone(exe.info) From af3f9c7cb0627f4eed597003011b14a8940ad85a Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Sat, 15 Feb 2025 17:14:20 +0100 Subject: [PATCH 6/7] Update dependency.py --- executorlib/interactive/dependency.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/executorlib/interactive/dependency.py b/executorlib/interactive/dependency.py index 4db50995..9ee81b9f 100644 --- a/executorlib/interactive/dependency.py +++ b/executorlib/interactive/dependency.py @@ -73,12 +73,12 @@ def info(self) -> Optional[dict]: Returns: Optional[dict]: Information about the executor. """ - f: Future = Future() if isinstance(self._future_queue, queue.Queue): + f: Future = Future() self._future_queue.queue.insert( 0, {"internal": True, "task": "info", "future": f} ) - return f.result() + return f.result() def submit( # type: ignore self, From 2b0d1272d140bc75ef8f8cf489b5846c5ca4008c Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Sat, 15 Feb 2025 17:24:20 +0100 Subject: [PATCH 7/7] Update dependency.py --- executorlib/interactive/dependency.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/executorlib/interactive/dependency.py b/executorlib/interactive/dependency.py index 9ee81b9f..95c7ca98 100644 --- a/executorlib/interactive/dependency.py +++ b/executorlib/interactive/dependency.py @@ -79,6 +79,8 @@ def info(self) -> Optional[dict]: 0, {"internal": True, "task": "info", "future": f} ) return f.result() + else: + return None def submit( # type: ignore self,