Fix send-side `MsgTypeError` rendering

Once `pformat_caller_frame()` renders successfully, the default
`_mk_send_mte()` path still fails while formatting the valid IPC
msg spec and then constructs its error message as a one-element
tuple.

Pass `MsgCodec` to `pformat_msgspec()`, keep the assembled message
a string and exercise the complete path through a printable
`MsgTypeError` regression.

Prompt-IO: ai/prompt-io/opencode/20260820T150250Z_9afda1c6_prompt_io.md

(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
pformat_caller_frame_render_guard
Gud Boi 2026-08-20 11:57:39 -04:00
parent 9afda1c61d
commit 33d74da8c2
5 changed files with 92 additions and 2 deletions

View File

@ -0,0 +1,33 @@
---
model: openai/gpt-5.6-sol
service: opencode
session: 7b9c97c4-fff7-4ac4-97fb-35720453308e
timestamp: 2026-08-20T15:02:50Z
git_ref: pformat_caller_frame_render_guard
scope: code
substantive: true
raw_file: 20260820T150250Z_9afda1c6_prompt_io.raw.md
---
## Prompt
Fix both newly exposed send-side `MsgTypeError` formatting failures
and pin them with an end-to-end regression in PR #503.
## Response summary
Corrected codec-spec formatting and default error-message assembly so
`_mk_send_mte()` returns a printable error instead of raising another
formatter exception.
## Files changed
- `tractor/msg/_codec.py` - pass the codec to its supported formatter.
- `tractor/_exceptions.py` - assemble the default message as `str`.
- `tests/devx/test_pformat.py` - render the complete default error.
## Human edits
The human selected both one-line fixes and the single end-to-end test
as coherent additions to PR #503, while leaving broader formatter
cleanup out of scope.

View File

@ -0,0 +1,25 @@
---
model: openai/gpt-5.6-sol
service: opencode
timestamp: 2026-08-20T15:02:50Z
git_ref: pformat_caller_frame_render_guard
diff_cmd: git diff HEAD~1..HEAD
---
## Prompt
After reviewing additional `tractor.devx.pformat` work suitable for
PR #503, the user approved fixing both send-side `MsgTypeError`
formatting failures and adding an end-to-end regression.
## Response
The generated code corrects the `MsgCodec.msg_spec_str` formatter
input, keeps `_mk_send_mte()`'s assembled default message a string,
and tests that the resulting `MsgTypeError` can be rendered:
> `git diff HEAD~1..HEAD -- tractor/msg/_codec.py tractor/_exceptions.py tests/devx/test_pformat.py`
These failures were hidden behind the original
`pformat_caller_frame()` keyword error addressed by the first two
commits on the branch.

View File

@ -6,10 +6,12 @@ from __future__ import annotations
import pytest
from tractor._exceptions import _mk_send_mte
from tractor.devx.pformat import (
pformat_boxed_tb,
pformat_caller_frame,
)
from tractor.msg._codec import _def_tractor_codec
@pytest.mark.parametrize(
@ -50,3 +52,33 @@ def test_pformat_boxed_tb_rejects_unknown_kwargs():
tb_str='doggy\n',
indent='',
)
def test_send_mte_default_message_renders():
'''
The default send-side `MsgTypeError` must remain printable.
Once `pformat_caller_frame()` stopped failing first, this path
exposed two more formatter errors: `MsgCodec.msg_spec_str` passed
a type union where `pformat_msgspec()` requires a codec/decoder,
then `_mk_send_mte()` wrapped its message in a one-element tuple.
Construct the error without an override message to execute that
complete default path. Requiring a `str` message with the bad
value and valid spec, then rendering the exception, proves the
original IPC violation survives every formatter layer.
'''
bad_msg: dict[str, bool] = {'bad': True}
mte = _mk_send_mte(
msg=bad_msg,
codec=_def_tractor_codec,
)
assert isinstance(mte.message, str)
assert f'invalid msg -> {bad_msg}' in mte.message
assert 'Valid IPC msgs are:' in mte.message
report: str = repr(mte)
assert 'MsgTypeError' in report
assert f'invalid msg -> {bad_msg}' in report

View File

@ -1509,7 +1509,7 @@ def _mk_send_mte(
f'invalid msg -> {msg}: {type(msg)}\n\n'
f'{tb_fmt}\n'
f'Valid IPC msgs are:\n\n'
f'{codec.msg_spec_str}\n',
f'{codec.msg_spec_str}\n'
)
elif src_type_error:
src_message: str = str(src_type_error)

View File

@ -430,7 +430,7 @@ class MsgCodec(Struct):
# wrapped field over the `.msg_spec` one?
@property
def msg_spec_str(self) -> str:
return pformat_msgspec(self.msg_spec)
return pformat_msgspec(self)
lib: ModuleType = msgspec