Match Trio's startup error exactly
Compare the complete canonical `Nursery.start()` protocol error before re-surfacing ambient cancellation. Preserve child-owned `RuntimeError` objects whose messages only resemble Trio's wording. Cover the colliding prefix and assert the original error remains the exception group's sole leaf. Review: PR #479 (goodboy) https://github.com/goodboy/tractor/pull/479 (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/ai_skillz_run_tests_landing
parent
203a0f7e1f
commit
1c7d0c7f3e
|
|
@ -224,10 +224,10 @@ def test_genuine_startup_rte_still_raised(
|
|||
@pytest.mark.parametrize(
|
||||
'rte_arg',
|
||||
[
|
||||
# a bare `'started' in args[0]` substring match
|
||||
# would (wrongly) demote this one to a `Cancelled`
|
||||
# under ambient cancellation.
|
||||
# Broad substring matches would wrongly demote either
|
||||
# child-owned error to `Cancelled` under cancellation.
|
||||
'never got started!',
|
||||
'child exited without calling user hook',
|
||||
# non-`str` first-arg edge; must not `TypeError`
|
||||
# inside the wrapper's msg-match guard.
|
||||
1234,
|
||||
|
|
@ -242,9 +242,12 @@ def test_childs_own_rte_never_demoted_to_cancel(
|
|||
first arg), raised under ambient cancellation must NOT
|
||||
be demoted to a `trio.Cancelled` by the exact-msg-match
|
||||
guard inside `start_or_cancel()`; the real error must
|
||||
always propagate to the caller unchanged.
|
||||
always propagate to the caller as the sole exception-group
|
||||
leaf, preserving object identity.
|
||||
|
||||
'''
|
||||
child_rte = RuntimeError(rte_arg)
|
||||
|
||||
async def cancels_cs_then_raises(
|
||||
task_status: TaskStatus[None] = (
|
||||
trio.TASK_STATUS_IGNORED
|
||||
|
|
@ -255,7 +258,7 @@ def test_childs_own_rte_never_demoted_to_cancel(
|
|||
# deterministically dies with ITS error while the
|
||||
# caller is under effective cancellation.
|
||||
cs.cancel()
|
||||
raise RuntimeError(rte_arg)
|
||||
raise child_rte
|
||||
|
||||
cs = trio.CancelScope()
|
||||
|
||||
|
|
@ -270,9 +273,7 @@ def test_childs_own_rte_never_demoted_to_cancel(
|
|||
with pytest.raises(ExceptionGroup) as excinfo:
|
||||
trio.run(main)
|
||||
|
||||
rte = excinfo.value.exceptions[0]
|
||||
assert isinstance(rte, RuntimeError)
|
||||
assert rte.args[0] == rte_arg
|
||||
assert excinfo.value.exceptions == (child_rte,)
|
||||
|
||||
|
||||
def test_started_value_and_args_passthru():
|
||||
|
|
|
|||
|
|
@ -349,7 +349,10 @@ async def start_or_cancel(
|
|||
# demote it to a `Cancelled`, losing the real error. The
|
||||
# `isinstance` guard also avoids a `TypeError` when
|
||||
# `rte.args[0]` isn't a `str`.
|
||||
'child exited without calling' in rte.args[0]
|
||||
rte.args[0] == (
|
||||
'child exited without calling '
|
||||
'task_status.started()'
|
||||
)
|
||||
):
|
||||
# re-raises the in-flight `trio.Cancelled` IFF we're
|
||||
# under effective cancellation; else a cheap no-op and
|
||||
|
|
|
|||
Loading…
Reference in New Issue