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)