From 1bc2bb3605101aa1a56cce5a02fba4648cae0485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 19 Oct 2023 10:59:00 +0200 Subject: [PATCH 1/3] Enhances signal handling, adds force exit capability --- src/pydase/server/server.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/pydase/server/server.py b/src/pydase/server/server.py index 454739f..3b32396 100644 --- a/src/pydase/server/server.py +++ b/src/pydase/server/server.py @@ -358,20 +358,16 @@ class Server: # Signals can only be listened to from the main thread. return - try: - for sig in HANDLED_SIGNALS: - self._loop.add_signal_handler(sig, self.handle_exit, sig, None) - except NotImplementedError: - # Windows - for sig in HANDLED_SIGNALS: - signal.signal(sig, self.handle_exit) + for sig in HANDLED_SIGNALS: + signal.signal(sig, self.handle_exit) def handle_exit(self, sig: int = 0, frame: Optional[FrameType] = None) -> None: - logger.info("Handling exit") if self.should_exit and sig == signal.SIGINT: - self.force_exit = True + logger.warning(f"Received signal {sig}, forcing exit...") + os._exit(1) else: self.should_exit = True + logger.warning(f"Received signal {sig}, exiting...") def custom_exception_handler( self, loop: asyncio.AbstractEventLoop, context: dict[str, Any] From b5b2fb8c35f2aed57a83064956a7f7d35bd23f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 19 Oct 2023 11:11:56 +0200 Subject: [PATCH 2/3] adding signal-handling test --- tests/server/test_server.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/server/test_server.py diff --git a/tests/server/test_server.py b/tests/server/test_server.py new file mode 100644 index 0000000..82e89bd --- /dev/null +++ b/tests/server/test_server.py @@ -0,0 +1,35 @@ +import signal + +from pytest_mock import MockerFixture + +import pydase + + +def test_signal_handling(mocker: MockerFixture): + # Mock os._exit and signal.signal + mock_exit = mocker.patch("os._exit") + mock_signal = mocker.patch("signal.signal") + + class MyService(pydase.DataService): + pass + + # Instantiate your server object + server = pydase.Server(MyService()) + + # Call the method to install signal handlers + server.install_signal_handlers() + + # Check if the signal handlers were registered correctly + assert mock_signal.call_args_list == [ + mocker.call(signal.SIGINT, server.handle_exit), + mocker.call(signal.SIGTERM, server.handle_exit), + ] + + # Simulate receiving a SIGINT signal for the first time + server.handle_exit(signal.SIGINT, None) + assert server.should_exit # assuming should_exit is public + mock_exit.assert_not_called() + + # Simulate receiving a SIGINT signal for the second time + server.handle_exit(signal.SIGINT, None) + mock_exit.assert_called_once_with(1) From b654c7d17649e31fa11c0e2b9e14f1a61f7b35ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 19 Oct 2023 11:12:32 +0200 Subject: [PATCH 3/3] adds pytest-mock to python dependencies --- poetry.lock | 19 ++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index afe1777..9ad89fe 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1536,6 +1536,23 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +[[package]] +name = "pytest-mock" +version = "3.11.1" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, + {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -2012,4 +2029,4 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "409dcbb9f27079667033d1111bdc1ca99436c0e28568562dece75b590aa80e08" +content-hash = "b2763b13a2e00c8094a0c30f6157e72c118bab47ab2d9a0357345b33693e6afa" diff --git a/pyproject.toml b/pyproject.toml index 29182d5..a25d589 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ flake8-pep604 = "^0.1.0" flake8-eradicate = "^1.4.0" matplotlib = "^3.7.2" pyright = "^1.1.323" +pytest-mock = "^3.11.1" [tool.poetry.group.docs.dependencies]