Mv task UID formatting into `devx.pformat`
Add `pformat_task()` beside `pformat_task_uid()` so diagnostics can inspect an explicit endpoint, sibling or nursery-owning `trio.Task`. Keep the current-task default and decimal head/tail identity format. Preserve the `tractor.log` entry point with lazy forwarding, avoiding eager debugger initialization during logging imports. Move the existing formatting TODOs with the implementation. Exercise real parent/child tasks without an actor, including coroutine identity, nursery ownership and equivalent log/tooling UID output. Prompt-IO: ai/prompt-io/20261021T145344Z_0553fcf8_task_format_prompt_io.md Prompt-IO: ai/prompt-io/20261021T151133Z_0553fcf8_uid_move_prompt_io.md (this patch was generated in some part by `opencode` using `gpt-6.1-sol` (`openai`))piker_pin
parent
0553fcf88c
commit
bf2bb1c9a6
|
|
@ -0,0 +1,56 @@
|
||||||
|
---
|
||||||
|
created_at: 2026-10-21T14:53:44Z
|
||||||
|
generated_by:
|
||||||
|
harness: opencode
|
||||||
|
provider: openai
|
||||||
|
model: openai/gpt-6.1-sol
|
||||||
|
git_ref: 0553fcf8
|
||||||
|
scope: code
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20261021T145344Z_0553fcf8_task_format_prompt_io.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
The human requested moving the new regression-local Trio task formatter
|
||||||
|
into devx.pformat, scanning branches for earlier equivalents first, and
|
||||||
|
noted that log.pformat_task_uid already extracts the task ID. Follow-up:
|
||||||
|
the reviewed change was good enough apart from the function move; the
|
||||||
|
QA agent had already been alerted to the new order-bootstrap race.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Found no earlier detailed task formatter across 810 local refs and 18
|
||||||
|
worktrees. Extracted pformat_task into tooling and made the existing UID
|
||||||
|
helper accept an explicit task, preserving its established log output.
|
||||||
|
Added focused coverage that inspects a real child from its parent and
|
||||||
|
updated the cancellation regression to use the shared renderer.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `tractor/devx/pformat.py`: reusable pformat_task.
|
||||||
|
- `tractor/log.py`: optional explicit task for pformat_task_uid.
|
||||||
|
- `tests/devx/test_pformat.py`: real task-selection/ownership coverage.
|
||||||
|
- `tests/test_context_final_return_disconnect.py`: shared-tool callers.
|
||||||
|
|
||||||
|
## Review boundary and verification
|
||||||
|
|
||||||
|
Pre-move tree: `27e75d8b1cdfec1d96284d993e55ad3c51c3804c`.
|
||||||
|
HEAD remains `0553fcf88cd37b4d487eafb992071d4d1cc6e06f`.
|
||||||
|
The real index was unchanged at extraction start. Existing final-send
|
||||||
|
work and provenance are retained, including the earlier review record
|
||||||
|
that documents the then-local helper. Original Tuicr replies were not
|
||||||
|
rewritten; this extraction supersedes their local-helper description.
|
||||||
|
See the raw partner for environment details and focused verification.
|
||||||
|
|
||||||
|
Final verification repeated after import/line-wrap adjustments: 75
|
||||||
|
formatter/logger tests and 10 final-Return/RPC tests passed; Ruff,
|
||||||
|
whitespace and added-source 69-column checks passed. A read-only Tuicr
|
||||||
|
comparison found the saved session now contains only the first original
|
||||||
|
comment/reply pair, unlike the earlier three-pair receipt. This extraction
|
||||||
|
did not write session state or recreate the absent comments.
|
||||||
|
|
||||||
|
## Human edits
|
||||||
|
|
||||||
|
This extraction follows the human's requested final placement. Existing
|
||||||
|
logging TODOs, pre-review changes and task/review states are preserved.
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
---
|
||||||
|
created_at: 2026-10-21T14:53:44Z
|
||||||
|
generated_by:
|
||||||
|
harness: opencode
|
||||||
|
provider: openai
|
||||||
|
model: openai/gpt-6.1-sol
|
||||||
|
git_ref: 0553fcf8
|
||||||
|
diff_cmd: git diff HEAD~1..HEAD
|
||||||
|
---
|
||||||
|
|
||||||
|
## Generated output
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- tractor/devx/pformat.py tractor/log.py`
|
||||||
|
|
||||||
|
Moved the regression-local task renderer into devx.pformat.pformat_task.
|
||||||
|
It accepts an explicit Trio task or defaults to the current task, and
|
||||||
|
reports identity, coroutine, parent nursery/owner and child nurseries.
|
||||||
|
The new renderer reuses log.pformat_task_uid for the short identity,
|
||||||
|
rather than independently extracting and slicing id(task).
|
||||||
|
Added a keyword-only optional task argument to that existing UID helper;
|
||||||
|
its current-task default, positional id_part and decimal head/tail output
|
||||||
|
remain unchanged. The full Task repr retains the full native identity.
|
||||||
|
Kept the UID import local to the richer renderer so log headers do not
|
||||||
|
gain a dependency on devx initialization. Existing UID/color TODOs remain.
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- tests/test_context_final_return_disconnect.py tests/devx/test_pformat.py`
|
||||||
|
|
||||||
|
Removed the local formatter and switched its three consumers to the
|
||||||
|
shared tooling function. Added an actor-free live parent/child task test
|
||||||
|
that checks explicit-task selection, default current-task selection,
|
||||||
|
nursery ownership, coroutine identity, and unchanged head/tail log IDs.
|
||||||
|
The accepted final-result send guard is untouched by this extraction.
|
||||||
|
|
||||||
|
## Existing-work discovery
|
||||||
|
|
||||||
|
Read-only scan: 810 local branch/remote-tracking refs, 18 worktree path
|
||||||
|
inventories and task-formatting definitions, plus relevant all-ref history.
|
||||||
|
Only log.pformat_task_uid and this session's regression helper were found.
|
||||||
|
The dirty pformat.py in wkt/tipc_backend_wg_stack contains an unrelated
|
||||||
|
comment spelling correction; no other worktree was modified.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Worktree Python 3.13.13 / pytest 9.1.0 / Trio 0.29.0: formatter and logger
|
||||||
|
suites, 75 passed. Downstream Python 3.13.14 / pytest 9.0.2 / Trio 0.32.0:
|
||||||
|
final-Return regression and RPC suite, 10 passed. The older pytest in the
|
||||||
|
downstream environment remains below the current harness reference's
|
||||||
|
version bound; neither environment was changed. Ruff passed. A source
|
||||||
|
line-length check prompted wrapping before final verification.
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
created_at: 2026-10-21T15:11:33Z
|
||||||
|
generated_by:
|
||||||
|
harness: opencode
|
||||||
|
provider: openai
|
||||||
|
model: openai/gpt-6.1-sol
|
||||||
|
git_ref: 0553fcf8
|
||||||
|
scope: code
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20261021T151133Z_0553fcf8_uid_move_prompt_io.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
The human proposed moving pformat_task_uid into devx.pformat with the
|
||||||
|
new pformat_task and its unit test in a precursor commit, then placing
|
||||||
|
the final-result disconnect fix and matching tests in the next commit.
|
||||||
|
The request authorizes implementation and commit planning, not commits.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Moved the identity implementation into the formatting module, removed
|
||||||
|
the detailed formatter's reverse logging dependency, and preserved the
|
||||||
|
existing logging entry point through lazy forwarding. Retained the
|
||||||
|
existing TODO group and task-state markers. Extended focused identity
|
||||||
|
tests, verified the relocation and selected two dependency-ordered
|
||||||
|
whole-file commit boundaries with separate provenance.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `tractor/devx/pformat.py`: canonical short and detailed task formatters.
|
||||||
|
- `tractor/log.py`: lazy forwarding entry point for existing log users.
|
||||||
|
- `tests/devx/test_pformat.py`: canonical/log entry-point equivalence.
|
||||||
|
|
||||||
|
## Verification and human edits
|
||||||
|
|
||||||
|
75 formatter/logger tests and 10 downstream final-Return/RPC tests passed.
|
||||||
|
Ruff and whitespace checks passed. Both existing environments are kept;
|
||||||
|
the downstream pytest-version caveat is disclosed in prior records.
|
||||||
|
Earlier raw prompt records are retained unchanged as generation history.
|
||||||
|
No staging, commits, history changes or Tuicr mutations were performed.
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
created_at: 2026-10-21T15:11:33Z
|
||||||
|
generated_by:
|
||||||
|
harness: opencode
|
||||||
|
provider: openai
|
||||||
|
model: openai/gpt-6.1-sol
|
||||||
|
git_ref: 0553fcf8
|
||||||
|
diff_cmd: git diff HEAD~1..HEAD
|
||||||
|
---
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- tractor/devx/pformat.py tractor/log.py tests/devx/test_pformat.py`
|
||||||
|
|
||||||
|
Moved pformat_task_uid's implementation into devx.pformat alongside
|
||||||
|
pformat_task. The detailed renderer now calls the UID renderer directly;
|
||||||
|
it no longer imports logging. Kept the tractor.log entry point as a
|
||||||
|
lazy forwarding function to avoid eagerly initializing devx/debugger
|
||||||
|
modules while logging itself is being imported. Preserved the existing
|
||||||
|
current-task default and decimal head/tail ID output, plus explicit-task
|
||||||
|
selection added in the preceding extraction. Moved the existing TODO
|
||||||
|
group verbatim and did not change its checklist markers.
|
||||||
|
|
||||||
|
Extended the task test to compare the logging entry point and canonical
|
||||||
|
tooling renderer for current and selected child tasks in both ID modes.
|
||||||
|
The existing tests/devx/test_pformat.py module is reused.
|
||||||
|
|
||||||
|
Verification: formatter/logger suites 75 passed in 0.16s on the worktree
|
||||||
|
environment; final-Return/RPC suites 10 passed in 1.76s on the downstream
|
||||||
|
evaluation environment. Ruff and git diff --check passed. The downstream
|
||||||
|
pytest version remains 9.0.2; its current harness-version gap is recorded
|
||||||
|
in the earlier review/extraction provenance. No environment was changed.
|
||||||
|
|
||||||
|
Prepared the requested tooling-first, disconnect-fix-second boundary
|
||||||
|
selection. Planning itself does not execute checks, stage or commit.
|
||||||
|
|
@ -5,15 +5,82 @@ Unit tests for the `tractor.devx.pformat` render helpers.
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import trio
|
||||||
|
|
||||||
from tractor._exceptions import _mk_send_mte
|
from tractor._exceptions import _mk_send_mte
|
||||||
|
from tractor.log import pformat_task_uid as log_task_uid
|
||||||
from tractor.devx.pformat import (
|
from tractor.devx.pformat import (
|
||||||
pformat_boxed_tb,
|
pformat_boxed_tb,
|
||||||
pformat_caller_frame,
|
pformat_caller_frame,
|
||||||
|
pformat_task,
|
||||||
|
pformat_task_uid,
|
||||||
)
|
)
|
||||||
from tractor.msg._codec import _def_tractor_codec
|
from tractor.msg._codec import _def_tractor_codec
|
||||||
|
|
||||||
|
|
||||||
|
def test_pformat_task_selects_another_tasks_identity() -> None:
|
||||||
|
'''
|
||||||
|
Describe the selected task rather than the diagnostic caller.
|
||||||
|
|
||||||
|
The final-Return regression needs to snapshot an endpoint and its
|
||||||
|
nursery owner from another task. Hold a real child in an active
|
||||||
|
nursery and inspect it from its parent, checking both identities
|
||||||
|
and public nursery relationships without requiring an actor.
|
||||||
|
Preserve the log header's decimal head/tail ID convention while
|
||||||
|
allowing that existing helper to select an explicit task too.
|
||||||
|
|
||||||
|
'''
|
||||||
|
async def main() -> None:
|
||||||
|
'''
|
||||||
|
Keep the inspected child alive through all report assertions.
|
||||||
|
|
||||||
|
'''
|
||||||
|
async def child(
|
||||||
|
task_status: trio.TaskStatus[trio.lowlevel.Task],
|
||||||
|
) -> None:
|
||||||
|
'''
|
||||||
|
Publish the real task before waiting for cancellation.
|
||||||
|
|
||||||
|
'''
|
||||||
|
task_status.started(trio.lowlevel.current_task())
|
||||||
|
await trio.sleep_forever()
|
||||||
|
|
||||||
|
owner: trio.lowlevel.Task = trio.lowlevel.current_task()
|
||||||
|
owner_id: str = str(id(owner))
|
||||||
|
assert pformat_task_uid() == f'{owner.name}[{owner_id[-6:]}]'
|
||||||
|
assert pformat_task_uid('head') == (
|
||||||
|
f'{owner.name}[{owner_id[:6]}]'
|
||||||
|
)
|
||||||
|
assert log_task_uid() == pformat_task_uid()
|
||||||
|
assert log_task_uid('head') == pformat_task_uid('head')
|
||||||
|
async with trio.open_nursery() as nursery:
|
||||||
|
task: trio.lowlevel.Task = await nursery.start(child)
|
||||||
|
task_id: str = str(id(task))
|
||||||
|
task_uid: str = f'{task.name}[{task_id[-6:]}]'
|
||||||
|
report: str = pformat_task(task)
|
||||||
|
assert pformat_task_uid(task=task) == task_uid
|
||||||
|
assert pformat_task_uid('head', task=task) == (
|
||||||
|
f'{task.name}[{task_id[:6]}]'
|
||||||
|
)
|
||||||
|
assert log_task_uid(task=task) == task_uid
|
||||||
|
assert log_task_uid('head', task=task) == (
|
||||||
|
pformat_task_uid('head', task=task)
|
||||||
|
)
|
||||||
|
assert f'uid={task_uid!r}' in report
|
||||||
|
assert f'task={task!r}' in report
|
||||||
|
assert f'coro={task.coro!r}' in report
|
||||||
|
assert f'parent_nursery: {nursery!r}' in report
|
||||||
|
assert f'parent_task={owner!r}' in report
|
||||||
|
assert 'child_nurseries: ()' in report
|
||||||
|
assert f'child_nurseries: ({nursery!r},)' in (
|
||||||
|
pformat_task(owner)
|
||||||
|
)
|
||||||
|
assert pformat_task() == pformat_task(owner)
|
||||||
|
nursery.cancel_scope.cancel()
|
||||||
|
|
||||||
|
trio.run(main)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'box_tb',
|
'box_tb',
|
||||||
[True, False],
|
[True, False],
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,14 @@ import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from trio import CancelScope
|
from trio import (
|
||||||
|
CancelScope,
|
||||||
|
Nursery,
|
||||||
|
)
|
||||||
|
from trio.lowlevel import (
|
||||||
|
Task,
|
||||||
|
current_task,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_div(
|
def add_div(
|
||||||
|
|
@ -219,6 +226,70 @@ def pformat_caller_frame(
|
||||||
return tb_str
|
return tb_str
|
||||||
|
|
||||||
|
|
||||||
|
# TODO IDEAs:
|
||||||
|
# -[ ] move to `.devx.pformat`?
|
||||||
|
# -[ ] do per task-name and actor-name color coding
|
||||||
|
# -[ ] unique color per task-id and actor-uuid
|
||||||
|
def pformat_task_uid(
|
||||||
|
id_part: str = 'tail',
|
||||||
|
*,
|
||||||
|
task: Task|None = None,
|
||||||
|
|
||||||
|
) -> str:
|
||||||
|
'''
|
||||||
|
Render a task's name and a decimal head/tail slice of its ID.
|
||||||
|
|
||||||
|
Default to the current task, or select an explicit `task` when
|
||||||
|
rendering another task's identity from diagnostic tooling.
|
||||||
|
|
||||||
|
'''
|
||||||
|
if task is None:
|
||||||
|
task = current_task()
|
||||||
|
tid: str = str(id(task))
|
||||||
|
if id_part == 'tail':
|
||||||
|
tid_part: str = tid[-6:]
|
||||||
|
else:
|
||||||
|
tid_part: str = tid[:6]
|
||||||
|
|
||||||
|
return f'{task.name}[{tid_part}]'
|
||||||
|
|
||||||
|
|
||||||
|
def pformat_task(
|
||||||
|
task: Task|None = None,
|
||||||
|
|
||||||
|
) -> str:
|
||||||
|
'''
|
||||||
|
Render a Trio task's identity, execution and nursery ownership.
|
||||||
|
|
||||||
|
Default to the current task. An explicit `task` lets a caller
|
||||||
|
inspect a sibling or nursery owner without selecting itself.
|
||||||
|
Capture the report while that task is alive to retain its active
|
||||||
|
`Task.parent_nursery` and `Task.child_nurseries` relationships.
|
||||||
|
|
||||||
|
'''
|
||||||
|
if task is None:
|
||||||
|
task = current_task()
|
||||||
|
task_uid: str = pformat_task_uid(task=task)
|
||||||
|
nursery: Nursery|None = task.parent_nursery
|
||||||
|
parent_task: Task|None = (
|
||||||
|
nursery.parent_task if nursery is not None else None
|
||||||
|
)
|
||||||
|
child_nurseries: tuple[Nursery, ...] = tuple(
|
||||||
|
task.child_nurseries,
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
f'<Task(\n'
|
||||||
|
f' |_name: {task.name!r}\n'
|
||||||
|
f' uid={task_uid!r}\n'
|
||||||
|
f' task={task!r}\n'
|
||||||
|
f' coro={task.coro!r}\n'
|
||||||
|
f' |_parent_nursery: {nursery!r}\n'
|
||||||
|
f' parent_task={parent_task!r}\n'
|
||||||
|
f' |_child_nurseries: {child_nurseries!r}\n'
|
||||||
|
f')>\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def pformat_cs(
|
def pformat_cs(
|
||||||
cs: CancelScope,
|
cs: CancelScope,
|
||||||
var_name: str = 'cs',
|
var_name: str = 'cs',
|
||||||
|
|
|
||||||
|
|
@ -332,26 +332,20 @@ def add_log_level(
|
||||||
add_log_level('IO', 21, 'purple')
|
add_log_level('IO', 21, 'purple')
|
||||||
|
|
||||||
|
|
||||||
# TODO IDEAs:
|
|
||||||
# -[ ] move to `.devx.pformat`?
|
|
||||||
# -[ ] do per task-name and actor-name color coding
|
|
||||||
# -[ ] unique color per task-id and actor-uuid
|
|
||||||
def pformat_task_uid(
|
def pformat_task_uid(
|
||||||
id_part: str = 'tail'
|
id_part: str = 'tail',
|
||||||
):
|
*,
|
||||||
|
task: trio.lowlevel.Task|None = None,
|
||||||
|
|
||||||
|
) -> str:
|
||||||
'''
|
'''
|
||||||
Return `str`-ified unique for a `trio.Task` via a combo of its
|
Forward the logging entry point to devx.pformat's UID renderer.
|
||||||
`.name: str` and `id()` truncated output.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
task: trio.Task = trio.lowlevel.current_task()
|
# Import lazily: devx initialization itself imports tractor.log.
|
||||||
tid: str = str(id(task))
|
from .devx.pformat import pformat_task_uid as render_task_uid
|
||||||
if id_part == 'tail':
|
|
||||||
tid_part: str = tid[-6:]
|
|
||||||
else:
|
|
||||||
tid_part: str = tid[:6]
|
|
||||||
|
|
||||||
return f'{task.name}[{tid_part}]'
|
return render_task_uid(id_part, task=task)
|
||||||
|
|
||||||
|
|
||||||
_curr_actor_no_exc = partial(
|
_curr_actor_no_exc = partial(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue