Skip to content

make_class() fails when passing dict of Attributes #1074

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

Closed
raphCode opened this issue Dec 28, 2022 · 6 comments · Fixed by #1075
Closed

make_class() fails when passing dict of Attributes #1074

raphCode opened this issue Dec 28, 2022 · 6 comments · Fixed by #1075

Comments

@raphCode
Copy link

I noticed this fails, but in my understanding of the manual it should work:

import attrs

@attrs.define
class Foo:
    bar: int

a = attrs.fields(Foo)[0]
attrs.make_class("Foo", dict(bar=a))
Traceback (most recent call last):
  File "test_attrs.py", line 9, in <module>
    attrs.make_class("Foo", dict(bar=a))
  File "/usr/lib/python3.10/site-packages/attr/_make.py", line 2888, in make_class
    return _attrs(these=cls_dict, **attributes_arguments)(type_)
  File "/usr/lib/python3.10/site-packages/attr/_make.py", line 1491, in wrap
    builder = _ClassBuilder(
  File "/usr/lib/python3.10/site-packages/attr/_make.py", line 658, in __init__
    attrs, base_attrs, base_map = _transform_attrs(
  File "/usr/lib/python3.10/site-packages/attr/_make.py", line 529, in _transform_attrs
    own_attrs = [
  File "/usr/lib/python3.10/site-packages/attr/_make.py", line 530, in <listcomp>
    Attribute.from_counting_attr(
  File "/usr/lib/python3.10/site-packages/attr/_make.py", line 2531, in from_counting_attr
    validator=ca._validator,
AttributeError: 'Attribute' object has no attribute '_validator'. Did you mean: 'validator'?

@raphCode
Copy link
Author

raphCode commented Dec 28, 2022

This fixes it for me now , so I can continue working:

attrs/src/attr/_make.py

Lines 2531 to 2532 in 88d2a37

validator=ca._validator,
default=ca._default,

validator=getattr(ca, "_validator", None),
default=getattr(ca, "_default", ca.default),

The real problem is probably somewhere else, I leave that up to the authors of the library :)

@raphCode
Copy link
Author

Bonus bug report:

With the above fix applied, I discovered that one can now pass Attributes in the wrong order: First an attribute with a default set, then one with default=NOTHING will produce this error:
ValueError: No mandatory attributes allowed after an attribute with a default value or factory.

Since 3.7 the insertion order of a dict is guaranteed, but I would argue that it would be less painful if make_class could automatically reorder the attributes if needed.

@hynek
Copy link
Member

hynek commented Dec 30, 2022

Oof that's not a bug, but documentation rot, because make_class has fallen a bit to the wayside.

As you can see in the example in https://www.attrs.org/en/stable/api.html#attrs.make_class, it doesn't take an instance of Attribute but a result of calling attr.ib() and it was never updated to new APIs.

Looking closer, in the end this seems to be another instance of #637, but adding the angle of make_class which should be kept in mind.

@hynek
Copy link
Member

hynek commented Dec 30, 2022

would you mind looking at #1075 and telling me if that's clearer?

@raphCode
Copy link
Author

raphCode commented Jan 1, 2023

Ohh I see.
That is funny because I actually looked at using attrs.field() but its return type was _CountingAttr which seemed far off what I wanted: not some sort of counter but a named Attribute.

I think the docs are better in that PR, yeah :)

What is Attribute.evolve() for then, when we can't use the evolved Attribute anywhere? (Or at least not with make_class, what I intended)

@hynek
Copy link
Member

hynek commented Jan 2, 2023

The Counting in CountingAttr comes from the fact that we had to add a class-counter on instantiation in pre-3.6 times to retain order of attribute definitions. :)


I have to admit that I'm somewhat confused why it's an public API, but it actually is part of the API docs 😇:

It is mainly meant to be used for Automatic Field Transformation and Modification.

attrs allows a lot of custom meta-programming and this is one of the features that allows the user to modify attributes, after attrs is done with it: https://www.attrs.org/en/stable/extending.html#transform-fields

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

Successfully merging a pull request may close this issue.

2 participants