Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash when __pre_init__, kw_only, and defaults come together #1319

Merged
merged 4 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1319.change.md
Original file line number Diff line number Diff line change
@@ -0,0 +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.
12 changes: 7 additions & 5 deletions src/attr/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -2207,15 +2207,17 @@ def _attrs_to_init_script(
# leading comma & kw_only args
args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}"
pre_init_kw_only_args = ", ".join(
[f"{kw_arg}={kw_arg}" for kw_arg in kw_only_args]
[
f"{kw_arg_name}={kw_arg_name}"
# We need to remove the defaults from the kw_only_args.
for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args)
]
)
pre_init_args += (
", " if pre_init_args else ""
) # handle only kwargs and no regular args
pre_init_args += ", " if pre_init_args else ""
pre_init_args += pre_init_kw_only_args

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

# Python 3.7 doesn't allow backslashes in f strings.
Expand Down
19 changes: 19 additions & 0 deletions tests/test_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,25 @@ def __attrs_pre_init__(self2, y):

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

@pytest.mark.usefixtures("with_and_without_validation")
def test_pre_init_kw_only_work_with_defaults(self):
"""
Default values together with kw_only don't break __attrs__pre_init__.
"""
val = None

@attr.define
class KWOnlyAndDefault:
kw_and_default: int = attr.field(kw_only=True, default=3)

def __attrs_pre_init__(self, *, kw_and_default):
nonlocal val
val = kw_and_default

inst = KWOnlyAndDefault()

assert 3 == val == inst.kw_and_default

@pytest.mark.usefixtures("with_and_without_validation")
def test_post_init(self):
"""
Expand Down