classification
Title: dataclasses: ClassVar attributes are not working properly
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: eric.smith, stachel
Priority: normal Keywords:

Created on 2018-03-17 23:03 by stachel, last changed 2018-03-20 21:49 by eric.smith. This issue is now closed.

Messages (6)
msg314017 - (view) Author: Adrian Stachlewski (stachel) Date: 2018-03-17 23:03
Class variables should behave in the same way whether with or without ClassVar annotation. Unfortunately there are not.

class A:
    __slots__ = ()
    x: ClassVar = set()

A()  # it's ok

@dataclass
class B:
    __slots__ = ()
    x = set()

B()  # ok too

@dataclass
class C:
    __slots__ = ()
    # cannot use set() because of error
    x: ClassVar = field(default_factory=set) 

C()  # AttributeError: 'C' object has no attribute 'x'

Exception is raised from __init__ method, with flag init=False nothing changes. 

Python version: 3.7.0b2
msg314072 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-03-19 01:15
There are a couple of problems here. You're using ClassVar incorrectly. It should be:

>>> @dataclass
... class C:
...   __slots__=()
...   x: ClassVar[int] = field(default=3)
... 
>>> C()
C()
>>> C.x
3


And you cannot have a ClassVar with a default_factory, since it would never get called:

>>> @dataclass
... class C:
...   __slots__=()
...   x: ClassVar[int] = field(default_factory=set)
... 

    raise TypeError(f'field {f.name} cannot have a '
TypeError: field x cannot have a default factory

Although this error message could be improved. Neither InitVars or ClassVars can have default factories.

I'm not exactly sure how to improve the error message that you're seeing.
msg314075 - (view) Author: Adrian Stachlewski (stachel) Date: 2018-03-19 02:38
Thanks for explaining. I was trying to do something like

@dataclass
class A:
  x: ClassVar = set()

and thanks to you I know it should be 

@dataclass
class A:
  x: ClassVar[Set] = set()

If you are looking for improved error message, it's probably should be somehow connected to not proper usage of annotation. I've ended with default_factory because x: ClassVar = set() wasn't working and there was no error with default_factory and without slots.
msg314086 - (view) Author: Adrian Stachlewski (stachel) Date: 2018-03-19 08:56
Once more same mistake. 

'x' should be declared as: 
- x: ClassVar[set] = set()
- x: ClassVar[Set[Any]] = set()
msg314127 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-03-20 01:23
Are there any remaining issues here? If not, I'm going to close this issue.
msg314166 - (view) Author: Adrian Stachlewski (stachel) Date: 2018-03-20 21:47
There's nothing to do, thanks for help one more again.
History
Date User Action Args
2018-03-20 21:49:34eric.smithsetstatus: open -> closed
resolution: not a bug
stage: resolved
2018-03-20 21:47:51stachelsetstatus: pending -> open

messages: + msg314166
2018-03-20 01:23:04eric.smithsetstatus: open -> pending

messages: + msg314127
2018-03-19 08:56:31stachelsetmessages: + msg314086
2018-03-19 02:38:07stachelsetmessages: + msg314075
2018-03-19 01:16:12eric.smithsetversions: + Python 3.8
2018-03-19 01:15:56eric.smithsetmessages: + msg314072
2018-03-18 04:27:46rhettingersetassignee: eric.smith

nosy: + eric.smith
2018-03-17 23:03:50stachelcreate