Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Python 3.12 to CI now that p4p is updated #655

Merged
merged 5 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
3 changes: 2 additions & 1 deletion src/ophyd_async/epics/adcore/_core_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ async def complete_acquisition() -> None:
state = await driver.detector_state.get_value()
if state not in good_states:
raise ValueError(
f"Final detector state {state} not in valid end states: {good_states}"
f"Final detector state {state.value} not in valid end "
f"states: {good_states}"
)

return AsyncStatus(complete_acquisition())
34 changes: 25 additions & 9 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -113,15 +115,22 @@ def fail_test_on_unclosed_tasks(request: FixtureRequest):
by the end of the test.
"""

fail_count = request.session.testsfailed
loop = asyncio.get_event_loop()
loop.set_debug(True)
try:
fail_count = request.session.testsfailed
loop = asyncio.get_running_loop()
evalott100 marked this conversation as resolved.
Show resolved Hide resolved

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
)
)
)
# 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
evalott100 marked this conversation as resolved.
Show resolved Hide resolved


@pytest.fixture(scope="function")
Expand Down Expand Up @@ -242,4 +251,11 @@ def pytest_collection_modifyitems(config, items):

for item in items:
if tango_dir in str(item.fspath):
item.add_marker(pytest.mark.forked)
if sys.version_info >= (3, 12):
item.add_marker(
pytest.mark.skip(
reason="Tango is currently not supported on Python 3.12: https://github.com/bluesky/ophyd-async/issues/681"
)
)
else:
item.add_marker(pytest.mark.forked)
1 change: 1 addition & 0 deletions tests/core/test_mock_signal_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tests/core/test_observe.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async def tick():

async def watch():
async for val in observe_value(sig, done_timeout=0.2):
time.sleep(0.15)
await asyncio.sleep(0.1)
coretl marked this conversation as resolved.
Show resolved Hide resolved
recv.append(val)

t = asyncio.create_task(tick())
Expand All @@ -95,7 +95,7 @@ async def watch():
with pytest.raises(asyncio.TimeoutError):
await watch()
assert recv == [0, 1]
assert time.time() - start == pytest.approx(0.3, abs=0.05)
assert time.time() - start == pytest.approx(0.2, abs=0.05)
finally:
t.cancel()

Expand Down
16 changes: 8 additions & 8 deletions tests/core/test_readable.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ def test_standard_readable_hints():

assert sr.hints == {}

hint1 = MagicMock()
hint1 = MagicMock(spec=HasHints)
evalott100 marked this conversation as resolved.
Show resolved Hide resolved
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])
Expand All @@ -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 = (
Expand All @@ -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 = (
Expand All @@ -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,)
Expand Down
12 changes: 7 additions & 5 deletions tests/epics/adcore/test_drivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,15 @@ async def test_start_acquiring_driver_and_ensure_status_fails_after_some_time(
set_mock_value(driver.detector_state, adcore.DetectorState.IDLE)

async def wait_then_fail():
await asyncio.sleep(0)
await asyncio.sleep(0.1)
set_mock_value(driver.detector_state, adcore.DetectorState.DISCONNECTED)

acquiring = await adcore.start_acquiring_driver_and_ensure_status(
driver, timeout=0.1
)
await wait_then_fail()

with pytest.raises(ValueError):
acquiring = await adcore.start_acquiring_driver_and_ensure_status(
driver, timeout=0.2
)
with pytest.raises(
ValueError, match="Final detector state Disconnected not in valid end states:"
):
await acquiring
6 changes: 4 additions & 2 deletions tests/sim/demo/test_sim_motor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import asyncio
import time

import pytest
from bluesky.plans import spiral_square
from bluesky.run_engine import RunEngine

Expand Down Expand Up @@ -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
evalott100 marked this conversation as resolved.
Show resolved Hide resolved
Loading