I’d like to make the type annotations for this function more specific:
def open_with_auto_compression(name: Any,
mode: str = "rt",
*,
ext: Optional[str] = None,
**kwargs: Any) -> Any:
"""Open a file, automatically compressing or decompressing it when
compression is indicated by the file extension. If 'ext' is
supplied, it overrides the extension on 'name' (this is useful
when 'name' is actually a file-like object). All other arguments
are passed down to open().
"""
if ext is None:
assert isinstance(name, str)
ext = os.path.splitext(name)[1]
if ext.startswith("."):
ext = ext[1:]
if ext == "gz":
import gzip
return gzip.open(name, mode, **kwargs)
elif ext == "bz2":
import bz2
return bz2.open(name, mode, **kwargs)
elif ext == "xz":
import lzma
return lzma.open(name, mode, format=lzma.FORMAT_XZ, **kwargs)
elif ext == "lzma":
import lzma
return lzma.open(name, mode, format=lzma.FORMAT_ALONE, **kwargs)
else:
return open(name, mode, **kwargs)
The problem is, first, that what the typeshed says for the built-in open
is a gigantic mess that I don’t want to copy into my code, and second, that even small subsets of it don’t work: for instance if I change the return type to IO[Any]
then I get
test.py:25: error: Incompatible return value type (got "Union[GzipFile, TextIO]", expected "IO[Any]")
What’s the best way to write accurate type annotations for this sort of function?