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

Mypy reports incompatible types for an optional dataclass field with generic default factory #11923

Closed
sagittarian opened this issue Jan 6, 2022 · 5 comments
Labels
bug mypy got something wrong topic-dataclasses topic-type-context Type context / bidirectional inference

Comments

@sagittarian
Copy link

Bug Report

In a dataclass with an optional field with a generic as the default factory, mypy reports that the types are incompatible when there should be no compatibility issue between them.

from typing import List, Optional
from dataclasses import dataclass, field


@dataclass
class A:
    x: Optional[List[int]] = field(default_factory=list)

Expected Behavior

A bare list is compatible with Optional[List[int]], so no error should be reported.

Actual Behavior

$ mypy ./optlist.py 
optlist.py:7: error: Incompatible types in assignment (expression has type "List[_T]", variable has type "Optional[List[int]]")
Found 1 error in 1 file (checked 1 source file)

Your Environment

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.3 LTS"
$ python --version
Python 3.8.10
$ mypy --version
mypy 0.930
@yoann9344
Copy link

yoann9344 commented Feb 24, 2023

def optional_list() -> list | None:
    return list()


@dataclass
class A:
    x: Optional[List[int]] = field(default_factory=optional_list)

Or even more convenient :

from dataclasses import dataclass, field
from typing import List, Optional, TypeVar, Callable


T = TypeVar("T")


def optional(type: type[T]) -> Callable[[], T | None]:
    def factory() -> T | None:
        return type()

    return factory


@dataclass
class A:
    x: Optional[List[int]] = field(default_factory=optional(list))

@JelleZijlstra JelleZijlstra added the topic-type-context Type context / bidirectional inference label Feb 24, 2023
@Pycz
Copy link

Pycz commented Mar 2, 2023

Same problem with the default dict factory, which should create an empty dictionary.

from typing import Dict, Any
from dataclasses import dataclass, field


@dataclasses.dataclass
class A:
    data: Dict[str, Any] = dataclasses.field(default_factory=dict)

Error text

error: Incompatible types in assignment (expression has type "Dict[_KT, _VT]", variable has type "Dict[str, Any]")

@Pycz
Copy link

Pycz commented Mar 2, 2023

Another workaround:

from typing import Dict, Any, cast
from dataclasses import dataclass, field


@dataclasses.dataclass
class A:
    data: Dict[str, Any] = dataclasses.field(default_factory=cast(Dict[str, Any], dict))

@lteich
Copy link

lteich commented May 17, 2023

I think the workaround above has a mistake in it - it tries to cast a callable into a dictionary. The correct one is:

from typing import Dict, List, Optional, Tuple, Any, cast, Callable
from dataclasses import dataclass, field

@dataclass
class A:
    data: Dict[str, Any] = field(default_factory=cast(Callable[[], Dict[str, Any]], dict))

@ilevkivskyi
Copy link
Member

The original examples passes without errors on current master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-dataclasses topic-type-context Type context / bidirectional inference
Projects
None yet
Development

No branches or pull requests

6 participants