This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Wrong type when missname dataclass attribute with existing variable name
Type: behavior Stage: resolved
Components: Extension Modules Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: bux, eric.smith, gvanrossum, levkivskyi, xtreak
Priority: normal Keywords:

Created on 2019-03-19 13:29 by bux, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (4)
msg338354 - (view) Author: Bastien Sevajol (bux) Date: 2019-03-19 13:29
Hello,

For following code:

```
import dataclasses
import typing
from datetime import datetime


@dataclasses.dataclass
class Foo:
    datetime: typing.Optional[datetime] = None


print(dataclasses.fields(Foo)[0].type)
```

`datetime` `Foo` attribute have `NoneType` type. Problem come from `datetime` attribute name is already used by the `from datetime import datetime` import. I'm not sure if it is a bug or a strange behavior but it seems not regular. Tested on python 3.8.0a2 with same result.
msg338367 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-03-19 15:41
I am not sure this is a problem with dataclasses. dataclasses acts upon information from cls.__dict__.get('__annotations__', {}) at [0] and sets the type attribute for the field. Seems like using a valid identifier (class or function) used as class attribute along with defining it as optional type of the same name sets None type in annotation. Also happens when a class attribute is used with optional type for another attribute as in Spam class This more feels like a behavior with typing module. I am adding typing module maintainers for clarification.

# bpo36363.py

import typing

class Baz:
    pass

class Bar:
    pass

class Foo:
    baz: typing.Optional[Bar] = None
    Bar: typing.Optional[Bar] = None

class Spam:
    bar: typing.Optional[Bar] = None
    baz: typing.Optional[bar] = None

print(Foo.__dict__.get('__annotations__', {}))
print(Spam.__dict__.get('__annotations__', {}))

$ ./python.exe ../backups/bpo36363.py
{'baz': typing.Union[__main__.Bar, NoneType], 'Bar': <class 'NoneType'>}
{'bar': typing.Union[__main__.Bar, NoneType], 'baz': <class 'NoneType'>}


[0] https://github.com/python/cpython/blob/dcf617152e1d4c4a5e7965733928858a9c0936ca/Lib/dataclasses.py#L828
msg338387 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-03-19 16:53
class Spam:
    bar: typing.Optional[bar] = str

class Spaz:
    bar: typing.Optional[bar] = None

print(Spam.__annotations__)
print(Spaz.__annotations__)

{'bar': typing.Union[str, NoneType]}
{'bar': <class 'NoneType'>}

In Spam bar has str assigned to it and seems like in Spaz bar is assigned None and hence during annotation creation this evaluates to bar: typing.Optional[None] where None is the value of bar and in Spam.bar it's typing.Union[str, NoneType] instead.
msg338389 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-03-19 17:15
A simpler example shows it has nothing to do with annotations -- it is simply behavior of the typing module.

>>> import typing
>>> typing.Optional[str]
typing.Union[str, NoneType]
>>> typing.Optional[None]
<class 'NoneType'>
>>> 

I don't think there's a bug here, and I am closing this as "not a bug". The problem in the original code is that the annotation references a global name that is shadowed by a local (to the class body) name, and because of the initialization, the latter takes precedence.  (To see for yourself, use the dis module to disassemble the code for Spam and Spaz.)
History
Date User Action Args
2022-04-11 14:59:12adminsetgithub: 80544
2022-02-20 15:19:08serhiy.storchakalinkissue46807 superseder
2019-03-19 17:15:25gvanrossumsetstatus: open -> closed
resolution: not a bug
messages: + msg338389

stage: resolved
2019-03-19 16:53:21xtreaksetmessages: + msg338387
2019-03-19 15:41:34xtreaksetnosy: + xtreak, gvanrossum, levkivskyi

messages: + msg338367
versions: + Python 3.8
2019-03-19 15:05:01rhettingersetassignee: eric.smith
2019-03-19 13:40:40xtreaksetnosy: + eric.smith
2019-03-19 13:29:50buxcreate