mypy overload and contextmanager

Viewed 154

I am trying to implement an abstract & concrete class for a file opener.

However, with mypy (v0.910 on Python 3.8) I can't seem to get the typing working. Below is my current code, and the error messages from mypy.

I also tried a few other "combinations" like @contextmanager on the abstract class, but just can't seem to find the right alchemy.

from abc import ABC, abstractmethod
from contextlib import contextmanager
from typing import ContextManager, Iterator, Literal, Union, overload


class Reader:
    """A file reader."""
    def __init__(self, path: str) -> None:
        self.path = path


class Writer:
    """A file writer."""
    def __init__(self, path: str) -> None:
        self.path = path


class FileOpenerAbstract(ABC):

    @overload
    @abstractmethod
    def open(self,
             path: str,
             mode: Literal['r']
    ) -> ContextManager[Reader]:
        ...

    @overload
    @abstractmethod
    def open(self,
             path: str,
             mode: Literal['x', 'w', 'a']
    ) -> ContextManager[Writer]:
        ...

    @abstractmethod
    def open(
        self,
        path: str,
        mode: Literal['r', 'x', 'w', 'a'] = 'r'
    ) -> Union[ContextManager[Reader], ContextManager[Writer]]:
        """Open an archive"""


class FileOpener(FileOpenerAbstract):

    @overload
    @contextmanager
    def open(self,
             path: str,
             mode: Literal['r']
    ) -> Iterator[Reader]:
        ...

    @overload
    @contextmanager
    def open(self,
             path: str,
             mode: Literal['x', 'w', 'a']
    ) -> Iterator[Writer]:
        ...

    @contextmanager
    def open(
        self,
        path: str,
        mode: Literal['r', 'x', 'w', 'a'] = 'r',
    ) -> Union[Iterator[Reader], Iterator[Writer]]:
        if mode == 'r':
            yield Reader(path)
        else:
            yield Writer(path)

$ mypy mypy_test.py
mypy_test.py:47: error: Signature of "open" incompatible with supertype "FileOpenerAbstract"
mypy_test.py:63: error: Overloaded function implementation cannot produce return type of signature 1
mypy_test.py:63: error: Overloaded function implementation cannot produce return type of signature 2
mypy_test.py:64: error: Signature of "open" incompatible with supertype "FileOpenerAbstract"
Found 4 errors in 1 file (checked 1 source file)

any pointers on how to get this to work?

(note autocompletion with VS Code's Pylance, seems to work with this code, so I'm not sure if it is a limitation of mypy? But then again pylint also has issues with interpreting it)

0 Answers
Related