Skip to content

astuple: forward filter and recurse into attrs nested in dict values#1577

Open
HrachShah wants to merge 4 commits into
python-attrs:mainfrom
HrachShah:fix/astuple-filter-propagation-into-dicts
Open

astuple: forward filter and recurse into attrs nested in dict values#1577
HrachShah wants to merge 4 commits into
python-attrs:mainfrom
HrachShah:fix/astuple-filter-propagation-into-dicts

Conversation

@HrachShah

Copy link
Copy Markdown

Summary

attrs.astuple has a dict-handling branch that recursively serializes attrs instances found as keys and values. The recursive call only forwarded tuple_factory and retain_collection_types, silently dropping both recurse and filter. As a result, a user-supplied filter that was meant to drop fields from a nested attrs class had no effect when the instance lived inside a dict, while the parallel list branch a few lines above did forward both.

Fix

Pass recurse=True and filter=filter to the two recursive astuple calls in the dict branch of astuple.

Test

Added TestAsTuple.test_dicts_filter_applies_to_values parametrized over dict and OrderedDict. The test asserts that a filter dropping the 'a' attribute of an inner attrs class still drops it when the inner instance is nested as a dict value. Without the fix, the test fails because the inner 'a' field survives into the resulting tuple.

All 55 tests in tests/test_funcs.py pass. The unrelated tests/test_converters.py::TestPipe::test_wrapped_annotation failure exists on main already and is not caused by this change.

Zo Bot and others added 4 commits June 27, 2026 03:52
os.environb yields bytes on POSIX and the documented use case
for to_bool is reading values out of environment variables. The
truthy and falsy lookup tuples only contain str and int, so a
bytes('true') input raised 'Cannot convert value to bool: b\'true\''
even though its ASCII-decoded value is the canonical truthy
literal.

Decode bytes and bytearray as ASCII before the lowercase + lookup
step, matching the str path. Non-ASCII bytes raise ValueError
('Cannot convert value to bool: ...') the same way an unknown
string does, since the decoded text would still not match any
known literal. Unknown byte values raise the same ValueError.
The dict-handling branch in attrs.astuple recursively serialized attrs
instances found as keys and values but only passed tuple_factory and
retain_collection_types, dropping both recurse and filter.  A user filter
that was meant to drop fields from a nested attrs class therefore had no
effect when the instance lived inside a dict, while the parallel list
branch a few lines above did forward both.

Pass recurse=True and filter=filter to the recursive astuple calls so the
documented filter contract holds for dicts as well, and add a regression
test in TestAsTuple covering dict and OrderedDict containers with a
filter that drops a field on the nested attrs class.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant