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

ValueError when using from __future__ import annotations #47

Open
isbadawi opened this issue May 4, 2023 · 3 comments
Open

ValueError when using from __future__ import annotations #47

isbadawi opened this issue May 4, 2023 · 3 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@isbadawi
Copy link

isbadawi commented May 4, 2023

With the below script, I get an exception:

from __future__ import annotations
from argparse_dataclass import dataclass

@dataclass
class MyArgs:
    foo: int = 0
    bar: str = 'hello'
    baz: bool = False

def main():
    print(MyArgs.parse_args())

if __name__ == '__main__':
    main()
$ python3 targ.py
Traceback (most recent call last):
  File "/Users/ibadawi/targ.py", line 4, in <module>
    @dataclass
     ^^^^^^^^^
  File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 474, in dataclass
    return wrap(cls)
           ^^^^^^^^^
  File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 465, in wrap
    cls.parse_args = staticmethod(ArgumentParser(cls).parse_args)
                                  ^^^^^^^^^^^^^^^^^^^
  File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 423, in __init__
    _add_dataclass_options(options_class, self)
  File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 374, in _add_dataclass_options
    parser.add_argument(*args, **kwargs)
  File "/usr/local/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/argparse.py", line 1448, in add_argument
    raise ValueError('%r is not callable' % (type_func,))
ValueError: 'int' is not callable

Removing from __future__ import annotations works fine and prints MyArgs(foo=0, bar='hello', baz=False) as expected.

It looks like the types as returned by dataclasses.fields() are just strings in this case. I'm not super familiar with writing code to process annotations but a workaround might be to use typing.get_type_hints() instead of dataclasses.fields() to get at the field types:

typing.get_type_hints(MyArgs):

{'bar': <class 'str'>, 'baz': <class 'bool'>, 'foo': <class 'int'>}

dataclasses.fields(MyArgs):

(Field(name='foo',type='int',default=0,default_factory=<dataclasses._MISSING_TYPE object at 0x10b1d5610>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD),
 Field(name='bar',type='str',default='hello',default_factory=<dataclasses._MISSING_TYPE object at 0x10b1d5610>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD),
 Field(name='baz',type='bool',default=False,default_factory=<dataclasses._MISSING_TYPE object at 0x10b1d5610>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD))
@ymd-h
Copy link

ymd-h commented Jun 6, 2023

I encountered the same issue.
By patching argparse_dataclass.fields() based on @isbadawi's idea, I could solve the error.

from __future__ import annotations
from dataclasses import fields
import argparse_dataclass
from typing import get_type_hints

def _patch_fields(cls, *args, **kwargs):
    t = get_type_hints(cls)
    def _update(_f):
        _f.type = t[_f.name]
        return _f
    
    return tuple(_update(f) for f in fields(cls, *args, **kwargs))

argparse_dataclass.fields = _patch_fields


@argparse_dataclass.dataclass
class MyArgs:
    foo: int = 0
    bar: str = 'hello'
    baz: bool = False

def main():
    print(MyArgs.parse_args())

if __name__ == '__main__':
    main()
MyArgs(foo=0, bar='hello', baz=False)

@mivade
Copy link
Owner

mivade commented Jun 6, 2023

See lovasoa/marshmallow_dataclass#186 for a solution to a similar problem.

Personally I never do this import because it has caused problems in the past with other libraries but I would be willing to accept a PR that addresses this.

ymd-h added a commit to ymd-h/argparse_dataclass that referenced this issue Jun 6, 2023
When importing __future__.annotations, class annotations are evaluated
lazily, and dataclasses.Field.type becomes str instead of actual type.

To access its accutual type, we patch the member.

Ref: mivade#47
@ymd-h
Copy link

ymd-h commented Jun 6, 2023

@mivade
Thank you for your reply.

I sent PR (#51).

@mivade mivade added bug Something isn't working help wanted Extra attention is needed labels Jun 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants