ericvsmith / dataclasses

Apache License 2.0
587 stars 53 forks source link

Don't force import of typing module #34

Closed ericvsmith closed 7 years ago

ericvsmith commented 7 years ago

Because typing is a large module, it would be nice for smaller programs to be able to use dataclasses without needing to import typing. The only place dataclasses.py uses typing is in this check:

        if type(a_type) is typing._ClassVar:
            # Skip this field if it's a ClassVar.
            continue

I think I could avoid using typing unless I know it's already been imported by dropping the import and changing that code to:

        # This is a hack for not depending on typing, unless it's already
        #  been loaded.
        typing = sys.modules.get('typing')
        if typing is not None:
            if type(a_type) is typing._ClassVar:
                # Skip this field if it's a ClassVar.
                continue

It seems to work:

% python3
>>> import sys
>>> from dataclasses import dataclass
>>> @dataclass
... class C:
...    x: int
... 
>>> C.__dataclass_fields__
OrderedDict([('x', Field(name='x',type=<class 'int'>,default=_MISSING,default_factory=_MISSING,init=True,repr=True,hash=None,cmp=True))])
>>> 'typing' in sys.modules
False
>>> import typing
>>> @dataclass
... class C:
...     x: int
...     y: typing.ClassVar[int]
... 
>>> @dataclass
... class C:
...     x: int
...     y: typing.ClassVar[int]
... 
>>> C.__dataclass_fields__
OrderedDict([('x', Field(name='x',type=<class 'int'>,default=_MISSING,default_factory=_MISSING,init=True,repr=True,hash=None,cmp=True))])
>>> 

I haven't thought through all of the implications, but I wanted to record this thought while I'm thinking about it.

EDIT: for clarity

ilevkivskyi commented 7 years ago

Internally in typing we use __type__ to store the ClassVar argument. So that hasattr(tp, __type__) is a reasonable test that tp is a ClassVar. Of course some few people could use __type__ for their own purposes, but they are already doomed, since all dunders are reserved for Python "authorized" use. Although typing is still provisional there is very high chance that __type__ will stay and its meaning will be unchanged.

Anyway, I think your "hack" for this is perfectly fine.

ericvsmith commented 7 years ago

In an ideal world, I'd like there to be a typing.is_ClassVar(tp). But in the meantime, I'll leave the test as-is.

My trick for not importing typing works with the current code, or if we change exactly how we detect a ClassVar. So I'm just going to implement the no-import trick now.

ilevkivskyi commented 7 years ago

In an ideal world, I'd like there to be a typing.is_ClassVar(tp)

There is a small project https://github.com/ilevkivskyi/typing_inspect that has typing_inspect.is_classvar(tp). There is an idea to play with it, and maybe add this functionality to typing at some point (there were several requests for this).

ericvsmith commented 7 years ago

I fixed this in 10a5ebb3087efbff9537b028173b5e4d75b3a6a1, but I typo'd the issue number.

@ilevkivskyi : Put me down as another request for is_classvar(tp). For my use case, I'd like it to be in typing so I can use the trick where I don't call it unless I know ClassVar is available to the program.