Polish the debugger examples
Finish the Python style, typing and docstring pass across the debugger examples without changing their intentional breakpoints, failures, cancellation races or timeout reproducers. Restore full child command lines in the documented process trees and keep the examples within the 69-column source limit. (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/big_boi_docs_472_follow_ups
parent
96a1838210
commit
97aff52050
|
|
@ -13,7 +13,11 @@ import tractor
|
||||||
@tractor.context
|
@tractor.context
|
||||||
async def sleep(
|
async def sleep(
|
||||||
ctx: tractor.Context,
|
ctx: tractor.Context,
|
||||||
):
|
) -> None:
|
||||||
|
'''
|
||||||
|
Start a context after a brief initialization delay.
|
||||||
|
|
||||||
|
'''
|
||||||
await trio.sleep(0.5)
|
await trio.sleep(0.5)
|
||||||
await ctx.started()
|
await ctx.started()
|
||||||
await trio.sleep_forever()
|
await trio.sleep_forever()
|
||||||
|
|
@ -21,10 +25,13 @@ async def sleep(
|
||||||
|
|
||||||
async def open_ctx(
|
async def open_ctx(
|
||||||
n: tractor.runtime._supervise.ActorNursery
|
n: tractor.runtime._supervise.ActorNursery
|
||||||
):
|
) -> None:
|
||||||
|
'''
|
||||||
|
Spawn a sleeper and open a context with it.
|
||||||
|
|
||||||
|
'''
|
||||||
# spawn both actors
|
# spawn both actors
|
||||||
portal = await n.start_actor(
|
portal: tractor.Portal = await n.start_actor(
|
||||||
name='sleeper',
|
name='sleeper',
|
||||||
enable_modules=[__name__],
|
enable_modules=[__name__],
|
||||||
)
|
)
|
||||||
|
|
@ -36,7 +43,10 @@ async def open_ctx(
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Fail the root while a subactor context is still starting.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
loglevel='runtime',
|
loglevel='runtime',
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
|
from collections.abc import AsyncIterator
|
||||||
|
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
|
|
||||||
async def breakpoint_forever():
|
async def breakpoint_forever() -> AsyncIterator[str]:
|
||||||
"Indefinitely re-enter debugger in child actor."
|
'''
|
||||||
|
Indefinitely re-enter debugger in child actor.
|
||||||
|
|
||||||
|
'''
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
yield 'yo'
|
yield 'yo'
|
||||||
|
|
@ -15,8 +20,11 @@ async def breakpoint_forever():
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
async def name_error():
|
async def name_error() -> None:
|
||||||
"Raise a ``NameError``"
|
'''
|
||||||
|
Raise a ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
getattr(doggypants) # noqa
|
getattr(doggypants) # noqa
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -28,8 +36,14 @@ async def main() -> None:
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
) as an:
|
) as an:
|
||||||
p0 = await an.start_actor('bp_forever', enable_modules=[__name__])
|
p0: tractor.Portal = await an.start_actor(
|
||||||
p1 = await an.start_actor('name_error', enable_modules=[__name__])
|
'bp_forever',
|
||||||
|
enable_modules=[__name__],
|
||||||
|
)
|
||||||
|
p1: tractor.Portal = await an.start_actor(
|
||||||
|
'name_error',
|
||||||
|
enable_modules=[__name__],
|
||||||
|
)
|
||||||
|
|
||||||
# retreive results
|
# retreive results
|
||||||
async with p0.open_stream_from(breakpoint_forever) as stream:
|
async with p0.open_stream_from(breakpoint_forever) as stream:
|
||||||
|
|
@ -40,6 +54,7 @@ async def main() -> None:
|
||||||
except tractor.RemoteActorError as rae:
|
except tractor.RemoteActorError as rae:
|
||||||
assert rae.boxed_type is NameError
|
assert rae.boxed_type is NameError
|
||||||
|
|
||||||
|
i: str
|
||||||
async for i in stream:
|
async for i in stream:
|
||||||
|
|
||||||
# a second time try the failing subactor and this tie
|
# a second time try the failing subactor and this tie
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,19 @@ import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
|
|
||||||
async def name_error():
|
async def name_error() -> None:
|
||||||
"Raise a ``NameError``"
|
'''
|
||||||
|
Raise a ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
getattr(doggypants) # noqa
|
getattr(doggypants) # noqa
|
||||||
|
|
||||||
|
|
||||||
async def breakpoint_forever():
|
async def breakpoint_forever() -> None:
|
||||||
"Indefinitely re-enter debugger in child actor."
|
'''
|
||||||
|
Indefinitely re-enter debugger in child actor.
|
||||||
|
|
||||||
|
'''
|
||||||
while True:
|
while True:
|
||||||
await tractor.pause()
|
await tractor.pause()
|
||||||
|
|
||||||
|
|
@ -20,9 +26,13 @@ async def breakpoint_forever():
|
||||||
# await trio.sleep(0)
|
# await trio.sleep(0)
|
||||||
|
|
||||||
|
|
||||||
async def spawn_until(depth=0):
|
async def spawn_until(
|
||||||
""""A nested nursery that triggers another ``NameError``.
|
depth: int = 0,
|
||||||
"""
|
) -> None:
|
||||||
|
'''
|
||||||
|
A nested nursery that triggers another ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
async with (
|
async with (
|
||||||
tractor.open_nursery() as an,
|
tractor.open_nursery() as an,
|
||||||
trio.open_nursery() as tn,
|
trio.open_nursery() as tn,
|
||||||
|
|
@ -37,7 +47,8 @@ async def spawn_until(depth=0):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Let the background one-shot enter `breakpoint_forever()`
|
# Let the background one-shot enter
|
||||||
|
# `breakpoint_forever()`
|
||||||
# before its sibling raises and cancellation propagates.
|
# before its sibling raises and cancellation propagates.
|
||||||
await trio.sleep(0.5)
|
await trio.sleep(0.5)
|
||||||
# rx and propagate error from child
|
# rx and propagate error from child
|
||||||
|
|
@ -48,9 +59,9 @@ async def spawn_until(depth=0):
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# recusrive call to spawn another process branching layer of
|
# recusrive call to spawn another process branching
|
||||||
# the tree; blocks (up) each level until the leaf's
|
# layer of the tree; blocks (up) each level until the
|
||||||
# `name_error` relays through.
|
# leaf's `name_error` relays through.
|
||||||
depth -= 1
|
depth -= 1
|
||||||
await tractor.to_actor.run(
|
await tractor.to_actor.run(
|
||||||
partial(
|
partial(
|
||||||
|
|
@ -64,24 +75,34 @@ async def spawn_until(depth=0):
|
||||||
|
|
||||||
# TODO: notes on the new boxed-relayed errors through proxy actors
|
# TODO: notes on the new boxed-relayed errors through proxy actors
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
"""The main ``tractor`` routine.
|
'''
|
||||||
|
The main ``tractor`` routine.
|
||||||
|
|
||||||
The process tree should look as approximately as follows when the debugger
|
The process tree should look approximately as follows when the
|
||||||
first engages:
|
debugger first engages:
|
||||||
|
|
||||||
python examples/debugging/multi_nested_subactors_bp_forever.py
|
python examples/debugging/multi_nested_subactors_bp_forever.py
|
||||||
├─ python -m tractor._child --uid ('spawner1', '7eab8462 ...)
|
├─ python -m tractor._child --uid
|
||||||
│ └─ python -m tractor._child --uid ('spawn_until_3', 'afcba7a8 ...)
|
│ ('spawner1', '7eab8462 ...')
|
||||||
│ └─ python -m tractor._child --uid ('spawn_until_2', 'd2433d13 ...)
|
│ └─ python -m tractor._child --uid
|
||||||
│ └─ python -m tractor._child --uid ('spawn_until_1', '1df589de ...)
|
│ ('spawn_until_3', 'afcba7a8 ...')
|
||||||
│ └─ python -m tractor._child --uid ('spawn_until_0', '3720602b ...)
|
│ └─ python -m tractor._child --uid
|
||||||
|
│ ('spawn_until_2', 'd2433d13 ...')
|
||||||
|
│ └─ python -m tractor._child --uid
|
||||||
|
│ ('spawn_until_1', '1df589de ...')
|
||||||
|
│ └─ python -m tractor._child --uid
|
||||||
|
│ ('spawn_until_0', '3720602b ...')
|
||||||
│
|
│
|
||||||
└─ python -m tractor._child --uid ('spawner0', '1d42012b ...)
|
└─ python -m tractor._child --uid
|
||||||
└─ python -m tractor._child --uid ('spawn_until_2', '2877e155 ...)
|
('spawner0', '1d42012b ...')
|
||||||
└─ python -m tractor._child --uid ('spawn_until_1', '0502d786 ...)
|
└─ python -m tractor._child --uid
|
||||||
└─ python -m tractor._child --uid ('spawn_until_0', 'de918e6d ...)
|
('spawn_until_2', '2877e155 ...')
|
||||||
|
└─ python -m tractor._child --uid
|
||||||
|
('spawn_until_1', '0502d786 ...')
|
||||||
|
└─ python -m tractor._child --uid
|
||||||
|
('spawn_until_0', 'de918e6d ...')
|
||||||
|
|
||||||
"""
|
'''
|
||||||
async with (
|
async with (
|
||||||
tractor.open_nursery(
|
tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,19 @@ import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
|
|
||||||
async def name_error():
|
async def name_error() -> None:
|
||||||
"Raise a ``NameError``"
|
'''
|
||||||
|
Raise a ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
getattr(doggypants) # noqa
|
getattr(doggypants) # noqa
|
||||||
|
|
||||||
|
|
||||||
async def spawn_error():
|
async def spawn_error() -> None:
|
||||||
""""A nested nursery that triggers another ``NameError``.
|
'''
|
||||||
"""
|
A nested nursery that triggers another ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery() as an:
|
async with tractor.open_nursery() as an:
|
||||||
return await tractor.to_actor.run(
|
return await tractor.to_actor.run(
|
||||||
name_error,
|
name_error,
|
||||||
|
|
@ -24,7 +29,8 @@ async def spawn_error():
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
"""The main ``tractor`` routine.
|
'''
|
||||||
|
The main ``tractor`` routine.
|
||||||
|
|
||||||
The process tree should look as approximately as follows:
|
The process tree should look as approximately as follows:
|
||||||
|
|
||||||
|
|
@ -37,7 +43,8 @@ async def main() -> None:
|
||||||
- nested name_error sub-sub-actor
|
- nested name_error sub-sub-actor
|
||||||
- root actor should then fail on assert
|
- root actor should then fail on assert
|
||||||
- program termination
|
- program termination
|
||||||
"""
|
|
||||||
|
'''
|
||||||
async with (
|
async with (
|
||||||
tractor.open_nursery(
|
tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
|
|
@ -46,11 +53,11 @@ async def main() -> None:
|
||||||
trio.open_nursery() as tn,
|
trio.open_nursery() as tn,
|
||||||
):
|
):
|
||||||
# spawn both actors..
|
# spawn both actors..
|
||||||
portal = await an.start_actor(
|
portal: tractor.Portal = await an.start_actor(
|
||||||
'name_error',
|
'name_error',
|
||||||
enable_modules=[__name__],
|
enable_modules=[__name__],
|
||||||
)
|
)
|
||||||
portal1 = await an.start_actor(
|
portal1: tractor.Portal = await an.start_actor(
|
||||||
'spawn_error',
|
'spawn_error',
|
||||||
enable_modules=[__name__],
|
enable_modules=[__name__],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,32 @@
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
|
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
|
|
||||||
async def breakpoint_forever():
|
async def breakpoint_forever() -> None:
|
||||||
"Indefinitely re-enter debugger in child actor."
|
'''
|
||||||
|
Indefinitely re-enter debugger in child actor.
|
||||||
|
|
||||||
|
'''
|
||||||
while True:
|
while True:
|
||||||
await trio.sleep(0.1)
|
await trio.sleep(0.1)
|
||||||
await tractor.pause()
|
await tractor.pause()
|
||||||
|
|
||||||
|
|
||||||
async def name_error():
|
async def name_error() -> None:
|
||||||
"Raise a ``NameError``"
|
'''
|
||||||
|
Raise a ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
getattr(doggypants) # noqa
|
getattr(doggypants) # noqa
|
||||||
|
|
||||||
|
|
||||||
async def spawn_error():
|
async def spawn_error() -> None:
|
||||||
""""A nested nursery that triggers another ``NameError``.
|
'''
|
||||||
"""
|
A nested nursery that triggers another ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery() as an:
|
async with tractor.open_nursery() as an:
|
||||||
return await tractor.to_actor.run(
|
return await tractor.to_actor.run(
|
||||||
name_error,
|
name_error,
|
||||||
|
|
@ -26,7 +36,8 @@ async def spawn_error():
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
"""The main ``tractor`` routine.
|
'''
|
||||||
|
The main ``tractor`` routine.
|
||||||
|
|
||||||
The process tree should look as approximately as follows:
|
The process tree should look as approximately as follows:
|
||||||
|
|
||||||
|
|
@ -35,7 +46,8 @@ async def main() -> None:
|
||||||
|-python -m tractor._child --uid ('bp_forever', '1f787a7e ...)
|
|-python -m tractor._child --uid ('bp_forever', '1f787a7e ...)
|
||||||
`-python -m tractor._child --uid ('spawn_error', '52ee14a5 ...)
|
`-python -m tractor._child --uid ('spawn_error', '52ee14a5 ...)
|
||||||
`-python -m tractor._child --uid ('name_error', '3391222c ...)
|
`-python -m tractor._child --uid ('name_error', '3391222c ...)
|
||||||
"""
|
|
||||||
|
'''
|
||||||
errors: list[BaseException] = []
|
errors: list[BaseException] = []
|
||||||
|
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
|
|
@ -43,12 +55,14 @@ async def main() -> None:
|
||||||
# loglevel='runtime',
|
# loglevel='runtime',
|
||||||
) as an:
|
) as an:
|
||||||
|
|
||||||
async def run_and_collect(fn):
|
async def run_and_collect(
|
||||||
|
fn: Callable[[], Awaitable[object]],
|
||||||
|
) -> None:
|
||||||
'''
|
'''
|
||||||
One-shot whose (boxed) error is stashed instead of
|
One-shot whose (boxed) error is stashed instead of
|
||||||
raised so a sibling's crash never cancels the others
|
raised so a sibling's crash never cancels the others
|
||||||
before they've had their own debugger sessions (the
|
before they've had their own debugger sessions (the
|
||||||
"collect all errors" the legacy `run_in_actor()` API
|
'collect all errors' the legacy `run_in_actor()` API
|
||||||
did implicitly at nursery teardown).
|
did implicitly at nursery teardown).
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,28 @@
|
||||||
import trio
|
import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
async def die():
|
|
||||||
|
async def die() -> None:
|
||||||
|
'''
|
||||||
|
Deliberately crash the calling actor.
|
||||||
|
|
||||||
|
'''
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Crash actors with different debugger settings concurrently.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery() as an:
|
async with tractor.open_nursery() as an:
|
||||||
|
|
||||||
debug_actor = await an.start_actor(
|
debug_actor: tractor.Portal = await an.start_actor(
|
||||||
'debugged_boi',
|
'debugged_boi',
|
||||||
enable_modules=[__name__],
|
enable_modules=[__name__],
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
)
|
)
|
||||||
crash_boi = await an.start_actor(
|
crash_boi: tractor.Portal = await an.start_actor(
|
||||||
'crash_boi',
|
'crash_boi',
|
||||||
enable_modules=[__name__],
|
enable_modules=[__name__],
|
||||||
# debug_mode=True,
|
# debug_mode=True,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import tractor
|
||||||
@tractor.context
|
@tractor.context
|
||||||
async def name_error(
|
async def name_error(
|
||||||
ctx: tractor.Context,
|
ctx: tractor.Context,
|
||||||
):
|
) -> None:
|
||||||
'''
|
'''
|
||||||
Raise a `NameError`, catch it and enter `.post_mortem()`, then
|
Raise a `NameError`, catch it and enter `.post_mortem()`, then
|
||||||
expect the `._rpc._invoke()` crash handler to also engage.
|
expect the `._rpc._invoke()` crash handler to also engage.
|
||||||
|
|
@ -49,7 +49,9 @@ async def main() -> None:
|
||||||
await tractor.post_mortem()
|
await tractor.post_mortem()
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('IPC ctx should have remote errored!?')
|
raise RuntimeError(
|
||||||
|
'IPC ctx should have remote errored!?'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ import tractor
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Pause in the root actor to exercise its debugger REPL.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_root_actor(
|
async with tractor.open_root_actor(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ import tractor
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Raise an assertion error from the debug-enabled root actor.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_root_actor(
|
async with tractor.open_root_actor(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,21 @@ import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
|
|
||||||
async def name_error():
|
async def name_error() -> None:
|
||||||
"Raise a ``NameError``"
|
'''
|
||||||
|
Raise a ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
getattr(doggypants) # noqa
|
getattr(doggypants) # noqa
|
||||||
|
|
||||||
|
|
||||||
async def spawn_until(depth=0):
|
async def spawn_until(
|
||||||
""""A nested nursery that triggers another ``NameError``.
|
depth: int = 0,
|
||||||
"""
|
) -> None:
|
||||||
|
'''
|
||||||
|
A nested nursery that triggers another ``NameError``.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery() as an:
|
async with tractor.open_nursery() as an:
|
||||||
if depth < 1:
|
if depth < 1:
|
||||||
await tractor.to_actor.run(name_error, an=an)
|
await tractor.to_actor.run(name_error, an=an)
|
||||||
|
|
@ -33,12 +40,17 @@ async def main() -> None:
|
||||||
debugger first engages:
|
debugger first engages:
|
||||||
|
|
||||||
python examples/debugging/multi_nested_subactors_bp_forever.py
|
python examples/debugging/multi_nested_subactors_bp_forever.py
|
||||||
├─ python -m tractor._child --uid ('spawner1', '7eab8462 ...)
|
├─ python -m tractor._child --uid
|
||||||
│ └─ python -m tractor._child --uid ('spawn_until_0', '3720602b ...)
|
│ ('spawner1', '7eab8462 ...')
|
||||||
│ └─ python -m tractor._child --uid ('name_error', '505bf71d ...)
|
│ └─ python -m tractor._child --uid
|
||||||
|
│ ('spawn_until_0', '3720602b ...')
|
||||||
|
│ └─ python -m tractor._child --uid
|
||||||
|
│ ('name_error', '505bf71d ...')
|
||||||
│
|
│
|
||||||
└─ python -m tractor._child --uid ('spawner0', '1d42012b ...)
|
└─ python -m tractor._child --uid
|
||||||
└─ python -m tractor._child --uid ('name_error', '6c2733b8 ...)
|
('spawner0', '1d42012b ...')
|
||||||
|
└─ python -m tractor._child --uid
|
||||||
|
('name_error', '6c2733b8 ...')
|
||||||
|
|
||||||
'''
|
'''
|
||||||
async with (
|
async with (
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ import tractor
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Enter shielded debugging after root cancellation, then fail.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_root_actor(
|
async with tractor.open_root_actor(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
loglevel='cancel',
|
loglevel='cancel',
|
||||||
|
|
@ -18,16 +22,19 @@ async def main() -> None:
|
||||||
try:
|
try:
|
||||||
await tractor.pause()
|
await tractor.pause()
|
||||||
except trio.Cancelled as _taskc:
|
except trio.Cancelled as _taskc:
|
||||||
assert (root_cs := _root._root_tn.cancel_scope).cancel_called
|
root_cs: trio.CancelScope
|
||||||
|
assert (
|
||||||
|
root_cs := _root._root_tn.cancel_scope
|
||||||
|
).cancel_called
|
||||||
# NOTE^^ above logic but inside `open_root_actor()` and
|
# NOTE^^ above logic but inside `open_root_actor()` and
|
||||||
# passed to the `shield=` expression is effectively what
|
# passed to the `shield=` expression is effectively what
|
||||||
# we're testing here!
|
# we're testing here!
|
||||||
await tractor.pause(shield=root_cs.cancel_called)
|
await tractor.pause(shield=root_cs.cancel_called)
|
||||||
|
|
||||||
# XXX, if shield logic *is wrong* inside `open_root_actor()`'s
|
# XXX, if shield logic *is wrong* inside
|
||||||
# crash-handler block this should never be interacted,
|
# `open_root_actor()`'s crash-handler block this should never
|
||||||
# instead `trio.Cancelled` would be bubbled up: the original
|
# be interacted, instead `trio.Cancelled` would be bubbled
|
||||||
# BUG.
|
# up: the original BUG.
|
||||||
assert 0
|
assert 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
|
|
||||||
async def key_error():
|
async def key_error() -> None:
|
||||||
"Raise a ``NameError``"
|
'''
|
||||||
|
Raise a ``KeyError``.
|
||||||
|
|
||||||
|
'''
|
||||||
return {}['doggy']
|
return {}['doggy']
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -21,7 +24,7 @@ async def main() -> None:
|
||||||
trio.open_nursery() as tn,
|
trio.open_nursery() as tn,
|
||||||
):
|
):
|
||||||
# spawn the actor..
|
# spawn the actor..
|
||||||
portal = await an.start_actor(
|
portal: tractor.Portal = await an.start_actor(
|
||||||
'key_error',
|
'key_error',
|
||||||
enable_modules=[__name__],
|
enable_modules=[__name__],
|
||||||
)
|
)
|
||||||
|
|
@ -32,9 +35,9 @@ async def main() -> None:
|
||||||
# root blocks below.
|
# root blocks below.
|
||||||
tn.start_soon(portal.run, key_error)
|
tn.start_soon(portal.run, key_error)
|
||||||
|
|
||||||
# XXX: originally a bug caused by this is where root would enter
|
# XXX: originally a bug caused by this is where root would
|
||||||
# the debugger and clobber the tty used by the repl even though
|
# enter the debugger and clobber the tty used by the repl
|
||||||
# child should have it locked.
|
# even though child should have it locked.
|
||||||
with trio.fail_after(1):
|
with trio.fail_after(1):
|
||||||
await trio.Event().wait()
|
await trio.Event().wait()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,15 @@ import tractor
|
||||||
|
|
||||||
|
|
||||||
async def cancellable_pause_loop(
|
async def cancellable_pause_loop(
|
||||||
task_status: trio.TaskStatus[trio.CancelScope] = trio.TASK_STATUS_IGNORED
|
task_status: trio.TaskStatus[
|
||||||
):
|
trio.CancelScope
|
||||||
|
] = trio.TASK_STATUS_IGNORED,
|
||||||
|
) -> None:
|
||||||
|
'''
|
||||||
|
Exercise shielded debugger pauses under cancellation.
|
||||||
|
|
||||||
|
'''
|
||||||
|
cs: trio.CancelScope
|
||||||
with trio.CancelScope() as cs:
|
with trio.CancelScope() as cs:
|
||||||
task_status.started(cs)
|
task_status.started(cs)
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
|
|
@ -30,7 +37,11 @@ async def cancellable_pause_loop(
|
||||||
await trio.lowlevel.checkpoint()
|
await trio.lowlevel.checkpoint()
|
||||||
|
|
||||||
|
|
||||||
async def pm_on_cancelled():
|
async def pm_on_cancelled() -> None:
|
||||||
|
'''
|
||||||
|
Compare shielded and unshielded post-mortem entry.
|
||||||
|
|
||||||
|
'''
|
||||||
async with trio.open_nursery() as tn:
|
async with trio.open_nursery() as tn:
|
||||||
tn.cancel_scope.cancel()
|
tn.cancel_scope.cancel()
|
||||||
try:
|
try:
|
||||||
|
|
@ -56,7 +67,7 @@ async def pm_on_cancelled():
|
||||||
|
|
||||||
|
|
||||||
async def cancelled_before_pause(
|
async def cancelled_before_pause(
|
||||||
):
|
) -> None:
|
||||||
'''
|
'''
|
||||||
Verify that using a shielded pause works despite surrounding
|
Verify that using a shielded pause works despite surrounding
|
||||||
cancellation called state in the calling task.
|
cancellation called state in the calling task.
|
||||||
|
|
@ -72,6 +83,10 @@ async def cancelled_before_pause(
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Exercise shielded debugger entry in subactor and root tasks.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
) as an:
|
) as an:
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
import platform
|
import platform
|
||||||
|
from collections.abc import AsyncIterator
|
||||||
|
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
|
|
||||||
async def gen():
|
async def gen() -> AsyncIterator[str]:
|
||||||
|
'''
|
||||||
|
Yield values around debugger pauses.
|
||||||
|
|
||||||
|
'''
|
||||||
yield 'yo'
|
yield 'yo'
|
||||||
await tractor.pause()
|
await tractor.pause()
|
||||||
yield 'yo'
|
yield 'yo'
|
||||||
|
|
@ -15,11 +20,15 @@ async def gen():
|
||||||
async def just_bp(
|
async def just_bp(
|
||||||
ctx: tractor.Context,
|
ctx: tractor.Context,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
'''
|
||||||
|
Pause repeatedly before deliberately breaking the context.
|
||||||
|
|
||||||
|
'''
|
||||||
await ctx.started()
|
await ctx.started()
|
||||||
await tractor.pause()
|
await tractor.pause()
|
||||||
|
|
||||||
# TODO: bps and errors in this call..
|
# TODO: bps and errors in this call..
|
||||||
|
val: str
|
||||||
async for val in gen():
|
async for val in gen():
|
||||||
print(val)
|
print(val)
|
||||||
|
|
||||||
|
|
@ -35,14 +44,17 @@ async def just_bp(
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Run the breakpoint context over a supported transport.
|
||||||
|
|
||||||
|
'''
|
||||||
# !TODO, parametrize the --tpt-proto={key} with osenv vars just
|
# !TODO, parametrize the --tpt-proto={key} with osenv vars just
|
||||||
# like we do for loglevel/spawn-backend!
|
# like we do for loglevel/spawn-backend!
|
||||||
# - [ ] run on both tpts for all such debugger tests?
|
# - [ ] run on both tpts for all such debugger tests?
|
||||||
# - [ ] special skip for macos!
|
# - [ ] special skip for macos!
|
||||||
#
|
#
|
||||||
if platform.system() != 'Darwin':
|
if platform.system() != 'Darwin':
|
||||||
tpt = 'uds'
|
tpt: str = 'uds'
|
||||||
else:
|
else:
|
||||||
# XXX, precisely we can't use pytest's tmp-path generation
|
# XXX, precisely we can't use pytest's tmp-path generation
|
||||||
# for tests.. apparently because:
|
# for tests.. apparently because:
|
||||||
|
|
@ -59,7 +71,7 @@ async def main() -> None:
|
||||||
enable_transports=[tpt],
|
enable_transports=[tpt],
|
||||||
loglevel='devx',
|
loglevel='devx',
|
||||||
) as an:
|
) as an:
|
||||||
p = await an.start_actor(
|
p: tractor.Portal = await an.start_actor(
|
||||||
'bp_boi',
|
'bp_boi',
|
||||||
enable_modules=[__name__],
|
enable_modules=[__name__],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
|
|
||||||
async def breakpoint_forever():
|
async def breakpoint_forever() -> None:
|
||||||
'''
|
'''
|
||||||
Indefinitely re-enter debugger in child actor.
|
Indefinitely re-enter debugger in child actor.
|
||||||
|
|
||||||
|
|
@ -13,7 +13,10 @@ async def breakpoint_forever():
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Run a subactor that repeatedly pauses in the debugger.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
loglevel='cancel',
|
loglevel='cancel',
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,19 @@ import trio
|
||||||
import tractor
|
import tractor
|
||||||
|
|
||||||
|
|
||||||
async def name_error():
|
async def name_error() -> None:
|
||||||
|
'''
|
||||||
|
Deliberately raise a ``NameError`` in a subactor.
|
||||||
|
|
||||||
|
'''
|
||||||
getattr(doggypants) # noqa (on purpose)
|
getattr(doggypants) # noqa (on purpose)
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Surface a subactor `NameError` at the waiting root task.
|
||||||
|
|
||||||
|
'''
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
) as an:
|
) as an:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue