From d7f3c345d22671d71b129036783ce0ce33105956 Mon Sep 17 00:00:00 2001 From: Mohammed Imaad Sharieff Date: Wed, 7 Jan 2026 11:18:32 +0530 Subject: [PATCH 1/3] Fix factory validation order --- src/attr/_make.py | 48 +++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index d24d9ba98..c9ceae865 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -2280,6 +2280,7 @@ def _attrs_to_init_script( init_factory_name = _INIT_FACTORY_PAT % (a.name,) if converter is not None: + # arg was passed explicitly → validate immediately lines.append( " " + fmt_setter_with_converter( @@ -2287,11 +2288,25 @@ def _attrs_to_init_script( ) ) lines.append("else:") + # no arg passed → run factory → validate → assign + lines.append( + " " + + f"val = {init_factory_name}({maybe_self})" + ) + if a.validator is not None: + val_name = "__attr_validator_" + a.name + attr_name_ref = "__attr_" + a.name + lines.append( + " " + + f"{val_name}(self, {attr_name_ref}, val)" + ) + names_for_globals[val_name] = a.validator + names_for_globals[attr_name_ref] = a lines.append( " " + fmt_setter_with_converter( attr_name, - init_factory_name + "(" + maybe_self + ")", + "val", has_on_setattr, converter, ) @@ -2300,37 +2315,30 @@ def _attrs_to_init_script( converter.converter ) else: + # arg passed explicitly → validate immediately lines.append( " " + fmt_setter(attr_name, arg_name, has_on_setattr) ) lines.append("else:") + # no arg passed → run factory → validate → assign + lines.append( + " " + + f"val = {init_factory_name}({maybe_self})" + ) + lines.append( + " " + + f"{validator_name}(self, a, val)" + ) lines.append( " " + fmt_setter( attr_name, - init_factory_name + "(" + maybe_self + ")", + "val", has_on_setattr, ) ) - names_for_globals[init_factory_name] = a.default.factory - else: - if a.kw_only: - kw_only_args.append(arg_name) - else: - args.append(arg_name) - pre_init_args.append(arg_name) - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + names_for_globals[init_factory_name] = a.default.factory if a.init is True: if a.type is not None and converter is None: From 81bbf6bb01595433489894bd8787208fbaaaa3f9 Mon Sep 17 00:00:00 2001 From: Mohammed Imaad Sharieff Date: Wed, 7 Jan 2026 11:22:12 +0530 Subject: [PATCH 2/3] Fix factory validation order --- src/attr/_make.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index c9ceae865..40737e490 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -2325,10 +2325,15 @@ def _attrs_to_init_script( " " + f"val = {init_factory_name}({maybe_self})" ) - lines.append( - " " - + f"{validator_name}(self, a, val)" - ) + if a.validator is not None: + val_name = "__attr_validator_" + a.name + attr_name_ref = "__attr_" + a.name + lines.append( + " " + + f"{val_name}(self, {attr_name_ref}, val)" + ) + names_for_globals[val_name] = a.validator + names_for_globals[attr_name_ref] = a lines.append( " " + fmt_setter( From b68d6d4885bbff2c934aa5e5d9dbb7ed1c448bd9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 06:06:21 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/attr/_make.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/attr/_make.py b/src/attr/_make.py index 40737e490..c64863153 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -2289,17 +2289,11 @@ def _attrs_to_init_script( ) lines.append("else:") # no arg passed → run factory → validate → assign - lines.append( - " " - + f"val = {init_factory_name}({maybe_self})" - ) + lines.append(f" val = {init_factory_name}({maybe_self})") if a.validator is not None: val_name = "__attr_validator_" + a.name attr_name_ref = "__attr_" + a.name - lines.append( - " " - + f"{val_name}(self, {attr_name_ref}, val)" - ) + lines.append(f" {val_name}(self, {attr_name_ref}, val)") names_for_globals[val_name] = a.validator names_for_globals[attr_name_ref] = a lines.append( @@ -2321,17 +2315,11 @@ def _attrs_to_init_script( ) lines.append("else:") # no arg passed → run factory → validate → assign - lines.append( - " " - + f"val = {init_factory_name}({maybe_self})" - ) + lines.append(f" val = {init_factory_name}({maybe_self})") if a.validator is not None: val_name = "__attr_validator_" + a.name attr_name_ref = "__attr_" + a.name - lines.append( - " " - + f"{val_name}(self, {attr_name_ref}, val)" - ) + lines.append(f" {val_name}(self, {attr_name_ref}, val)") names_for_globals[val_name] = a.validator names_for_globals[attr_name_ref] = a lines.append(