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(
|
@pytest.mark.parametrize(
|
||||||
'rte_arg',
|
'rte_arg',
|
||||||
[
|
[
|
||||||
# a bare `'started' in args[0]` substring match
|
# Broad substring matches would wrongly demote either
|
||||||
# would (wrongly) demote this one to a `Cancelled`
|
# child-owned error to `Cancelled` under cancellation.
|
||||||
# under ambient cancellation.
|
|
||||||
'never got started!',
|
'never got started!',
|
||||||
|
'child exited without calling user hook',
|
||||||
# non-`str` first-arg edge; must not `TypeError`
|
# non-`str` first-arg edge; must not `TypeError`
|
||||||
# inside the wrapper's msg-match guard.
|
# inside the wrapper's msg-match guard.
|
||||||
1234,
|
1234,
|
||||||
|
|
@ -242,9 +242,12 @@ def test_childs_own_rte_never_demoted_to_cancel(
|
||||||
first arg), raised under ambient cancellation must NOT
|
first arg), raised under ambient cancellation must NOT
|
||||||
be demoted to a `trio.Cancelled` by the exact-msg-match
|
be demoted to a `trio.Cancelled` by the exact-msg-match
|
||||||
guard inside `start_or_cancel()`; the real error must
|
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(
|
async def cancels_cs_then_raises(
|
||||||
task_status: TaskStatus[None] = (
|
task_status: TaskStatus[None] = (
|
||||||
trio.TASK_STATUS_IGNORED
|
trio.TASK_STATUS_IGNORED
|
||||||
|
|
@ -255,7 +258,7 @@ def test_childs_own_rte_never_demoted_to_cancel(
|
||||||
# deterministically dies with ITS error while the
|
# deterministically dies with ITS error while the
|
||||||
# caller is under effective cancellation.
|
# caller is under effective cancellation.
|
||||||
cs.cancel()
|
cs.cancel()
|
||||||
raise RuntimeError(rte_arg)
|
raise child_rte
|
||||||
|
|
||||||
cs = trio.CancelScope()
|
cs = trio.CancelScope()
|
||||||
|
|
||||||
|
|
@ -270,9 +273,7 @@ def test_childs_own_rte_never_demoted_to_cancel(
|
||||||
with pytest.raises(ExceptionGroup) as excinfo:
|
with pytest.raises(ExceptionGroup) as excinfo:
|
||||||
trio.run(main)
|
trio.run(main)
|
||||||
|
|
||||||
rte = excinfo.value.exceptions[0]
|
assert excinfo.value.exceptions == (child_rte,)
|
||||||
assert isinstance(rte, RuntimeError)
|
|
||||||
assert rte.args[0] == rte_arg
|
|
||||||
|
|
||||||
|
|
||||||
def test_started_value_and_args_passthru():
|
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
|
# demote it to a `Cancelled`, losing the real error. The
|
||||||
# `isinstance` guard also avoids a `TypeError` when
|
# `isinstance` guard also avoids a `TypeError` when
|
||||||
# `rte.args[0]` isn't a `str`.
|
# `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
|
# re-raises the in-flight `trio.Cancelled` IFF we're
|
||||||
# under effective cancellation; else a cheap no-op and
|
# under effective cancellation; else a cheap no-op and
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue