Add `tests/msg/` sub-pkg, audit `pformat()` filtering
Reorganize existing msg-related test suites under
a new `tests/msg/` subdir (matching `tests/devx/`
and `tests/ipc/` convention) and add unit tests for
the `_`-prefixed field filtering in `pformat()`.
Deats,
- `git mv` `test_ext_types_msgspec` and `test_pldrx_limiting` into
`tests/msg/`.
- add `__init__.py` + `conftest.py` for the new test sub-pkg.
- add new `test_pretty_struct.py` suite with 8 unit tests:
- parametrized field visibility (public shown, `_`-private hidden,
mixed)
- direct `iter_struct_ppfmt_lines()` assertion
- nested struct recursion filtering
- empty struct edge case
- real `MsgDec` via `mk_dec()` hiding `_dec`
- `repr()` integration via `Struct.__repr__()`
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
ns_aware
parent
8215a7ba34
commit
1529095c32
|
|
@ -0,0 +1,4 @@
|
|||
'''
|
||||
`tractor.msg.*` sub-sys test suite.
|
||||
|
||||
'''
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
'''
|
||||
`tractor.msg.*` test sub-pkg conf.
|
||||
|
||||
'''
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
'''
|
||||
Unit tests for `tractor.msg.pretty_struct`
|
||||
private-field filtering in `pformat()`.
|
||||
|
||||
'''
|
||||
from typing import (
|
||||
Any,
|
||||
)
|
||||
|
||||
import pytest
|
||||
|
||||
from tractor.msg.pretty_struct import (
|
||||
Struct,
|
||||
pformat,
|
||||
iter_struct_ppfmt_lines,
|
||||
)
|
||||
from tractor.msg._codec import (
|
||||
MsgDec,
|
||||
mk_dec,
|
||||
)
|
||||
|
||||
|
||||
# ------ test struct definitions ------ #
|
||||
|
||||
class PublicOnly(Struct):
|
||||
'''
|
||||
All-public fields for baseline testing.
|
||||
|
||||
'''
|
||||
name: str = 'alice'
|
||||
age: int = 30
|
||||
|
||||
|
||||
class PrivateOnly(Struct):
|
||||
'''
|
||||
Only underscore-prefixed (private) fields.
|
||||
|
||||
'''
|
||||
_secret: str = 'hidden'
|
||||
_internal: int = 99
|
||||
|
||||
|
||||
class MixedFields(Struct):
|
||||
'''
|
||||
Mix of public and private fields.
|
||||
|
||||
'''
|
||||
name: str = 'bob'
|
||||
_hidden: int = 42
|
||||
value: float = 3.14
|
||||
_meta: str = 'internal'
|
||||
|
||||
|
||||
class Inner(
|
||||
Struct,
|
||||
frozen=True,
|
||||
):
|
||||
'''
|
||||
Frozen inner struct with a private field,
|
||||
for nesting tests.
|
||||
|
||||
'''
|
||||
x: int = 1
|
||||
_secret: str = 'nope'
|
||||
|
||||
|
||||
class Outer(Struct):
|
||||
'''
|
||||
Outer struct nesting an `Inner`.
|
||||
|
||||
'''
|
||||
label: str = 'outer'
|
||||
inner: Inner = Inner()
|
||||
|
||||
|
||||
class EmptyStruct(Struct):
|
||||
'''
|
||||
Struct with zero fields.
|
||||
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
# ------ tests ------ #
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'struct_and_expected',
|
||||
[
|
||||
(
|
||||
PublicOnly(),
|
||||
{
|
||||
'shown': ['name', 'age'],
|
||||
'hidden': [],
|
||||
},
|
||||
),
|
||||
(
|
||||
MixedFields(),
|
||||
{
|
||||
'shown': ['name', 'value'],
|
||||
'hidden': ['_hidden', '_meta'],
|
||||
},
|
||||
),
|
||||
(
|
||||
PrivateOnly(),
|
||||
{
|
||||
'shown': [],
|
||||
'hidden': ['_secret', '_internal'],
|
||||
},
|
||||
),
|
||||
],
|
||||
ids=[
|
||||
'all-public',
|
||||
'mixed-pub-priv',
|
||||
'all-private',
|
||||
],
|
||||
)
|
||||
def test_field_visibility_in_pformat(
|
||||
struct_and_expected: tuple[
|
||||
Struct,
|
||||
dict[str, list[str]],
|
||||
],
|
||||
):
|
||||
'''
|
||||
Verify `pformat()` shows public fields
|
||||
and hides `_`-prefixed private fields.
|
||||
|
||||
'''
|
||||
(
|
||||
struct,
|
||||
expected,
|
||||
) = struct_and_expected
|
||||
output: str = pformat(struct)
|
||||
|
||||
for field_name in expected['shown']:
|
||||
assert field_name in output, (
|
||||
f'{field_name!r} should appear in:\n'
|
||||
f'{output}'
|
||||
)
|
||||
|
||||
for field_name in expected['hidden']:
|
||||
assert field_name not in output, (
|
||||
f'{field_name!r} should NOT appear in:\n'
|
||||
f'{output}'
|
||||
)
|
||||
|
||||
|
||||
def test_iter_ppfmt_lines_skips_private():
|
||||
'''
|
||||
Directly verify `iter_struct_ppfmt_lines()`
|
||||
never yields tuples with `_`-prefixed field
|
||||
names.
|
||||
|
||||
'''
|
||||
struct = MixedFields()
|
||||
lines: list[tuple[str, str]] = list(
|
||||
iter_struct_ppfmt_lines(
|
||||
struct,
|
||||
field_indent=2,
|
||||
)
|
||||
)
|
||||
# should have lines for public fields only
|
||||
assert len(lines) == 2
|
||||
|
||||
for _prefix, line_content in lines:
|
||||
field_name: str = (
|
||||
line_content.split(':')[0].strip()
|
||||
)
|
||||
assert not field_name.startswith('_'), (
|
||||
f'private field leaked: {field_name!r}'
|
||||
)
|
||||
|
||||
|
||||
def test_nested_struct_filters_inner_private():
|
||||
'''
|
||||
Verify that nested struct's private fields
|
||||
are also filtered out during recursion.
|
||||
|
||||
'''
|
||||
outer = Outer()
|
||||
output: str = pformat(outer)
|
||||
|
||||
# outer's public field
|
||||
assert 'label' in output
|
||||
|
||||
# inner's public field (recursed into)
|
||||
assert 'x' in output
|
||||
|
||||
# inner's private field must be hidden
|
||||
assert '_secret' not in output
|
||||
|
||||
|
||||
def test_empty_struct_pformat():
|
||||
'''
|
||||
An empty struct should produce a valid
|
||||
`pformat()` result with no field lines.
|
||||
|
||||
'''
|
||||
output: str = pformat(EmptyStruct())
|
||||
assert 'EmptyStruct(' in output
|
||||
assert output.rstrip().endswith(')')
|
||||
|
||||
# no field lines => only struct header+footer
|
||||
lines: list[tuple[str, str]] = list(
|
||||
iter_struct_ppfmt_lines(
|
||||
EmptyStruct(),
|
||||
field_indent=2,
|
||||
)
|
||||
)
|
||||
assert lines == []
|
||||
|
||||
|
||||
def test_real_msgdec_pformat_hides_private():
|
||||
'''
|
||||
Verify `pformat()` on a real `MsgDec`
|
||||
hides the `_dec` internal field.
|
||||
|
||||
NOTE: `MsgDec.__repr__` is custom and does
|
||||
NOT call `pformat()`, so we call it directly.
|
||||
|
||||
'''
|
||||
dec: MsgDec = mk_dec(spec=int)
|
||||
output: str = pformat(dec)
|
||||
|
||||
# the private `_dec` field should be filtered
|
||||
assert '_dec' not in output
|
||||
|
||||
# but the struct type name should be present
|
||||
assert 'MsgDec(' in output
|
||||
|
||||
|
||||
def test_pformat_repr_integration():
|
||||
'''
|
||||
Verify that `Struct.__repr__()` (which calls
|
||||
`pformat()`) also hides private fields for
|
||||
custom structs that do NOT override `__repr__`.
|
||||
|
||||
'''
|
||||
mixed = MixedFields()
|
||||
output: str = repr(mixed)
|
||||
|
||||
assert 'name' in output
|
||||
assert 'value' in output
|
||||
assert '_hidden' not in output
|
||||
assert '_meta' not in output
|
||||
Loading…
Reference in New Issue