Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

MyPy fails dataclass argument with optional list of objects type

I’m having trouble getting MyPy to pass my script which contains a dataclass Bar with an optional argument foos that holds a list of Foo objects and defaults to an empty list.

Stranger still, adding a method Bar.sum_foos() which iterates through self.foos raises a second MyPy error. Am I misunderstanding how to set the correct types, or is something else going on?

script.py

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

from __future__ import annotations
from typing import Optional
from dataclasses import dataclass, field


class Foo():
    pass


@dataclass
class Bar():
    foos: Optional[list[Foo]] = field(default_factory = list)

    def sum_foos(self) -> float:
        for foo in self.foos:
            pass
        return 0.0

2 MyPy errors

$ mypy script.py
script.py:12: error: Incompatible types in assignment (expression has type "List[_T]", variable has type "Optional[List[Foo]]")
script.py:15: error: Item "None" of "Optional[List[Foo]]" has no attribute "__iter__" (not iterable)
Found 2 errors in 1 file (checked 1 source file)

Versions

$ python --version
Python 3.8.12
$ mypy --version
mypy 0.950 (compiled: yes)

>Solution :

You have foos as an optional argument so if it’s None you can’t iterate of it and it will throw an error. You can add simple check before doing so. About second error its list of Foo so you need to add typing.

Fixed code:

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


class Foo():
    pass


@dataclass
class Bar():
    foos: Optional[list[Foo]] = field(default_factory=list[Foo])

    def sum_foos(self) -> float:
        if self.foos:
            for foo in self.foos:
                pass
        return 0.0
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading