piker/tests/test_services.py

360 lines
9.9 KiB
Python
Raw Normal View History

'''
Actor tree daemon sub-service verifications
'''
from typing import (
AsyncContextManager,
Callable,
)
from contextlib import asynccontextmanager as acm
from types import SimpleNamespace
from exceptiongroup import BaseExceptionGroup
import pytest
import trio
import tractor
from piker.service import (
find_service,
Services,
)
from piker.service import _registry
from piker.data import (
open_feed,
)
from piker.clearing import (
open_ems,
)
from piker.clearing._messages import (
BrokerdPosition,
Status,
)
from piker.clearing._client import (
OrderClient,
)
def test_runtime_boot(
open_test_pikerd: AsyncContextManager
):
'''
Verify we can boot the `pikerd` service stack using the
`open_test_pikerd()` fixture helper and that contact-registry
address details match up.
'''
async def main():
port = 6666
daemon_addr = ('127.0.0.1', port)
services: Services
async with (
open_test_pikerd(
reg_addr=daemon_addr,
) as (_, _, pikerd_portal, services),
tractor.wait_for_actor(
'pikerd',
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
registry_addr=daemon_addr,
) as portal,
):
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
uw_raddr: tuple = pikerd_portal.chan.raddr.unwrap()
canonical_addr: tuple = (
_registry._normalize_addresses(
[daemon_addr],
)[0]
)
assert uw_raddr == canonical_addr
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
assert uw_raddr == portal.chan.raddr.unwrap()
# no service tasks should be started
assert not services.service_tasks
trio.run(main)
def test_registry_normalizes_tagged_addresses(
monkeypatch: pytest.MonkeyPatch,
):
'''
Tractor now emits tagged registry addresses while existing Piker
callers still pass legacy socket pairs. Direct list and set
comparisons treated the two forms as different and retained the
legacy value in `Registry.addrs`.
Seed `Registry.addrs` with a legacy pair, request the equivalent
tagged address, and enter `open_registry()` as a root actor. The
yielded and stored values must both use tractor's canonical form.
'''
legacy = ('127.0.0.1', 6116)
tagged = ('tcp', '127.0.0.1', 6116)
actor = SimpleNamespace(
aid=SimpleNamespace(uid=('test', 'uid')),
)
monkeypatch.setattr(
tractor,
'current_actor',
lambda: actor,
)
monkeypatch.setattr(
tractor,
'is_root_process',
lambda: True,
)
_registry.Registry.addrs = [legacy]
async def main():
async with _registry.open_registry(
[tagged],
) as addrs:
assert addrs == [tagged]
assert _registry.Registry.addrs == [tagged]
assert _registry._tractor_kwargs[
'registry_addrs'
] == [tagged]
try:
trio.run(main)
finally:
_registry.Registry.addrs = []
Add `datad` daemon machinery to `.data` First half of the `brokerd` split: a new per-provider data-feed-only daemon-actor `datad.<broker>` to (soon) host all `validate._eps['datad']` eps (live quotes, history loading, symbology search) leaving `brokerd` for live order ctl only. Purely additive; nothing routes through it yet. Deats, - new `piker.data._daemon` mod mirroring the `.brokers._daemon` conventions (and the `samplerd` sub-daemon precedent): - `_setup_persistent_datad()` lifetime fixture owning the actor-global `_FeedsBus` alloc. - `datad_init()` building `enable_modules` from the backend's `_datad_mods` (falling back to `__enable_modules__` for not-yet-split backends) and copying `_spawn_kwargs` (critical for `ib`'s `infect_asyncio`). - `spawn_datad()`/`maybe_spawn_datad()` wrapping `Services` + `maybe_spawn_daemon()`. - add `piker.data._daemon` to `_root_modules` so `pikerd` can run `spawn_datad()` requests. - re-export the spawn eps from `piker.service`. - add `test_datad_spawn` verifying actor boot + service registration via `ensure_service('datad.kraken')`. Note the `Services`-based impl style deliberately mirrors `spawn_brokerd()` so the eventual `tractor.hilevel` `ServiceMngr` port (see the `service_mng_to_tractor` branch's d8c21d44 prep work) lands symmetrically on both. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171142Z_119d2c04_prompt_io.md
2026-06-10 17:12:26 +00:00
def test_datad_spawn(
open_test_pikerd: AsyncContextManager,
loglevel: str,
) -> None:
'''
Verify the new (data-feed-only) `datad.<broker>` daemon
can be spawned/registered as a `pikerd` sub-service via
the `maybe_spawn_datad()` factory.
'''
from piker.service import maybe_spawn_datad
backend: str = 'kraken'
datad_name: str = f'datad.{backend}'
async def main():
async with (
open_test_pikerd() as (_, _, _, services),
maybe_spawn_datad(
backend,
loglevel=loglevel,
) as portal,
):
assert portal
async with ensure_service(datad_name):
assert (
datad_name in services.service_tasks
)
trio.run(main)
def test_ensure_datafeed_actors(
open_test_pikerd: AsyncContextManager,
loglevel: str,
# cancel_method: str,
) -> None:
'''
.data: cut feed layer over to `datad` actors The topology flip: all data-feed consumers now route to the new `datad.<broker>` sibling daemon; `brokerd` becomes trading-only and is ONLY ever booted lazily by `emsd`'s `open_brokerd_dialog()` (see prior commit). Chart-only and paper sessions run with zero (live, credentialed) `brokerd` procs B) Deats, - `open_feed()` -> `maybe_spawn_datad()` (NB: imported relative-direct from `._daemon` to dodge a partial-init cycle via `piker.service`); flip the `open_feed_bus()` actor-name assert to `'datad'`; comment sweep. - slim `_setup_persistent_brokerd()` to a trading-only fixture: console logging + pinned-open ctx; the feed-bus alloc moves to `_setup_persistent_datad()` and backend `open_trade_dialog()` ctxs own their own task trees. (the `piker ledger` ad-hoc actor enters this same slimmed fixture - exactly what it needs.) - repoint data-flavoured spawn sites to `maybe_spawn_datad`: `.ui._app` symbol-search (+ rename `install_brokerd_search` -> `install_datad_search`), `.brokers.core.symbol_search()`, `.brokers.cli` `brokercheck`/`record`, legacy kivy `.ui.cli` + `option_chain`'s `wait_for_actor()`. - invert `tests.test_services` expectations: feed/EMS-paper flows must spawn `datad.kraken` and `paperboi.kraken` with an explicit negative assert that NO `brokerd.kraken` service task exists. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
2026-06-10 17:13:44 +00:00
Verify that booting a data feed starts a `datad`
actor and a singleton global `samplerd` and opening
an order mode in paper opens the `paperboi` service.
'''
.data: cut feed layer over to `datad` actors The topology flip: all data-feed consumers now route to the new `datad.<broker>` sibling daemon; `brokerd` becomes trading-only and is ONLY ever booted lazily by `emsd`'s `open_brokerd_dialog()` (see prior commit). Chart-only and paper sessions run with zero (live, credentialed) `brokerd` procs B) Deats, - `open_feed()` -> `maybe_spawn_datad()` (NB: imported relative-direct from `._daemon` to dodge a partial-init cycle via `piker.service`); flip the `open_feed_bus()` actor-name assert to `'datad'`; comment sweep. - slim `_setup_persistent_brokerd()` to a trading-only fixture: console logging + pinned-open ctx; the feed-bus alloc moves to `_setup_persistent_datad()` and backend `open_trade_dialog()` ctxs own their own task trees. (the `piker ledger` ad-hoc actor enters this same slimmed fixture - exactly what it needs.) - repoint data-flavoured spawn sites to `maybe_spawn_datad`: `.ui._app` symbol-search (+ rename `install_brokerd_search` -> `install_datad_search`), `.brokers.core.symbol_search()`, `.brokers.cli` `brokercheck`/`record`, legacy kivy `.ui.cli` + `option_chain`'s `wait_for_actor()`. - invert `tests.test_services` expectations: feed/EMS-paper flows must spawn `datad.kraken` and `paperboi.kraken` with an explicit negative assert that NO `brokerd.kraken` service task exists. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
2026-06-10 17:13:44 +00:00
actor_name: str = 'datad'
backend: str = 'kraken'
.data: cut feed layer over to `datad` actors The topology flip: all data-feed consumers now route to the new `datad.<broker>` sibling daemon; `brokerd` becomes trading-only and is ONLY ever booted lazily by `emsd`'s `open_brokerd_dialog()` (see prior commit). Chart-only and paper sessions run with zero (live, credentialed) `brokerd` procs B) Deats, - `open_feed()` -> `maybe_spawn_datad()` (NB: imported relative-direct from `._daemon` to dodge a partial-init cycle via `piker.service`); flip the `open_feed_bus()` actor-name assert to `'datad'`; comment sweep. - slim `_setup_persistent_brokerd()` to a trading-only fixture: console logging + pinned-open ctx; the feed-bus alloc moves to `_setup_persistent_datad()` and backend `open_trade_dialog()` ctxs own their own task trees. (the `piker ledger` ad-hoc actor enters this same slimmed fixture - exactly what it needs.) - repoint data-flavoured spawn sites to `maybe_spawn_datad`: `.ui._app` symbol-search (+ rename `install_brokerd_search` -> `install_datad_search`), `.brokers.core.symbol_search()`, `.brokers.cli` `brokercheck`/`record`, legacy kivy `.ui.cli` + `option_chain`'s `wait_for_actor()`. - invert `tests.test_services` expectations: feed/EMS-paper flows must spawn `datad.kraken` and `paperboi.kraken` with an explicit negative assert that NO `brokerd.kraken` service task exists. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
2026-06-10 17:13:44 +00:00
datad_name: str = f'{actor_name}.{backend}'
async def main():
async with (
open_test_pikerd(),
open_feed(
['xbtusdt.kraken'],
loglevel=loglevel,
) as feed
):
# halt rt quote streams since we aren't testing them
await feed.pause()
async with (
.data: cut feed layer over to `datad` actors The topology flip: all data-feed consumers now route to the new `datad.<broker>` sibling daemon; `brokerd` becomes trading-only and is ONLY ever booted lazily by `emsd`'s `open_brokerd_dialog()` (see prior commit). Chart-only and paper sessions run with zero (live, credentialed) `brokerd` procs B) Deats, - `open_feed()` -> `maybe_spawn_datad()` (NB: imported relative-direct from `._daemon` to dodge a partial-init cycle via `piker.service`); flip the `open_feed_bus()` actor-name assert to `'datad'`; comment sweep. - slim `_setup_persistent_brokerd()` to a trading-only fixture: console logging + pinned-open ctx; the feed-bus alloc moves to `_setup_persistent_datad()` and backend `open_trade_dialog()` ctxs own their own task trees. (the `piker ledger` ad-hoc actor enters this same slimmed fixture - exactly what it needs.) - repoint data-flavoured spawn sites to `maybe_spawn_datad`: `.ui._app` symbol-search (+ rename `install_brokerd_search` -> `install_datad_search`), `.brokers.core.symbol_search()`, `.brokers.cli` `brokercheck`/`record`, legacy kivy `.ui.cli` + `option_chain`'s `wait_for_actor()`. - invert `tests.test_services` expectations: feed/EMS-paper flows must spawn `datad.kraken` and `paperboi.kraken` with an explicit negative assert that NO `brokerd.kraken` service task exists. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
2026-06-10 17:13:44 +00:00
ensure_service(datad_name),
ensure_service('samplerd'),
):
await trio.sleep(0.1)
trio.run(main)
@acm
async def ensure_service(
name: str,
sockaddr: tuple[str, int] | None = None,
) -> None:
async with find_service(name) as portal:
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
remote_sockaddr: tuple = portal.chan.raddr.unwrap()
print(f'FOUND `{name}` @ {remote_sockaddr}')
if sockaddr:
assert remote_sockaddr == sockaddr
yield portal
def run_test_w_cancel_method(
cancel_method: str,
main: Callable,
) -> None:
'''
Run our runtime under trio and expect a certain type of cancel condition
depending on input.
'''
cancelled_msg: str = (
"was remotely cancelled by remote actor (\'pikerd\'")
if cancel_method == 'sigint':
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
# XXX: with modern `tractor` the (single-exc)
# group is collapsed so a bare KBI normally
# propagates; tolerate either form.
with pytest.raises((
KeyboardInterrupt,
BaseExceptionGroup,
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
)) as exc_info:
trio.run(main)
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
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]
)
case KeyboardInterrupt():
pass
case _:
pytest.fail(
f'Unexpected error {suberr}'
)
case KeyboardInterrupt():
pass
elif cancel_method == 'services':
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
# 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}')
@pytest.mark.parametrize(
'cancel_method',
['services', 'sigint'],
)
def test_ensure_ems_in_paper_actors(
open_test_pikerd: AsyncContextManager,
loglevel: str,
cancel_method: str,
) -> None:
backend: str = 'kraken'
.data: cut feed layer over to `datad` actors The topology flip: all data-feed consumers now route to the new `datad.<broker>` sibling daemon; `brokerd` becomes trading-only and is ONLY ever booted lazily by `emsd`'s `open_brokerd_dialog()` (see prior commit). Chart-only and paper sessions run with zero (live, credentialed) `brokerd` procs B) Deats, - `open_feed()` -> `maybe_spawn_datad()` (NB: imported relative-direct from `._daemon` to dodge a partial-init cycle via `piker.service`); flip the `open_feed_bus()` actor-name assert to `'datad'`; comment sweep. - slim `_setup_persistent_brokerd()` to a trading-only fixture: console logging + pinned-open ctx; the feed-bus alloc moves to `_setup_persistent_datad()` and backend `open_trade_dialog()` ctxs own their own task trees. (the `piker ledger` ad-hoc actor enters this same slimmed fixture - exactly what it needs.) - repoint data-flavoured spawn sites to `maybe_spawn_datad`: `.ui._app` symbol-search (+ rename `install_brokerd_search` -> `install_datad_search`), `.brokers.core.symbol_search()`, `.brokers.cli` `brokercheck`/`record`, legacy kivy `.ui.cli` + `option_chain`'s `wait_for_actor()`. - invert `tests.test_services` expectations: feed/EMS-paper flows must spawn `datad.kraken` and `paperboi.kraken` with an explicit negative assert that NO `brokerd.kraken` service task exists. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
2026-06-10 17:13:44 +00:00
datad_name: str = f'datad.{backend}'
brokerd_name: str = f'brokerd.{backend}'
async def main():
# type declares
client: OrderClient
pps: dict[str, list[BrokerdPosition]]
accounts: list[str]
dialogs: dict[str, Status]
# 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)
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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
2026-06-10 17:11:05 +00:00
# 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),
open_ems(
'xbtusdt.kraken',
mode='paper',
loglevel=loglevel,
) as (
client,
_, # trades_stream: tractor.MsgStream
pps,
accounts,
dialogs,
),
):
# there should be no on-going positions,
# TODO: though eventually we'll want to validate against
# local ledger and `pps.toml` state ;)
assert not pps
assert not dialogs
# XXX: should be new client with no state from other tests
assert not client._sent_orders
assert accounts
pikerd_subservices = ['emsd', 'samplerd']
async with (
ensure_service('emsd'),
.data: cut feed layer over to `datad` actors The topology flip: all data-feed consumers now route to the new `datad.<broker>` sibling daemon; `brokerd` becomes trading-only and is ONLY ever booted lazily by `emsd`'s `open_brokerd_dialog()` (see prior commit). Chart-only and paper sessions run with zero (live, credentialed) `brokerd` procs B) Deats, - `open_feed()` -> `maybe_spawn_datad()` (NB: imported relative-direct from `._daemon` to dodge a partial-init cycle via `piker.service`); flip the `open_feed_bus()` actor-name assert to `'datad'`; comment sweep. - slim `_setup_persistent_brokerd()` to a trading-only fixture: console logging + pinned-open ctx; the feed-bus alloc moves to `_setup_persistent_datad()` and backend `open_trade_dialog()` ctxs own their own task trees. (the `piker ledger` ad-hoc actor enters this same slimmed fixture - exactly what it needs.) - repoint data-flavoured spawn sites to `maybe_spawn_datad`: `.ui._app` symbol-search (+ rename `install_brokerd_search` -> `install_datad_search`), `.brokers.core.symbol_search()`, `.brokers.cli` `brokercheck`/`record`, legacy kivy `.ui.cli` + `option_chain`'s `wait_for_actor()`. - invert `tests.test_services` expectations: feed/EMS-paper flows must spawn `datad.kraken` and `paperboi.kraken` with an explicit negative assert that NO `brokerd.kraken` service task exists. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
2026-06-10 17:13:44 +00:00
ensure_service(datad_name),
ensure_service(f'paperboi.{backend}'),
):
for name in pikerd_subservices:
assert name in services.service_tasks
.data: cut feed layer over to `datad` actors The topology flip: all data-feed consumers now route to the new `datad.<broker>` sibling daemon; `brokerd` becomes trading-only and is ONLY ever booted lazily by `emsd`'s `open_brokerd_dialog()` (see prior commit). Chart-only and paper sessions run with zero (live, credentialed) `brokerd` procs B) Deats, - `open_feed()` -> `maybe_spawn_datad()` (NB: imported relative-direct from `._daemon` to dodge a partial-init cycle via `piker.service`); flip the `open_feed_bus()` actor-name assert to `'datad'`; comment sweep. - slim `_setup_persistent_brokerd()` to a trading-only fixture: console logging + pinned-open ctx; the feed-bus alloc moves to `_setup_persistent_datad()` and backend `open_trade_dialog()` ctxs own their own task trees. (the `piker ledger` ad-hoc actor enters this same slimmed fixture - exactly what it needs.) - repoint data-flavoured spawn sites to `maybe_spawn_datad`: `.ui._app` symbol-search (+ rename `install_brokerd_search` -> `install_datad_search`), `.brokers.core.symbol_search()`, `.brokers.cli` `brokercheck`/`record`, legacy kivy `.ui.cli` + `option_chain`'s `wait_for_actor()`. - invert `tests.test_services` expectations: feed/EMS-paper flows must spawn `datad.kraken` and `paperboi.kraken` with an explicit negative assert that NO `brokerd.kraken` service task exists. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
2026-06-10 17:13:44 +00:00
# datad.kraken actor should have been
# started implicitly by the feed layer.
assert datad_name in services.service_tasks
# XXX: paper-mode sessions should NEVER
# boot a (live, credentialed) `brokerd`;
# only emsd's `open_brokerd_dialog()`
# live-ep path is allowed to spawn it!
assert (
brokerd_name
not in
services.service_tasks
)
print('ALL SERVICES STARTED, cancelling runtime with:\n'
f'-> {cancel_method}')
if cancel_method == 'services':
await services.cancel_service('emsd')
elif cancel_method == 'sigint':
raise KeyboardInterrupt
run_test_w_cancel_method(cancel_method, main)