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

"No mandatory attributes after..." error message #437

Open
aleaverfay opened this issue Aug 27, 2018 · 2 comments
Open

"No mandatory attributes after..." error message #437

aleaverfay opened this issue Aug 27, 2018 · 2 comments

Comments

@aleaverfay
Copy link

I was getting the

No mandatory attributes allowed after an attribute with a default value or factory.

error message related to issues #38 and #93. I had been stumped as to what the order of attributes was for my class and which ones had and which lacked defaults/factory methods. It would be super useful if the exception printed more about the offending attributes. In my case, I wanted to know:

"What is the first attribute that has a default that appears ahead of an attribute which lacks one?"

right now, the error message only tells me what attribute lacks a default.

E.g., I edited _make.py around line 331 (as of version 17.4) to this:

had_default = False
which_had_default = None
for a in attrs:
    if had_default is True and a.default is NOTHING and a.init is True:
        raise ValueError(
            "No mandatory attributes allowed after an attribute with a "
            "default value or factory.  Attribute in question: {a!r} appears after {before!r}"
            .format(a=a, before=which_had_default)
        )
    elif had_default is False and \
            a.default is not NOTHING and \
            a.init is not False:
        had_default = True
        which_had_default = a

(Printing only this message was not quite sufficient for my pretty funky case, and so I ended up printing out the full ordered list of attributes to see which were appearing out of reverse-MRO order and causing my problem. It might be even more helpful to print out the full attrs list in the even of an error.)

@hynek hynek added the Feature label Aug 28, 2018
@micimize
Copy link

It might also be good to better document / message that kw_only can be used to address this use case:

# kw default in parent
@attr.s(auto_attribs=True, hash=True, collect_by_mro=True)
class A:
    a: int = attr.field(default=1, kw_only=True)

@attr.s(auto_attribs=True, hash=True, collect_by_mro=True)
class B(A):
    b: int

B(1)
# kw required in subclass
@attr.s(auto_attribs=True, hash=True, collect_by_mro=True)
class A:
    a: int = 1

@attr.s(auto_attribs=True, hash=True, collect_by_mro=True)
class B(A):
    b: int = attr.field(kw_only=True)

B(b=1)

@four43
Copy link

four43 commented Jul 19, 2023

Just leaving a note about this - it's a little more explicit now, like @aleaverfay had suggested. My error message (post stack trace):

ValueError: No mandatory attributes allowed after an attribute with a default value or factory.  Attribute in question: Attribute(name='input', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=typing.Tuple[pathlib.Path, pathlib.Path], converter=None, kw_only=False, inherited=False, on_setattr=None, alias=None)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants