From 47a6f45881c4a245e3f58ab9c1bb14a7539062ab Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Tue, 19 Nov 2024 09:04:41 +0000 Subject: [PATCH 1/6] Add Python 3.12 to CI and pyproject.toml now that p4p is updated --- .github/workflows/ci.yml | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f5705961..ecdbae1f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: strategy: matrix: runs-on: ["ubuntu-latest", "windows-latest"] # can add macos-latest - python-version: ["3.10", "3.11"] # 3.12 should be added when p4p is updated + python-version: ["3.10","3.11","3.12"] include: # Include one that runs in the dev environment - runs-on: "ubuntu-latest" diff --git a/pyproject.toml b/pyproject.toml index ef4834750..9246ec9ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ classifiers = [ "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] description = "Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango" dependencies = [ From d15f3b33cf54c710ef7a15a48d76da9b486d15df Mon Sep 17 00:00:00 2001 From: Ollie Copping Date: Tue, 19 Nov 2024 13:14:13 +0000 Subject: [PATCH 2/6] Replace get_event_loop() in conftest.py as deprecated in Python 3.12 --- tests/conftest.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index ce6221841..1ac45442b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -114,7 +114,12 @@ def fail_test_on_unclosed_tasks(request: FixtureRequest): """ fail_count = request.session.testsfailed - loop = asyncio.get_event_loop() + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + + asyncio.set_event_loop(loop) loop.set_debug(True) request.addfinalizer( From db1746fb1f8da87922d6766f14c6a9cc8c31dd75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Malinowski?= <56644812+stan-dot@users.noreply.github.com> Date: Mon, 25 Nov 2024 13:28:22 +0000 Subject: [PATCH 3/6] Add the python package and the config and make the contracts kept (#669) * added and all the contracts are kept * respond to feedback --- panda_connect.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 panda_connect.py diff --git a/panda_connect.py b/panda_connect.py new file mode 100644 index 000000000..7e80a189a --- /dev/null +++ b/panda_connect.py @@ -0,0 +1,29 @@ +import asyncio +from pathlib import Path + +import numpy as np + +from ophyd_async.core import StaticFilenameProvider, StaticPathProvider +from ophyd_async.fastcs.panda import HDFPanda, SeqTable + + +async def get_panda(): + panda = HDFPanda( + "PANDA1:", StaticPathProvider(StaticFilenameProvider("test-panda"), Path(".")) + ) + await panda.connect() + assert isinstance(panda, HDFPanda) + table = await panda.seq[1].table.get_value() + assert isinstance(table, SeqTable) + print("OUTA1", table.outa1) + outa2 = table.outa2 + position = table.position + assert isinstance(outa2, np.ndarray) and outa2.dtype == np.bool_, outa2.dtype + assert ( + isinstance(position, np.ndarray) and position.dtype == np.int32 + ), position.dtype + + return panda + + +asyncio.run(get_panda()) From 7633bc3473ee27806368c44870fb5f91b09a3b78 Mon Sep 17 00:00:00 2001 From: Eva Lott Date: Wed, 27 Nov 2024 15:27:51 +0000 Subject: [PATCH 4/6] only fail on unclosed tasks with a running event loop --- tests/conftest.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 1ac45442b..8af1e7e52 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -113,20 +113,21 @@ def fail_test_on_unclosed_tasks(request: FixtureRequest): by the end of the test. """ - fail_count = request.session.testsfailed try: + fail_count = request.session.testsfailed loop = asyncio.get_running_loop() - except RuntimeError: - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - loop.set_debug(True) + asyncio.set_event_loop(loop) + loop.set_debug(True) - request.addfinalizer( - lambda: _error_and_kill_pending_tasks( - loop, request.node.name, request.session.testsfailed == fail_count + request.addfinalizer( + lambda: _error_and_kill_pending_tasks( + loop, request.node.name, request.session.testsfailed == fail_count + ) ) - ) + except RuntimeError as error: + if str(error) != "no running event loop": + raise error @pytest.fixture(scope="function") From 636808013f6a6c5d68937d52c1aeb25848d1a135 Mon Sep 17 00:00:00 2001 From: Eva Lott Date: Wed, 27 Nov 2024 16:05:58 +0000 Subject: [PATCH 5/6] fixed tests other than `_event_processor` deprecation warning --- tests/conftest.py | 7 +++++-- tests/core/test_mock_signal_backend.py | 1 + tests/core/test_readable.py | 16 ++++++++-------- tests/epics/adcore/test_drivers.py | 8 +++++--- tests/sim/demo/test_sim_motor.py | 6 ++++-- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 8af1e7e52..871162d99 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -89,7 +89,9 @@ def _error_and_kill_pending_tasks( unfinished_tasks = { task for task in asyncio.all_tasks(loop) - if task.get_coro().__name__ not in _ALLOWED_PYTEST_TASKS and not task.done() + if (coro := task.get_coro()) is not None + and coro.__name__ not in _ALLOWED_PYTEST_TASKS + and not task.done() } for task in unfinished_tasks: task.cancel() @@ -117,7 +119,6 @@ def fail_test_on_unclosed_tasks(request: FixtureRequest): fail_count = request.session.testsfailed loop = asyncio.get_running_loop() - asyncio.set_event_loop(loop) loop.set_debug(True) request.addfinalizer( @@ -125,6 +126,8 @@ def fail_test_on_unclosed_tasks(request: FixtureRequest): loop, request.node.name, request.session.testsfailed == fail_count ) ) + # Once https://github.com/bluesky/ophyd-async/issues/683 + # is finished we can remove this try, except. except RuntimeError as error: if str(error) != "no running event loop": raise error diff --git a/tests/core/test_mock_signal_backend.py b/tests/core/test_mock_signal_backend.py index 046f0097f..f44e8ef5f 100644 --- a/tests/core/test_mock_signal_backend.py +++ b/tests/core/test_mock_signal_backend.py @@ -185,6 +185,7 @@ async def test_blocks_during_put(mock_signals): with mock_puts_blocked(signal1, signal2): status1 = signal1.set("second_value", wait=True, timeout=None) status2 = signal2.set("second_value", wait=True, timeout=None) + await asyncio.sleep(0.1) assert await signal1.get_value() == "second_value" assert await signal2.get_value() == "second_value" assert not status1.done diff --git a/tests/core/test_readable.py b/tests/core/test_readable.py index 8b39fb404..d0c781d19 100644 --- a/tests/core/test_readable.py +++ b/tests/core/test_readable.py @@ -32,13 +32,13 @@ def test_standard_readable_hints(): assert sr.hints == {} - hint1 = MagicMock() + hint1 = MagicMock(spec=HasHints) hint1.hints = {"fields": ["abc"], "dimensions": [(["f1", "f2"], "s1")]} - hint2 = MagicMock() + hint2 = MagicMock(spec=HasHints) hint2.hints = {"fields": ["def", "ghi"]} - hint3 = MagicMock() + hint3 = MagicMock(spec=HasHints) hint3.hints = {"fields": ["jkl"], "gridding": "rectilinear_nonsequential"} sr.add_readables([hint1, hint2, hint3]) @@ -53,10 +53,10 @@ def test_standard_readable_hints(): def test_standard_readable_hints_raises_when_overriding_string_literal(): sr = StandardReadable() - hint1 = MagicMock() + hint1 = MagicMock(spec=HasHints) hint1.hints = {"gridding": "rectilinear_nonsequential"} - hint2 = MagicMock() + hint2 = MagicMock(spec=HasHints) hint2.hints = {"gridding": "a different string"} sr._has_hints = ( @@ -71,10 +71,10 @@ def test_standard_readable_hints_raises_when_overriding_string_literal(): def test_standard_readable_hints_raises_when_overriding_sequence(): sr = StandardReadable() - hint1 = MagicMock() + hint1 = MagicMock(spec=HasHints) hint1.hints = {"fields": ["field1", "field2"]} - hint2 = MagicMock() + hint2 = MagicMock(spec=HasHints) hint2.hints = {"fields": ["field2"]} sr._has_hints = ( @@ -90,7 +90,7 @@ def test_standard_readable_hints_raises_when_overriding_sequence(): def test_standard_readable_hints_invalid_types(invalid_type): sr = StandardReadable() - hint1 = MagicMock() + hint1 = MagicMock(spec=HasHints) hint1.hints = {"test": invalid_type} sr._has_hints = (hint1,) diff --git a/tests/epics/adcore/test_drivers.py b/tests/epics/adcore/test_drivers.py index f2b2dcadc..e04ee9ff1 100644 --- a/tests/epics/adcore/test_drivers.py +++ b/tests/epics/adcore/test_drivers.py @@ -90,10 +90,12 @@ async def wait_then_fail(): await asyncio.sleep(0) set_mock_value(driver.detector_state, adcore.DetectorState.DISCONNECTED) + await wait_then_fail() + acquiring = await adcore.start_acquiring_driver_and_ensure_status( driver, timeout=0.1 ) - await wait_then_fail() - - with pytest.raises(ValueError): + with pytest.raises( + ValueError, match="Final detector state DetectorState.DISCONNECTED" + ): await acquiring diff --git a/tests/sim/demo/test_sim_motor.py b/tests/sim/demo/test_sim_motor.py index 9a8ac75a6..d879c717b 100644 --- a/tests/sim/demo/test_sim_motor.py +++ b/tests/sim/demo/test_sim_motor.py @@ -1,6 +1,7 @@ import asyncio import time +import pytest from bluesky.plans import spiral_square from bluesky.run_engine import RunEngine @@ -49,6 +50,7 @@ async def test_stop(): new_pos = await m1.user_readback.get_value() assert new_pos < 10 assert new_pos >= 0.1 - # move should not be successful as we stopped it - assert move_status.done + assert not move_status.success + with pytest.raises(RuntimeError, match="Motor was stopped"): + await move_status From ad985e705006a614d92fcc4535e49dea3d050c5e Mon Sep 17 00:00:00 2001 From: Eva Lott Date: Wed, 27 Nov 2024 16:43:55 +0000 Subject: [PATCH 6/6] ignored tango deprecation warning This will be handled seperately in https://github.com/bluesky/ophyd-async/issues/681. --- panda_connect.py | 29 ----------------------------- pyproject.toml | 8 ++++++-- 2 files changed, 6 insertions(+), 31 deletions(-) delete mode 100644 panda_connect.py diff --git a/panda_connect.py b/panda_connect.py deleted file mode 100644 index 7e80a189a..000000000 --- a/panda_connect.py +++ /dev/null @@ -1,29 +0,0 @@ -import asyncio -from pathlib import Path - -import numpy as np - -from ophyd_async.core import StaticFilenameProvider, StaticPathProvider -from ophyd_async.fastcs.panda import HDFPanda, SeqTable - - -async def get_panda(): - panda = HDFPanda( - "PANDA1:", StaticPathProvider(StaticFilenameProvider("test-panda"), Path(".")) - ) - await panda.connect() - assert isinstance(panda, HDFPanda) - table = await panda.seq[1].table.get_value() - assert isinstance(table, SeqTable) - print("OUTA1", table.outa1) - outa2 = table.outa2 - position = table.position - assert isinstance(outa2, np.ndarray) and outa2.dtype == np.bool_, outa2.dtype - assert ( - isinstance(position, np.ndarray) and position.dtype == np.int32 - ), position.dtype - - return panda - - -asyncio.run(get_panda()) diff --git a/pyproject.toml b/pyproject.toml index 9246ec9ba..0b71859b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,8 +99,12 @@ addopts = """ --doctest-glob="*.rst" --doctest-glob="*.md" --ignore=docs/examples --ignore=src/ophyd_async/epics/signal.py """ -# https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings -filterwarnings = "error" +# "error" for https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings +# "tango" for https://github.com/bluesky/ophyd-async/issues/681 +filterwarnings = """ +error +ignore::DeprecationWarning:tango.asyncio_executor: +""" # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "docs src tests" log_format = "%(asctime)s,%(msecs)03d %(levelname)s (%(threadName)s) %(message)s"