From 891b3d76471d84bcc678846a78ce8930d3562943 Mon Sep 17 00:00:00 2001 From: Alyssa Travitz Date: Thu, 16 Jan 2025 09:04:13 -0800 Subject: [PATCH 1/6] add special exception and test --- gufe/protocols/errors.py | 5 +++++ gufe/protocols/protocolunit.py | 5 +++-- gufe/tests/test_protocolunit.py | 31 ++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/gufe/protocols/errors.py b/gufe/protocols/errors.py index b9256e46..bcfbb58a 100644 --- a/gufe/protocols/errors.py +++ b/gufe/protocols/errors.py @@ -26,3 +26,8 @@ class MissingUnitResultError(ProtocolDAGResultError): class ProtocolUnitFailureError(ProtocolDAGResultError): """Error when a ProtocolDAGResult has only ProtocolUnitFailure(s) for a given ProtocolUnit.""" + +class ExecutionInterrupt(BaseException): + """Exception for unrecoverable execution failures that are unrelated to user inputs. + Will not be caught by ProtocolUnit.execute(). + """ \ No newline at end of file diff --git a/gufe/protocols/protocolunit.py b/gufe/protocols/protocolunit.py index fba47adb..2d0b809b 100644 --- a/gufe/protocols/protocolunit.py +++ b/gufe/protocols/protocolunit.py @@ -20,6 +20,7 @@ from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union +from .errors import ExecutionInterrupt from ..tokenization import TOKENIZABLE_REGISTRY, GufeKey, GufeTokenizable @@ -328,8 +329,8 @@ def execute( end_time=datetime.datetime.now(), ) - except KeyboardInterrupt: - # if we "fail" due to a KeyboardInterrupt, we always want to raise + except KeyboardInterrupt or ExecutionInterrupt: + # we always want to raise in these situations raise except Exception as e: if raise_error: diff --git a/gufe/tests/test_protocolunit.py b/gufe/tests/test_protocolunit.py index 51a37a47..f89a14df 100644 --- a/gufe/tests/test_protocolunit.py +++ b/gufe/tests/test_protocolunit.py @@ -5,7 +5,7 @@ from gufe.protocols.protocolunit import Context, ProtocolUnit, ProtocolUnitFailure, ProtocolUnitResult from gufe.tests.test_tokenization import GufeTokenizableTestsMixin - +from gufe.protocols.errors import ExecutionInterrupt class DummyUnit(ProtocolUnit): @staticmethod @@ -26,6 +26,14 @@ def _execute(ctx: Context, an_input=2, **inputs): return {"foo": "bar"} +class DummyExecutionInterruptUnit(ProtocolUnit): + @staticmethod + def _execute(ctx: Context, an_input=2, **inputs): + + if an_input != 2: + raise ExecutionInterrupt + + return {"foo": "bar"} @pytest.fixture def dummy_unit(): @@ -77,6 +85,27 @@ def test_execute(self, tmpdir): with pytest.raises(ValueError, match="should always be 2"): unit.execute(context=ctx, raise_error=True, an_input=3) + def test_execute_ExecutionInterrupt(self, tmpdir): + with tmpdir.as_cwd(): + + unit = DummyExecutionInterruptUnit() + + shared = Path("shared") / str(unit.key) + shared.mkdir(parents=True) + + scratch = Path("scratch") / str(unit.key) + scratch.mkdir(parents=True) + + ctx = Context(shared=shared, scratch=scratch) + + with pytest.raises(ExecutionInterrupt): + unit.execute(context=ctx, an_input=3) + + u: ProtocolUnitResult = unit.execute(context=ctx, an_input=2) + + assert u.outputs == {"foo": "bar"} + + def test_execute_KeyboardInterrupt(self, tmpdir): with tmpdir.as_cwd(): From 6130d6a224120416f956d6cfdeee8d9299ec5658 Mon Sep 17 00:00:00 2001 From: Alyssa Travitz Date: Thu, 16 Jan 2025 09:08:02 -0800 Subject: [PATCH 2/6] add news --- news/add_execution_interrupt.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/add_execution_interrupt.rst diff --git a/news/add_execution_interrupt.rst b/news/add_execution_interrupt.rst new file mode 100644 index 00000000..b3826fd5 --- /dev/null +++ b/news/add_execution_interrupt.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ExecutionInterrupt, a special exception that does not get handled as a ``ProtocolUnitFailure``. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 21562c38dae9c29230176646d7e322afcb0d49ce Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:10:33 +0000 Subject: [PATCH 3/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- gufe/protocols/errors.py | 3 ++- gufe/protocols/protocolunit.py | 2 +- gufe/tests/test_protocolunit.py | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/gufe/protocols/errors.py b/gufe/protocols/errors.py index bcfbb58a..6d853a90 100644 --- a/gufe/protocols/errors.py +++ b/gufe/protocols/errors.py @@ -27,7 +27,8 @@ class MissingUnitResultError(ProtocolDAGResultError): class ProtocolUnitFailureError(ProtocolDAGResultError): """Error when a ProtocolDAGResult has only ProtocolUnitFailure(s) for a given ProtocolUnit.""" + class ExecutionInterrupt(BaseException): """Exception for unrecoverable execution failures that are unrelated to user inputs. Will not be caught by ProtocolUnit.execute(). - """ \ No newline at end of file + """ diff --git a/gufe/protocols/protocolunit.py b/gufe/protocols/protocolunit.py index 2d0b809b..1683a9e5 100644 --- a/gufe/protocols/protocolunit.py +++ b/gufe/protocols/protocolunit.py @@ -20,8 +20,8 @@ from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union -from .errors import ExecutionInterrupt from ..tokenization import TOKENIZABLE_REGISTRY, GufeKey, GufeTokenizable +from .errors import ExecutionInterrupt @dataclass diff --git a/gufe/tests/test_protocolunit.py b/gufe/tests/test_protocolunit.py index f89a14df..c3f153fe 100644 --- a/gufe/tests/test_protocolunit.py +++ b/gufe/tests/test_protocolunit.py @@ -3,9 +3,10 @@ import pytest +from gufe.protocols.errors import ExecutionInterrupt from gufe.protocols.protocolunit import Context, ProtocolUnit, ProtocolUnitFailure, ProtocolUnitResult from gufe.tests.test_tokenization import GufeTokenizableTestsMixin -from gufe.protocols.errors import ExecutionInterrupt + class DummyUnit(ProtocolUnit): @staticmethod @@ -26,6 +27,7 @@ def _execute(ctx: Context, an_input=2, **inputs): return {"foo": "bar"} + class DummyExecutionInterruptUnit(ProtocolUnit): @staticmethod def _execute(ctx: Context, an_input=2, **inputs): @@ -35,6 +37,7 @@ def _execute(ctx: Context, an_input=2, **inputs): return {"foo": "bar"} + @pytest.fixture def dummy_unit(): return DummyUnit(name="qux") @@ -105,7 +108,6 @@ def test_execute_ExecutionInterrupt(self, tmpdir): assert u.outputs == {"foo": "bar"} - def test_execute_KeyboardInterrupt(self, tmpdir): with tmpdir.as_cwd(): From 5b19d0a842966d2f20023fa9f8191a00b1ec9cb3 Mon Sep 17 00:00:00 2001 From: Alyssa Travitz Date: Thu, 16 Jan 2025 10:55:24 -0800 Subject: [PATCH 4/6] fixing exception syntax --- gufe/protocols/protocolunit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gufe/protocols/protocolunit.py b/gufe/protocols/protocolunit.py index 1683a9e5..3aede9f7 100644 --- a/gufe/protocols/protocolunit.py +++ b/gufe/protocols/protocolunit.py @@ -329,7 +329,7 @@ def execute( end_time=datetime.datetime.now(), ) - except KeyboardInterrupt or ExecutionInterrupt: + except (KeyboardInterrupt, ExecutionInterrupt): # we always want to raise in these situations raise except Exception as e: From 74c1e621c6a6bbd311fb0e61e29e675f5a10d4e7 Mon Sep 17 00:00:00 2001 From: David Dotson Date: Thu, 16 Jan 2025 17:32:33 -0700 Subject: [PATCH 5/6] Small docstring edit --- gufe/protocols/errors.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gufe/protocols/errors.py b/gufe/protocols/errors.py index 6d853a90..3dddf9d6 100644 --- a/gufe/protocols/errors.py +++ b/gufe/protocols/errors.py @@ -30,5 +30,7 @@ class ProtocolUnitFailureError(ProtocolDAGResultError): class ExecutionInterrupt(BaseException): """Exception for unrecoverable execution failures that are unrelated to user inputs. - Will not be caught by ProtocolUnit.execute(). + + Will not be caught by ``ProtocolUnit.execute()``. + """ From e42ad884c34a75c09063528807ca86bb2ed6d6c2 Mon Sep 17 00:00:00 2001 From: Alyssa Travitz Date: Fri, 17 Jan 2025 14:27:19 -0800 Subject: [PATCH 6/6] updating note --- gufe/protocols/protocolunit.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gufe/protocols/protocolunit.py b/gufe/protocols/protocolunit.py index 3aede9f7..56dcd750 100644 --- a/gufe/protocols/protocolunit.py +++ b/gufe/protocols/protocolunit.py @@ -328,9 +328,8 @@ def execute( start_time=start, end_time=datetime.datetime.now(), ) - except (KeyboardInterrupt, ExecutionInterrupt): - # we always want to raise in these situations + # NOTE: this statement is for clarity, these Interrupts will raise regardless. raise except Exception as e: if raise_error: