Merge pull request #503 from goodboy/pformat_caller_frame_render_guard
Fix `pformat_caller_frame()` render failurewkt/macos_ci_reruns
commit
3690e43abc
|
|
@ -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.
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
'''
|
||||||
|
Unit tests for the `tractor.devx.pformat` render helpers.
|
||||||
|
|
||||||
|
'''
|
||||||
|
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(
|
||||||
|
'box_tb',
|
||||||
|
[True, False],
|
||||||
|
ids=['boxed', 'bare'],
|
||||||
|
)
|
||||||
|
def test_pformat_caller_frame_renders(box_tb: bool):
|
||||||
|
'''
|
||||||
|
`pformat_caller_frame()` must render, not raise.
|
||||||
|
|
||||||
|
XXX the `box_tb=True` branch was passing an `indent=''` kwarg
|
||||||
|
that `pformat_boxed_tb()` never accepted, so it blew up with
|
||||||
|
a `TypeError`. Nothing in the test suite covered it, and the
|
||||||
|
only caller is `_mk_send_mte()` — i.e. EVERY send-side
|
||||||
|
`MsgTypeError` died while formatting itself, masking the real
|
||||||
|
msg-spec violation behind a bogus `TypeError`.
|
||||||
|
|
||||||
|
'''
|
||||||
|
report: str = pformat_caller_frame(
|
||||||
|
stack_limit=3,
|
||||||
|
box_tb=box_tb,
|
||||||
|
)
|
||||||
|
assert isinstance(report, str)
|
||||||
|
assert 'test_pformat_caller_frame_renders' in report
|
||||||
|
|
||||||
|
|
||||||
|
def test_pformat_boxed_tb_rejects_unknown_kwargs():
|
||||||
|
'''
|
||||||
|
Pin the signature so a future typo'd kwarg fails loudly at the
|
||||||
|
call site rather than only when some rare error path runs.
|
||||||
|
|
||||||
|
'''
|
||||||
|
assert pformat_boxed_tb(tb_str='doggy\n')
|
||||||
|
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
pformat_boxed_tb(
|
||||||
|
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
|
||||||
|
|
@ -1509,7 +1509,7 @@ def _mk_send_mte(
|
||||||
f'invalid msg -> {msg}: {type(msg)}\n\n'
|
f'invalid msg -> {msg}: {type(msg)}\n\n'
|
||||||
f'{tb_fmt}\n'
|
f'{tb_fmt}\n'
|
||||||
f'Valid IPC msgs are:\n\n'
|
f'Valid IPC msgs are:\n\n'
|
||||||
f'{codec.msg_spec_str}\n',
|
f'{codec.msg_spec_str}\n'
|
||||||
)
|
)
|
||||||
elif src_type_error:
|
elif src_type_error:
|
||||||
src_message: str = str(src_type_error)
|
src_message: str = str(src_type_error)
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,6 @@ def pformat_caller_frame(
|
||||||
tb_str: str = pformat_boxed_tb(
|
tb_str: str = pformat_boxed_tb(
|
||||||
tb_str=tb_str,
|
tb_str=tb_str,
|
||||||
field_prefix=' ',
|
field_prefix=' ',
|
||||||
indent='',
|
|
||||||
)
|
)
|
||||||
return tb_str
|
return tb_str
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,7 +430,7 @@ class MsgCodec(Struct):
|
||||||
# wrapped field over the `.msg_spec` one?
|
# wrapped field over the `.msg_spec` one?
|
||||||
@property
|
@property
|
||||||
def msg_spec_str(self) -> str:
|
def msg_spec_str(self) -> str:
|
||||||
return pformat_msgspec(self.msg_spec)
|
return pformat_msgspec(self)
|
||||||
|
|
||||||
lib: ModuleType = msgspec
|
lib: ModuleType = msgspec
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue