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

Generic slots classes don't work #313

Closed
gabbard opened this issue Dec 12, 2017 · 8 comments
Closed

Generic slots classes don't work #313

gabbard opened this issue Dec 12, 2017 · 8 comments
Labels

Comments

@gabbard
Copy link
Member

gabbard commented Dec 12, 2017

Attempting to create a generic attrs class with slots=True fails if it does not inherit from some other generic class.

from typing import TypeVar, Generic, Container
from unittest import TestCase

from attr import attrs

T = TypeVar('T')


class TestGenericBug(TestCase):
    def test_no_slots_ok(self):
        @attrs
        class Foo(Generic[T]):
            pass

    def test_no_attrs(self):
        class Meep(Generic[T]):
            __slots__ = ()

    def test_frozen_with_generic_parent_ok(self):
        @attrs(frozen=True)
        class Foo2(Generic[T], Container[T]):
            def __contains__(self, x: object) -> bool:
                return False
   
   # Failure is here
    def test_slots_with_no_parent(self):
        with self.assertRaisesRegex(TypeError, "Cannot inherit from plain Generic"):
            @attrs(slots=True)
            class Foo4(Generic[T]):
                pass

The full failure stack trace (if we remove the assertRaises is:

  File "/Users/gabbard/repos/isi-flexnlp/tests/util/test_generic_bug.py", line 27, in test_slots_with_no_parent
    class Foo4(Generic[T]):
  File "/Users/gabbard/anaconda3/envs/flexnlp/lib/python3.6/site-packages/attr/_make.py", line 637, in wrap
    return builder.build_class()
  File "/Users/gabbard/anaconda3/envs/flexnlp/lib/python3.6/site-packages/attr/_make.py", line 372, in build_class
    return self._create_slots_class()
  File "/Users/gabbard/anaconda3/envs/flexnlp/lib/python3.6/site-packages/attr/_make.py", line 442, in _create_slots_class
    cd,
  File "/Users/gabbard/anaconda3/envs/flexnlp/lib/python3.6/typing.py", line 948, in __new__
    raise TypeError("Cannot inherit from plain Generic")
TypeError: Cannot inherit from plain Generic

I am using attrs 17.3.0

@hynek
Copy link
Member

hynek commented Dec 15, 2017

This is something about meta classes, isn’t it? 😐

@dcbaker
Copy link

dcbaker commented Jun 1, 2018

I ran into this also (on 18.1), and discovered that oddly enough defining __slots__ myself and using attr.s(these={...}) does work.

simplified example:

@attr.s(these={'foo': attr.ib()})
class Foo(Generic[T]):
     __slots__ = ['foo']

I have tested that slots work correctly in this case.

I don't really know what that means, but maybe that's useful for narrowing it down?

@leftys
Copy link

leftys commented Sep 17, 2018

Confirming the bug in 18.2.0.

@dcbaker
Copy link

dcbaker commented Sep 17, 2018

This does work with python 3.7, at least with __future__.annotations, I haven't tested it without.

@wsanchez wsanchez added the Bug label Sep 11, 2019
ChrisTimperley added a commit to ChrisTimperley/dockerblade that referenced this issue Oct 12, 2019
ChrisTimperley added a commit to ChrisTimperley/dockerblade that referenced this issue Oct 12, 2019
…cess.run) (#10)

* added CompletedProcess class

* freeze

* updated execute to run

* added import

* removed slots=True as Python 3.6 workaround: python-attrs/attrs#313
@RazerM
Copy link

RazerM commented Aug 24, 2020

I used the workaround from @dcbaker, but you can use slots=True instead of defining it manually:

from typing import Generic, TypeVar
import attr

T = TypeVar('T')

@attr.s(these={'foo': attr.ib()}, slots=True)
class Foo(Generic[T]):
     pass

f = Foo(1)
assert not hasattr(f, '__dict__')
assert f.__slots__ == ('foo',)  # attrs 18.1
assert f.__slots__ == ('foo', '__weakref__')  # attrs 20.1

Edit: This only works on 3.7+ apparently

graingert added a commit to graingert/twisted that referenced this issue Jul 13, 2021
richvdh added a commit to matrix-org/synapse that referenced this issue Jul 16, 2021
reivilibre added a commit to matrix-org/synapse that referenced this issue Sep 2, 2021
DMRobertson pushed a commit to matrix-org/synapse that referenced this issue Sep 23, 2021
@reivilibre
Copy link

To save future readers from confusion: the workaround in commit matrix-org/synapse@d15d241 above does not work and was discarded after it was found not to work.

(People on our team keep coming across this issue and thinking 'oh look, (other team member) already found a workaround!' only to be confused when it doesn't do the trick..)

@jhominal
Copy link

As this bug occurs only in Python <= 3.6, and the next version will drop Python 3.6 support, maybe this issue should be closed?

@hynek
Copy link
Member

hynek commented Mar 17, 2023

yeah looks like this is not an issue on 3.7+ anymore – thanks!

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

No branches or pull requests

8 participants