Skip to content

Commit 09161fc

Browse files
authored
Fix crash when __pre_init__, kw_only, and defaults come together (#1319)
* Fix crash when __pre_init__, kw_only, and defaults come together Fixes #1284 * Add news fragment * Improve test
1 parent 689a0e6 commit 09161fc

3 files changed

Lines changed: 27 additions & 5 deletions

File tree

changelog.d/1319.change.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The combination of a `__attrs_pre_init__` that takes arguments, a kw-only field, and a default on that field does not crash anymore.

src/attr/_make.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,15 +2207,17 @@ def _attrs_to_init_script(
22072207
# leading comma & kw_only args
22082208
args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}"
22092209
pre_init_kw_only_args = ", ".join(
2210-
[f"{kw_arg}={kw_arg}" for kw_arg in kw_only_args]
2210+
[
2211+
f"{kw_arg_name}={kw_arg_name}"
2212+
# We need to remove the defaults from the kw_only_args.
2213+
for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args)
2214+
]
22112215
)
2212-
pre_init_args += (
2213-
", " if pre_init_args else ""
2214-
) # handle only kwargs and no regular args
2216+
pre_init_args += ", " if pre_init_args else ""
22152217
pre_init_args += pre_init_kw_only_args
22162218

22172219
if call_pre_init and pre_init_has_args:
2218-
# If pre init method has arguments, pass same arguments as `__init__`
2220+
# If pre init method has arguments, pass same arguments as `__init__`.
22192221
lines[0] = f"self.__attrs_pre_init__({pre_init_args})"
22202222

22212223
# Python 3.7 doesn't allow backslashes in f strings.

tests/test_make.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,25 @@ def __attrs_pre_init__(self2, y):
694694

695695
assert 12 == getattr(c, "z", None)
696696

697+
@pytest.mark.usefixtures("with_and_without_validation")
698+
def test_pre_init_kw_only_work_with_defaults(self):
699+
"""
700+
Default values together with kw_only don't break __attrs__pre_init__.
701+
"""
702+
val = None
703+
704+
@attr.define
705+
class KWOnlyAndDefault:
706+
kw_and_default: int = attr.field(kw_only=True, default=3)
707+
708+
def __attrs_pre_init__(self, *, kw_and_default):
709+
nonlocal val
710+
val = kw_and_default
711+
712+
inst = KWOnlyAndDefault()
713+
714+
assert 3 == val == inst.kw_and_default
715+
697716
@pytest.mark.usefixtures("with_and_without_validation")
698717
def test_post_init(self):
699718
"""

0 commit comments

Comments
 (0)