From 47a7cf55020b3c07a81973f53cf8e7f99aa03a11 Mon Sep 17 00:00:00 2001 From: goodboy Date: Tue, 9 Jun 2026 17:20:45 -0400 Subject: [PATCH] Port service+tests to latest `tractor` APIs Continue the `repair_tests`-branch mission (already merged in this stack's ancestry, see f4c4f1e2 which ported `conftest.py`) by fixing the remaining drift breakage vs. `tractor` git `main`; without these NOTHING boots since the `tractor.Address` port in 604e5fcf. Deats, - normalize reg addrs via `wrap_address()` in `open_pikerd()` before `.unwrap()`-ing; entries may be raw `tuple`s when passed in from (test) client code. - port `check_for_service()` to `query_actor(regaddr=)` (was `arbiter_sockaddr=`) incl. its 2-tuple yield and the now-required `open_registry(addrs=)` arg. - `wait_for_actor(registry_addr=)` + `.chan.raddr.unwrap()` raw-tuple compares in `test_runtime_boot` and `ensure_service()`. - update `run_test_w_cancel_method()` for modern `tractor` cancel semantics: self-requested sub-service cancels are absorbed (no `ContextCancelled` raised to the opener) and single-exc groups collapse to a bare KBI. - `RemoteActorError.boxed_type` (was `.type`) and `Position.cumsize` (was `.size`) renames in tests. - bump the paper-EMS startup budget 9 -> 19s; it includes a live (kraken) symbology fetch so needs net headroom. - woops, add the missing comma in `.deribit.api`'s `tractor.trionics` import tuple.. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code Co-Authored-By: Claude Fable 5 --- piker/brokers/deribit/api.py | 2 +- piker/service/_actor_runtime.py | 8 +++- piker/service/_registry.py | 9 ++-- tests/test_ems.py | 4 +- tests/test_services.py | 74 +++++++++++++++++++-------------- 5 files changed, 59 insertions(+), 38 deletions(-) diff --git a/piker/brokers/deribit/api.py b/piker/brokers/deribit/api.py index eb70bfa0..85d490be 100644 --- a/piker/brokers/deribit/api.py +++ b/piker/brokers/deribit/api.py @@ -37,7 +37,7 @@ from rapidfuzz import process as fuzzy import numpy as np from tractor.trionics import ( broadcast_receiver, - maybe_open_context + maybe_open_context, collapse_eg, ) from tractor import to_asyncio diff --git a/piker/service/_actor_runtime.py b/piker/service/_actor_runtime.py index 5bb67c5b..b0f180e4 100644 --- a/piker/service/_actor_runtime.py +++ b/piker/service/_actor_runtime.py @@ -214,7 +214,13 @@ async def open_pikerd( trio.open_nursery() as service_tn, ): for addr in reg_addrs: - uaddr: tuple = addr.unwrap() + # normalize to a wrapped `tractor` addr-type; + # entries may be raw `tuple`s when passed in + # from (test) client code. + wladdr = tractor.discovery._addr.wrap_address( + addr, + ) + uaddr: tuple = wladdr.unwrap() if ( uaddr not in root_actor.accept_addrs ): diff --git a/piker/service/_registry.py b/piker/service/_registry.py index e24539e2..2d787d7c 100644 --- a/piker/service/_registry.py +++ b/piker/service/_registry.py @@ -225,10 +225,13 @@ async def check_for_service( ''' async with ( - open_registry(ensure_exists=False) as reg_addr, + open_registry( + addrs=Registry.addrs, + ensure_exists=False, + ) as reg_addrs, tractor.query_actor( service_name, - arbiter_sockaddr=reg_addr, - ) as sockaddr, + regaddr=reg_addrs[0], + ) as (sockaddr, _), ): return sockaddr diff --git a/tests/test_ems.py b/tests/test_ems.py index 07e28c33..a6adbbf8 100644 --- a/tests/test_ems.py +++ b/tests/test_ems.py @@ -151,7 +151,7 @@ def load_and_check_pos( # is the same the fqme. pp: Position = table.pps[ppmsg.symbol] - assert ppmsg.size == pp.size + assert ppmsg.size == pp.cumsize assert ppmsg.avg_price == pp.ppu yield pp @@ -179,7 +179,7 @@ def test_ems_err_on_bad_broker( # NOTE: emsd should error on the actor's enabled modules # import phase, when looking for a backend named `doggy`. except tractor.RemoteActorError as re: - assert re.type is ModuleNotFoundError + assert re.boxed_type is ModuleNotFoundError run_and_tollerate_cancels(load_bad_fqme) diff --git a/tests/test_services.py b/tests/test_services.py index 433e97f3..69771c09 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -53,11 +53,12 @@ def test_runtime_boot( tractor.wait_for_actor( 'pikerd', - arbiter_sockaddr=daemon_addr, + registry_addr=daemon_addr, ) as portal, ): - assert pikerd_portal.channel.raddr == daemon_addr - assert pikerd_portal.channel.raddr == portal.channel.raddr + uw_raddr: tuple = pikerd_portal.chan.raddr.unwrap() + assert uw_raddr == daemon_addr + assert uw_raddr == portal.chan.raddr.unwrap() # no service tasks should be started assert not services.service_tasks @@ -108,7 +109,7 @@ async def ensure_service( sockaddr: tuple[str, int] | None = None, ) -> None: async with find_service(name) as portal: - remote_sockaddr = portal.channel.raddr + remote_sockaddr: tuple = portal.chan.raddr.unwrap() print(f'FOUND `{name}` @ {remote_sockaddr}') if sockaddr: @@ -131,40 +132,49 @@ def run_test_w_cancel_method( "was remotely cancelled by remote actor (\'pikerd\'") if cancel_method == 'sigint': - with pytest.raises( + # XXX: with modern `tractor` the (single-exc) + # group is collapsed so a bare KBI normally + # propagates; tolerate either form. + with pytest.raises(( + KeyboardInterrupt, BaseExceptionGroup, - ) as exc_info: + )) as exc_info: trio.run(main) - multi = exc_info.value + err = exc_info.value + match err: + case BaseExceptionGroup(): + for suberr in err.exceptions: + match suberr: + # ensure we receive a remote + # cancellation error caused by the + # pikerd root actor. + case tractor.ContextCancelled(): + assert ( + cancelled_msg + in + suberr.args[0] + ) - for suberr in multi.exceptions: - match suberr: - # ensure we receive a remote cancellation error caused - # by the pikerd root actor since we used the - # `.cancel_service()` API above B) - case tractor.ContextCancelled(): - assert cancelled_msg in suberr.args[0] + case KeyboardInterrupt(): + pass - case KeyboardInterrupt(): - pass + case _: + pytest.fail( + f'Unexpected error {suberr}' + ) - case _: - pytest.fail(f'Unexpected error {suberr}') + case KeyboardInterrupt(): + pass elif cancel_method == 'services': - - # XXX NOTE: oddly, when you pass --pdb to pytest, i think since - # we also use that to enable the underlying tractor debug mode, - # it causes this to not raise for some reason? So if you see - # that while changing this test.. it's prolly that. - - with pytest.raises( - tractor.ContextCancelled - ) as exc_info: - trio.run(main) - - assert cancelled_msg in exc_info.value.args[0] + # XXX: cancelling our own sub-service via + # `Services.cancel_service()` is a *self* + # requested cancel: modern `tractor` absorbs the + # resulting `ContextCancelled` (canceller is our + # own actor) so the runtime tears down gracefully + # with NO error raised to the opener. + trio.run(main) else: pytest.fail(f'Test is broken due to {cancel_method}') @@ -197,7 +207,9 @@ def test_ensure_ems_in_paper_actors( # ensure we timeout after is startup is too slow. # TODO: something like this should be our start point for # benchmarking end-to-end startup B) - with trio.fail_after(9): + # NOTE: includes a live (kraken) symbology fetch so + # the budget needs some headroom for net latency.. + with trio.fail_after(19): async with ( open_test_pikerd() as (_, _, _, services),