Structure hook on a PEP 695 alias is ignored inside a passthrough union
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 62/100
Hướng nghiên cứu
Start with the reproduction script in the issue, then read get_passthrough_base in src/cattrs/strategies/_unions.py (around lines 180-183 and 202-207), where a PEP 695 alias is unwrapped to its value before the union hook is built. The preconf converters pick this up through src/cattrs/preconf/json.py. Done means structure(' x ', Trimmed | int) returns 'x' again, matching 26.1.0, with a regression test that registers a hook on an alias and structures a union containing it.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Since 26.2.0, a structure hook registered for a PEP 695 type alias is skipped when the alias is a member of a union handled by the union passthrough strategy, which every preconf converter configures, so the raw value comes back with no error.
Minimal example
import cattrs
from cattrs.preconf.json import make_converter
from cattrs.strategies import configure_union_passthrough
type Trimmed = str
def build_plain():
c = cattrs.Converter()
configure_union_passthrough(str | int, c)
return c
for name, c in (("Converter + passthrough", build_plain()), ("preconf.json", make_converter())):
c.register_structure_hook_func(lambda t: t is Trimmed, lambda v, _: v.strip())
print(f"[{name}]")
print(" structure(' x ', Trimmed) observed:", repr(c.structure(" x ", Trimmed)))
print(" structure(' x ', Trimmed | int) observed:", repr(c.structure(" x ", Trimmed | int)))
print(" structure(' x ', Trimmed | int) expected:", repr("x"))
Observed output
[Converter + passthrough]
structure(' x ', Trimmed) observed: 'x'
structure(' x ', Trimmed | int) observed: ' x '
structure(' x ', Trimmed | int) expected: 'x'
[preconf.json]
structure(' x ', Trimmed) observed: 'x'
structure(' x ', Trimmed | int) observed: ' x '
structure(' x ', Trimmed | int) expected: 'x'
The hook runs for Trimmed on its own but not for Trimmed | int. Trimmed | int | None behaves the same way.
Expected behaviour
'x' in both cases, as 26.1.0 returns for the same script. The Type Aliases section of docs/defaulthooks.md says alias hooks can be overridden with predicate hooks, and its versionchanged 26.2.0 note about the passthrough strategy doesn't say those hooks are skipped inside unions.
Versions
- Python 3.12.3
- cattrs 26.2.1 (26.1.0 is not affected)
- attrs 26.1.0
- OS: Linux
Cause
In configure_union_passthrough (src/cattrs/strategies/_unions.py, main at 73fa273), get_passthrough_base (lines 180-181) replaces an alias with its value, so Trimmed becomes str in args (line 183) and in non_literal_classes (lines 202-207). The alias is then not in spillover, and the native union hook returns the value as is because val.__class__ in classes (lines 251 and 262). Before 26.2.0 the alias was not unwrapped, went to spillover, and converter.structure(val, Trimmed) reached the user hook. cattrs.preconf.json.make_converter() configures the passthrough at src/cattrs/preconf/json.py line 64, and the other preconf converters do the same, so any hook on a str, int, float, bool or bytes alias used in such a union is affected.
Proposed fix
Unwrap an alias only when the converter has no dedicated hook for it, for example when converter.get_structure_hook(alias) is still the product of the default type alias factory; otherwise leave the alias in spillover while the union is still claimed through its other members. A test that registers a hook on an alias and structures Alias | int would cover it.
I'm happy to open a PR with this fix and a test.
- Ngôn ngữ chính
- Python
- Star
- 1.1k
- Fork
- 171
- Merge trung bình
- 14 giờ 46 phút
- Pull request đã merge (30 ngày)
- 5
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của python-attrs/cattrs
-
Dataclass default_factory field treated as required in union disambiguationCó thể đã có người làm @Eryx-Z đã nhận 1 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
python-attrs/cattrs#796 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
decimal.Decimal not handled in preconf converters (json, pyyaml)Có thể đã có người làm @Binilkks đã nhận 113 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
python-attrs/cattrs#761 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
python-attrs/cattrs#513 · 4 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
msgspec converter skips hooks and drops private fields in nested recursionCó thể đã có người làm @Gabrieljr42 đã nhận 1 ngày trước. Đang mở
Độ khó 3/5 Nửa ngày Mức phù hợp với người mới 64/100
python-attrs/cattrs#795 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Getting the next structure hookĐang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 25/100
python-attrs/cattrs#794 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của python-attrs/cattrs
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
Maintainer thường phản hồi trong vòng 1 ngày
-
infrastructure qa
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
khuisman/mcp-gee-sweet#1068 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
The book has a Nix install section that chelis.ch lacks, and it names two of the three systemsĐang mởarea:ecosystem documentation
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Chelis-Lang/chelis#3866 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
`lvm_compact` has no self-hosted twin, and `docs/158` §5 says every language-face component mustĐang mởbug sev-3 vm
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
-
issue: Picking a prompt from the / menu in a channel inserts a command chip instead of the promptĐang mởbug confirmed issue
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 78/100
open-webui/open-webui#32712 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày