How to type annotate a Gzipfile in Python?
Pyright complains when I use the following code to process gzip files:
import gzip
import os
import typing
def readfile(f: os.PathLike | typing.TextIO):
pass
with gzip.open("/path/to/foo.gz", 'r') as input:
readfile(input)
Diagnostics:
Argument of type "GzipFile" cannot be assigned to parameter "file" of type "PathLike[Unknown] | TextIO" in func
tion "readfile"
Type "GzipFile" is incompatible with type "PathLike[Unknown] | TextIO"
"GzipFile" is incompatible with protocol "PathLike[Unknown]"
"__fspath__" is not present
"GzipFile" is incompatible with "TextIO" [reportArgumentType]
Text File inside
- According to the gzip.open() docs:
The filename argument can be an actual filename (a str or bytes object), or an existing file object to read from or write to.
The mode argument can be any of ‘r’, ‘rb’, ‘a’, ‘ab’, ‘w’, ‘wb’, ‘x’ or ‘xb’ for binary mode, or ‘rt’, ‘at’, ‘wt’, or ‘xt’ for text mode. The default is ‘rb’.
For binary mode, this function is equivalent to the GzipFile constructor: GzipFile(filename, mode, compresslevel). In this case, the encoding, errors and newline arguments must not be provided.
For text mode, a GzipFile object is created, and wrapped in an io.TextIOWrapper instance with the specified encoding, error handling behavior, and line ending(s).
- Thus when opening a gzip file whose content is indeed a text file, we must explicitly specify the file mode
't'
(in my case,'rt'
), so that it returns aio.TextIOWrapper
wrapped instance and won’t annoy the lsp with annotationtyping.TextIO
.
Binary File inside
GzipFile
is not a file object. A type annotationtyping.BinaryIO
is not compatible with it. We can annotate the object with barelyGzipFile
.Constructor for the GzipFile class, which simulates most of the methods of a file object, with the exception of the truncate() method. At least one of fileobj and filename must be given a non-trivial value.
References
Stackoverflow: What exactly is a file-like object in Python?
Stackoverflow: Why does mypy complain about TextIOWrapper receiving GzipFile as argument 1?
GitHub: typeshed - typing.IO and io.BaseIO type hierarchies are incompatible
#gzip #lsp #python