Kick off `.devx` subpkg for our dev tools B)
Where `.devx` is "developer experience", a hopefully broad enough subpkg
name for all the slick stuff planned to augment working on the actor
runtime 💥
Move the `._debug` module into the new subpkg and adjust rest of core
code base to reflect import path change. Also add a new
`.devx._debug.open_crash_handler()` manager for wrapping any sync code
outside a `trio.run()` which is handy for eventual CLI addons for
popular frameworks like `click`/`typer`.
multihomed
parent
3d0e95513c
commit
fa9a9cfb1d
|
@ -45,7 +45,7 @@ from ._exceptions import (
|
|||
ModuleNotExposed,
|
||||
ContextCancelled,
|
||||
)
|
||||
from ._debug import (
|
||||
from .devx import (
|
||||
breakpoint,
|
||||
pause,
|
||||
pause_from_sync,
|
||||
|
|
|
@ -222,7 +222,7 @@ class Context:
|
|||
)
|
||||
|
||||
if self._cancel_called:
|
||||
# from ._debug import breakpoint
|
||||
# from .devx._debug import breakpoint
|
||||
# await breakpoint()
|
||||
|
||||
# this is an expected cancel request response message
|
||||
|
@ -247,7 +247,7 @@ class Context:
|
|||
self._scope.cancel()
|
||||
|
||||
# NOTE: this usage actually works here B)
|
||||
# from ._debug import breakpoint
|
||||
# from .devx._debug import breakpoint
|
||||
# await breakpoint()
|
||||
|
||||
# XXX: this will break early callee results sending
|
||||
|
@ -277,7 +277,7 @@ class Context:
|
|||
log.cancel(f'Cancelling {side} side of context to {self.chan.uid}')
|
||||
|
||||
self._cancel_called = True
|
||||
# await _debug.breakpoint()
|
||||
# await devx._debug.breakpoint()
|
||||
# breakpoint()
|
||||
|
||||
if side == 'caller':
|
||||
|
|
|
@ -482,7 +482,7 @@ class Portal:
|
|||
# were initiated by *this* side's task.
|
||||
if not ctx._cancel_called:
|
||||
# XXX: this should NEVER happen!
|
||||
# from ._debug import breakpoint
|
||||
# from .devx._debug import breakpoint
|
||||
# await breakpoint()
|
||||
raise
|
||||
|
||||
|
@ -564,7 +564,7 @@ class Portal:
|
|||
# a "stop" msg for a stream), this can result in a deadlock
|
||||
# where the root is waiting on the lock to clear but the
|
||||
# child has already cleared it and clobbered IPC.
|
||||
from ._debug import maybe_wait_for_debugger
|
||||
from .devx._debug import maybe_wait_for_debugger
|
||||
await maybe_wait_for_debugger()
|
||||
|
||||
# remove the context from runtime tracking
|
||||
|
|
|
@ -37,7 +37,7 @@ from ._runtime import (
|
|||
Arbiter,
|
||||
async_main,
|
||||
)
|
||||
from . import _debug
|
||||
from .devx import _debug
|
||||
from . import _spawn
|
||||
from . import _state
|
||||
from . import log
|
||||
|
@ -89,7 +89,7 @@ async def open_root_actor(
|
|||
# https://github.com/python-trio/trio/issues/1155#issuecomment-742964018
|
||||
builtin_bp_handler = sys.breakpointhook
|
||||
orig_bp_path: str | None = os.environ.get('PYTHONBREAKPOINT', None)
|
||||
os.environ['PYTHONBREAKPOINT'] = 'tractor._debug.pause_from_sync'
|
||||
os.environ['PYTHONBREAKPOINT'] = 'tractor.devx._debug.pause_from_sync'
|
||||
|
||||
# attempt to retreive ``trio``'s sigint handler and stash it
|
||||
# on our debugger lock state.
|
||||
|
@ -137,7 +137,7 @@ async def open_root_actor(
|
|||
|
||||
# expose internal debug module to every actor allowing
|
||||
# for use of ``await tractor.breakpoint()``
|
||||
enable_modules.append('tractor._debug')
|
||||
enable_modules.append('tractor.devx._debug')
|
||||
|
||||
# if debug mode get's enabled *at least* use that level of
|
||||
# logging for some informative console prompts.
|
||||
|
|
|
@ -58,7 +58,7 @@ from ._exceptions import (
|
|||
ContextCancelled,
|
||||
TransportClosed,
|
||||
)
|
||||
from . import _debug
|
||||
from .devx import _debug
|
||||
from ._discovery import get_registry
|
||||
from ._portal import Portal
|
||||
from . import _state
|
||||
|
@ -264,7 +264,6 @@ async def _invoke(
|
|||
cs: trio.CancelScope = ctx._scope
|
||||
if cs.cancel_called:
|
||||
canceller = ctx._cancelled_remote
|
||||
# await _debug.breakpoint()
|
||||
|
||||
# NOTE / TODO: if we end up having
|
||||
# ``Actor._cancel_task()`` call
|
||||
|
@ -536,7 +535,7 @@ class Actor:
|
|||
self._parent_main_data = _mp_fixup_main._mp_figure_out_main()
|
||||
|
||||
# always include debugging tools module
|
||||
enable_modules.append('tractor._debug')
|
||||
enable_modules.append('tractor.devx._debug')
|
||||
|
||||
self.enable_modules: dict[str, str] = {}
|
||||
for name in enable_modules:
|
||||
|
|
|
@ -35,7 +35,7 @@ from exceptiongroup import BaseExceptionGroup
|
|||
import trio
|
||||
from trio_typing import TaskStatus
|
||||
|
||||
from ._debug import (
|
||||
from .devx._debug import (
|
||||
maybe_wait_for_debugger,
|
||||
acquire_debug_lock,
|
||||
)
|
||||
|
|
|
@ -28,7 +28,7 @@ import warnings
|
|||
from exceptiongroup import BaseExceptionGroup
|
||||
import trio
|
||||
|
||||
from ._debug import maybe_wait_for_debugger
|
||||
from .devx._debug import maybe_wait_for_debugger
|
||||
from ._state import current_actor, is_main_process
|
||||
from .log import get_logger, get_loglevel
|
||||
from ._runtime import Actor
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
# tractor: structured concurrent "actors".
|
||||
# Copyright 2018-eternity Tyler Goodlet.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Runtime "developer experience" utils and addons to aid our
|
||||
(advanced) users and core devs in building distributed applications
|
||||
and working with/on the actor runtime.
|
||||
|
||||
"""
|
||||
from ._debug import (
|
||||
maybe_wait_for_debugger,
|
||||
acquire_debug_lock,
|
||||
breakpoint,
|
||||
pause,
|
||||
pause_from_sync,
|
||||
shield_sigint_handler,
|
||||
MultiActorPdb,
|
||||
open_crash_handler,
|
||||
post_mortem,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'maybe_wait_for_debugger',
|
||||
'acquire_debug_lock',
|
||||
'breakpoint',
|
||||
'pause',
|
||||
'pause_from_sync',
|
||||
'shield_sigint_handler',
|
||||
'MultiActorPdb',
|
||||
'open_crash_handler',
|
||||
'post_mortem',
|
||||
]
|
|
@ -28,6 +28,7 @@ from functools import (
|
|||
cached_property,
|
||||
)
|
||||
from contextlib import asynccontextmanager as acm
|
||||
from contextlib import contextmanager as cm
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
|
@ -44,22 +45,25 @@ from trio_typing import (
|
|||
# Task,
|
||||
)
|
||||
|
||||
from .log import get_logger
|
||||
from ._discovery import get_root
|
||||
from ._state import (
|
||||
from ..log import get_logger
|
||||
from .._discovery import get_root
|
||||
from .._state import (
|
||||
is_root_process,
|
||||
debug_mode,
|
||||
)
|
||||
from ._exceptions import (
|
||||
from .._exceptions import (
|
||||
is_multi_cancelled,
|
||||
ContextCancelled,
|
||||
)
|
||||
from ._ipc import Channel
|
||||
from .._ipc import Channel
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
|
||||
__all__ = ['breakpoint', 'post_mortem']
|
||||
__all__ = [
|
||||
'breakpoint',
|
||||
'post_mortem',
|
||||
]
|
||||
|
||||
|
||||
class Lock:
|
||||
|
@ -390,7 +394,7 @@ async def wait_for_parent_stdin_hijack(
|
|||
# this syncs to child's ``Context.started()`` call.
|
||||
async with portal.open_context(
|
||||
|
||||
tractor._debug.lock_tty_for_child,
|
||||
lock_tty_for_child,
|
||||
subactor_uid=actor_uid,
|
||||
|
||||
) as (ctx, val):
|
||||
|
@ -855,7 +859,7 @@ pause = partial(
|
|||
_pause,
|
||||
_set_trace,
|
||||
)
|
||||
pp = pause # short-hand for "pause point"
|
||||
# pp = pause # short-hand for "pause point"
|
||||
|
||||
|
||||
async def breakpoint(**kwargs):
|
||||
|
@ -1008,3 +1012,32 @@ async def maybe_wait_for_debugger(
|
|||
log.debug(
|
||||
'Root acquired TTY LOCK'
|
||||
)
|
||||
|
||||
|
||||
# TODO: better naming and what additionals?
|
||||
# - optional runtime plugging?
|
||||
# - detection for sync vs. async code?
|
||||
# - specialized REPL entry when in distributed mode?
|
||||
@cm
|
||||
def open_crash_handler(
|
||||
catch: set[BaseException] = {
|
||||
Exception,
|
||||
BaseException,
|
||||
}
|
||||
):
|
||||
'''
|
||||
Generic "post mortem" crash handler using `pdbp` REPL debugger.
|
||||
|
||||
We expose this as a CLI framework addon to both `click` and
|
||||
`typer` users so they can quickly wrap cmd endpoints which get
|
||||
automatically wrapped to use the runtime's `debug_mode: bool`
|
||||
AND `pdbp.pm()` around any code that is PRE-runtime entry
|
||||
- any sync code which runs BEFORE the main call to
|
||||
`trio.run()`.
|
||||
|
||||
'''
|
||||
try:
|
||||
yield
|
||||
except tuple(catch):
|
||||
pdbp.xpm()
|
||||
raise
|
Loading…
Reference in New Issue