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

Hybrid behavior doesn't work when maybe_cls=None and no annotations #673

Closed
euresti opened this issue Aug 21, 2020 · 2 comments · Fixed by #675
Closed

Hybrid behavior doesn't work when maybe_cls=None and no annotations #673

euresti opened this issue Aug 21, 2020 · 2 comments · Fixed by #675
Labels

Comments

@euresti
Copy link
Contributor

euresti commented Aug 21, 2020

The doc says:

    :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves
       exactly like `attr.s`. If left `None`, `attr.s` will try to guess:

       1. If all attributes are annotated and no `attr.ib` is found, it assumes
          *auto_attribs=True*.
       2. Otherwise it assumes *auto_attribs=False* and tries to collect
          `attr.ib`\ s.

Sadly it doesn't exactly work.

import attr

@attr.define()
class Trigger:
    a = attr.field()

The code does this:

    try:
        return do_it(True)
    except UnannotatedAttributeError:
        return do_it(False)

But do_it itself won't raise UnannotatedAttributeError until the decorator is applied to the class.

@hynek
Copy link
Member

hynek commented Aug 21, 2020

Ah yikes it’s about the (). I’m afk for now but any ideas how to make it work? 🤔

@euresti
Copy link
Contributor Author

euresti commented Aug 21, 2020

This seems to work but is not fully tested:

def define(
    maybe_cls=None,
    *,
   ...
):
    def wrap(cls):
        def do_it(auto_attribs):
            return attrs(
                maybe_cls=cls,
                these=these,
                repr=repr,
                hash=hash,
                init=init,
                slots=slots,
                frozen=frozen,
                weakref_slot=weakref_slot,
                str=str,
                auto_attribs=auto_attribs,
                kw_only=kw_only,
                cache_hash=cache_hash,
                auto_exc=auto_exc,
                eq=eq,
                order=order,
                auto_detect=auto_detect,
                collect_by_mro=True,
                getstate_setstate=getstate_setstate,
                on_setattr=on_setattr,
            )

        if auto_attribs is not None:
            return do_it(auto_attribs)

        try:
            return do_it(True)
        except UnannotatedAttributeError:
            return do_it(False)

    # maybe_cls's type depends on the usage of the decorator.  It's a class
    # if it's used as `@attrs` but ``None`` if used as `@attrs()`.
    if maybe_cls is None:
        return wrap
    else:
        return wrap(maybe_cls)

Edit: Fixed the code a bit.

@euresti euresti changed the title Hybrid behavior doesn't work. Hybrid behavior doesn't work when maybe_cls is None and no annotations Aug 23, 2020
@euresti euresti changed the title Hybrid behavior doesn't work when maybe_cls is None and no annotations Hybrid behavior doesn't work when maybe_cls=None and no annotations Aug 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants