From 9ada628a5757daf76125de7cbd093ee7be5bf334 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 18 Jul 2025 20:07:35 -0400 Subject: [PATCH] Rename all lingering ctx-side bits As before but more thoroughly in comments and var names finally changing all, - caller -> parent - callee -> child --- tractor/_context.py | 103 +++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/tractor/_context.py b/tractor/_context.py index 395a4b57..e97487a4 100644 --- a/tractor/_context.py +++ b/tractor/_context.py @@ -154,7 +154,7 @@ class Context: 2 cancel-scope-linked, communicating and parallel executing `Task`s. Contexts are allocated on each side of any task RPC-linked msg dialog, i.e. for every request to a remote - actor from a `Portal`. On the "callee" side a context is + actor from a `Portal`. On the "child" side a context is always allocated inside `._rpc._invoke()`. TODO: more detailed writeup on cancellation, error and @@ -222,8 +222,8 @@ class Context: # `._runtime.invoke()`. _remote_func_type: str | None = None - # NOTE: (for now) only set (a portal) on the caller side since - # the callee doesn't generally need a ref to one and should + # NOTE: (for now) only set (a portal) on the parent side since + # the child doesn't generally need a ref to one and should # normally need to explicitly ask for handle to its peer if # more the the `Context` is needed? _portal: Portal | None = None @@ -252,12 +252,12 @@ class Context: _outcome_msg: Return|Error|ContextCancelled = Unresolved # on a clean exit there should be a final value - # delivered from the far end "callee" task, so + # delivered from the far end "child" task, so # this value is only set on one side. # _result: Any | int = None _result: PayloadT|Unresolved = Unresolved - # if the local "caller" task errors this value is always set + # if the local "parent" task errors this value is always set # to the error that was captured in the # `Portal.open_context().__aexit__()` teardown block OR, in # 2 special cases when an (maybe) expected remote error @@ -293,7 +293,7 @@ class Context: # a `ContextCancelled` due to a call to `.cancel()` triggering # "graceful closure" on either side: # - `._runtime._invoke()` will check this flag before engaging - # the crash handler REPL in such cases where the "callee" + # the crash handler REPL in such cases where the "child" # raises the cancellation, # - `.devx.debug.lock_stdio_for_peer()` will set it to `False` if # the global tty-lock has been configured to filter out some @@ -307,8 +307,8 @@ class Context: _stream_opened: bool = False _stream: MsgStream|None = None - # caller of `Portal.open_context()` for - # logging purposes mostly + # the parent-task's calling-fn's frame-info, the frame above + # `Portal.open_context()`, for introspection/logging. _caller_info: CallerInfo|None = None # overrun handling machinery @@ -529,11 +529,11 @@ class Context: ''' Exactly the value of `self._scope.cancelled_caught` (delegation) and should only be (able to be read as) - `True` for a `.side == "caller"` ctx wherein the + `True` for a `.side == "parent"` ctx wherein the `Portal.open_context()` block was exited due to a call to `._scope.cancel()` - which should only ocurr in 2 cases: - - a caller side calls `.cancel()`, the far side cancels + - a parent side calls `.cancel()`, the far side cancels and delivers back a `ContextCancelled` (making `.cancel_acked == True`) and `._scope.cancel()` is called by `._maybe_cancel_and_set_remote_error()` which @@ -542,20 +542,20 @@ class Context: => `._scope.cancelled_caught == True` by normal `trio` cs semantics. - - a caller side is delivered a `._remote_error: + - a parent side is delivered a `._remote_error: RemoteActorError` via `._deliver_msg()` and a transitive call to `_maybe_cancel_and_set_remote_error()` calls `._scope.cancel()` and that cancellation eventually results in `trio.Cancelled`(s) caught in the `.open_context()` handling around the @acm's `yield`. - Only as an FYI, in the "callee" side case it can also be + Only as an FYI, in the "child" side case it can also be set but never is readable by any task outside the RPC machinery in `._invoke()` since,: - - when a callee side calls `.cancel()`, `._scope.cancel()` + - when a child side calls `.cancel()`, `._scope.cancel()` is called immediately and handled specially inside `._invoke()` to raise a `ContextCancelled` which is then - sent to the caller side. + sent to the parent side. However, `._scope.cancelled_caught` can NEVER be accessed/read as `True` by any RPC invoked task since it @@ -666,7 +666,7 @@ class Context: when called/closed by actor local task(s). NOTEs: - - It is expected that the caller has previously unwrapped + - It is expected that the parent has previously unwrapped the remote error using a call to `unpack_error()` and provides that output exception value as the input `error` argument *here*. @@ -676,7 +676,7 @@ class Context: `Portal.open_context()` (ideally) we want to interrupt any ongoing local tasks operating within that `Context`'s cancel-scope so as to be notified ASAP of - the remote error and engage any caller handling (eg. + the remote error and engage any parent handling (eg. for cross-process task supervision). - In some cases we may want to raise the remote error @@ -886,6 +886,11 @@ class Context: @property def repr_caller(self) -> str: + ''' + Render a "namespace-path" style representation of the calling + task-fn. + + ''' ci: CallerInfo|None = self._caller_info if ci: return ( @@ -899,7 +904,7 @@ class Context: def repr_api(self) -> str: return 'Portal.open_context()' - # TODO: use `.dev._frame_stack` scanning to find caller! + # TODO: use `.dev._frame_stack` scanning to find caller fn! # ci: CallerInfo|None = self._caller_info # if ci: # return ( @@ -934,7 +939,7 @@ class Context: => That is, an IPC `Context` (this) **does not** have the same semantics as a `trio.CancelScope`. - If the caller (who entered the `Portal.open_context()`) + If the parent (who entered the `Portal.open_context()`) desires that the internal block's cancel-scope be cancelled it should open its own `trio.CancelScope` and manage it as needed. @@ -1017,7 +1022,7 @@ class Context: # `_invoke()` RPC task. # # NOTE: on this side we ALWAYS cancel the local scope - # since the caller expects a `ContextCancelled` to be sent + # since the parent expects a `ContextCancelled` to be sent # from `._runtime._invoke()` back to the other side. The # logic for catching the result of the below # `._scope.cancel()` is inside the `._runtime._invoke()` @@ -1190,8 +1195,8 @@ class Context: ) -> Any|Exception: ''' - From some (caller) side task, wait for and return the final - result from the remote (callee) side's task. + From some (parent) side task, wait for and return the final + result from the remote (child) side's task. This provides a mechanism for one task running in some actor to wait on another task at the other side, in some other actor, to terminate. @@ -1600,7 +1605,7 @@ class Context: raise err # TODO: maybe a flag to by-pass encode op if already done - # here in caller? + # here in parent? await self.chan.send(started_msg) # set msg-related internal runtime-state @@ -1676,7 +1681,7 @@ class Context: XXX RULES XXX ------ - ------ - - NEVER raise remote errors from this method; a runtime task caller. + - NEVER raise remote errors from this method; a calling runtime-task. An error "delivered" to a ctx should always be raised by the corresponding local task operating on the `Portal`/`Context` APIs. @@ -1752,7 +1757,7 @@ class Context: else: report = ( - 'Queueing OVERRUN msg on caller task:\n\n' + 'Queueing OVERRUN msg on parent task:\n\n' + report ) log.debug(report) @@ -1948,12 +1953,12 @@ async def open_context_from_portal( IPC protocol. The yielded `tuple` is a pair delivering a `tractor.Context` - and any first value "sent" by the "callee" task via a call + and any first value "sent" by the "child" task via a call to `Context.started()`; this side of the - context does not unblock until the "callee" task calls + context does not unblock until the "child" task calls `.started()` in similar style to `trio.Nursery.start()`. - When the "callee" (side that is "called"/started by a call - to *this* method) returns, the caller side (this) unblocks + When the "child" (side that is "called"/started by a call + to *this* method) returns, the parent side (this) unblocks and any final value delivered from the other end can be retrieved using the `Contex.wait_for_result()` api. @@ -1966,7 +1971,7 @@ async def open_context_from_portal( __tracebackhide__: bool = hide_tb # denote this frame as a "runtime frame" for stack - # introspection where we report the caller code in logging + # introspection where we report the parent code in logging # and error message content. # NOTE: 2 bc of the wrapping `@acm` __runtimeframe__: int = 2 # noqa @@ -2025,7 +2030,7 @@ async def open_context_from_portal( # placeholder for any exception raised in the runtime # or by user tasks which cause this context's closure. scope_err: BaseException|None = None - ctxc_from_callee: ContextCancelled|None = None + ctxc_from_child: ContextCancelled|None = None try: async with ( collapse_eg(), @@ -2104,7 +2109,7 @@ async def open_context_from_portal( # that we can re-use it around the `yield` ^ here # or vice versa? # - # maybe TODO NOTE: between the caller exiting and + # maybe TODO NOTE: between the parent exiting and # arriving here the far end may have sent a ctxc-msg or # other error, so the quetion is whether we should check # for it here immediately and maybe raise so as to engage @@ -2170,16 +2175,16 @@ async def open_context_from_portal( # request in which case we DO let the error bubble to the # opener. # - # 2-THIS "caller" task somewhere invoked `Context.cancel()` - # and received a `ContextCanclled` from the "callee" + # 2-THIS "parent" task somewhere invoked `Context.cancel()` + # and received a `ContextCanclled` from the "child" # task, in which case we mask the `ContextCancelled` from - # bubbling to this "caller" (much like how `trio.Nursery` + # bubbling to this "parent" (much like how `trio.Nursery` # swallows any `trio.Cancelled` bubbled by a call to # `Nursery.cancel_scope.cancel()`) except ContextCancelled as ctxc: scope_err = ctxc ctx._local_error: BaseException = scope_err - ctxc_from_callee = ctxc + ctxc_from_child = ctxc # XXX TODO XXX: FIX THIS debug_mode BUGGGG!!! # using this code and then resuming the REPL will @@ -2216,11 +2221,11 @@ async def open_context_from_portal( # the above `._scope` can be cancelled due to: # 1. an explicit self cancel via `Context.cancel()` or # `Actor.cancel()`, - # 2. any "callee"-side remote error, possibly also a cancellation + # 2. any "child"-side remote error, possibly also a cancellation # request by some peer, - # 3. any "caller" (aka THIS scope's) local error raised in the above `yield` + # 3. any "parent" (aka THIS scope's) local error raised in the above `yield` except ( - # CASE 3: standard local error in this caller/yieldee + # CASE 3: standard local error in this parent/yieldee Exception, # CASES 1 & 2: can manifest as a `ctx._scope_nursery` @@ -2234,9 +2239,9 @@ async def open_context_from_portal( # any `Context._maybe_raise_remote_err()` call. # # 2.-`BaseExceptionGroup[ContextCancelled | RemoteActorError]` - # from any error delivered from the "callee" side + # from any error delivered from the "child" side # AND a group-exc is only raised if there was > 1 - # tasks started *here* in the "caller" / opener + # tasks started *here* in the "parent" / opener # block. If any one of those tasks calls # `.wait_for_result()` or `MsgStream.receive()` # `._maybe_raise_remote_err()` will be transitively @@ -2249,8 +2254,8 @@ async def open_context_from_portal( trio.Cancelled, # NOTE: NOT from inside the ctx._scope KeyboardInterrupt, - ) as caller_err: - scope_err = caller_err + ) as rent_err: + scope_err = rent_err ctx._local_error: BaseException = scope_err # XXX: ALWAYS request the context to CANCEL ON any ERROR. @@ -2289,9 +2294,9 @@ async def open_context_from_portal( 'Calling `ctx.cancel()`!\n' ) - # we don't need to cancel the callee if it already + # we don't need to cancel the child if it already # told us it's cancelled ;p - if ctxc_from_callee is None: + if ctxc_from_child is None: try: await ctx.cancel() except ( @@ -2322,8 +2327,8 @@ async def open_context_from_portal( # via a call to # `Context._maybe_cancel_and_set_remote_error()`. # As per `Context._deliver_msg()`, that error IS - # ALWAYS SET any time "callee" side fails and causes "caller - # side" cancellation via a `ContextCancelled` here. + # ALWAYS SET any time "child" side fails and causes + # "parent side" cancellation via a `ContextCancelled` here. try: result_or_err: Exception|Any = await ctx.wait_for_result() except BaseException as berr: @@ -2359,7 +2364,7 @@ async def open_context_from_portal( ) case (None, _): log.runtime( - 'Context returned final result from callee task:\n' + 'Context returned final result from child task:\n' f'<= peer: {uid}\n' f' |_ {nsf}()\n\n' @@ -2454,7 +2459,7 @@ async def open_context_from_portal( ) # TODO: should we add a `._cancel_req_received` - # flag to determine if the callee manually called + # flag to determine if the child manually called # `ctx.cancel()`? # -[ ] going to need a cid check no? @@ -2510,7 +2515,7 @@ def mk_context( recv_chan: trio.MemoryReceiveChannel send_chan, recv_chan = trio.open_memory_channel(msg_buffer_size) - # TODO: only scan caller-info if log level so high! + # TODO: only scan parent-info if log level so high! from .devx._frame_stack import find_caller_info caller_info: CallerInfo|None = find_caller_info()