为什么 mypy 抱怨 TextIOWrapper 接收 GzipFile 作为参数 1?
Why does mypy complain about TextIOWrapper receiving GzipFile as argument 1?
我正在将内容写入内存中的二进制流,以便将内容上传到 S3 而无需将其存储在本地文件中(我的内存比磁盘多 space)。以下代码有效,但 mypy mvce.py
失败并显示
mvce.py:6: error: Argument 1 to "TextIOWrapper" has incompatible type "GzipFile";
expected "IO[bytes]"
Found 1 error in 1 file (checked 1 source file)
mvce.py
from io import BytesIO, TextIOWrapper
import gzip
inmem = BytesIO()
with gzip.GzipFile(fileobj=inmem, mode="wb") as gzip_handler, TextIOWrapper(
gzip_handler, encoding="utf-8"
) as wrapper:
wrapper.write("some test string")
# Check if this actually worked
with open("foobar.gzip", "wb") as f1:
inmem.seek(0)
f1.write(inmem.read())
with gzip.open("foobar.gzip", "rb") as f2:
data = f2.read()
print(data)
问题
为什么 mypy 会失败,我该如何让它工作?是否存在隐藏的潜在问题?
为什么 MyPy 会失败?
MyPy 使用一组称为 Typeshed 的类型存根来定义标准库的类型。在 Typeshed 中,gzip.GzipFile
不继承自 typing.IO[bytes]
。
class 层次结构是:gzip.GzipFile -> _compression.BaseStream -> io.BufferedIOBase -> io.IOBase
。
如何让它发挥作用?
您可以使用 typing.cast(IO[bytes], gzip_handler)
向 MyPy 提示 GzipFile
实例应被视为二进制文件对象。有关转换的更多信息,请参阅 documentation。
或者,您可以使用 gzip.open(inmem, mode='wt', encoding="utf-8")
直接获取文本文件对象(与您正在做的基本相同,见下文)。此函数在 Typeshed 中具有 return 类型 IO[Any]
。
是否存在隐藏的潜在问题?
gzip
documentation 关于 gzip.open()
函数的说法:
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).
因此您的代码在实践中应该可以正常工作。
这可以在 Typeshed 中修复吗?
我尝试在 Typeshed 中添加 IO[bytes]
作为 GZipFile
的超级 class,但我在测试中遇到一个错误:
stdlib/3/gzip.pyi:17: error: Definition of "__enter__" in base class "IOBase" is incompatible with definition in base class "IO"
此问题的解决方案留作 reader 的练习。
我正在将内容写入内存中的二进制流,以便将内容上传到 S3 而无需将其存储在本地文件中(我的内存比磁盘多 space)。以下代码有效,但 mypy mvce.py
失败并显示
mvce.py:6: error: Argument 1 to "TextIOWrapper" has incompatible type "GzipFile";
expected "IO[bytes]"
Found 1 error in 1 file (checked 1 source file)
mvce.py
from io import BytesIO, TextIOWrapper
import gzip
inmem = BytesIO()
with gzip.GzipFile(fileobj=inmem, mode="wb") as gzip_handler, TextIOWrapper(
gzip_handler, encoding="utf-8"
) as wrapper:
wrapper.write("some test string")
# Check if this actually worked
with open("foobar.gzip", "wb") as f1:
inmem.seek(0)
f1.write(inmem.read())
with gzip.open("foobar.gzip", "rb") as f2:
data = f2.read()
print(data)
问题
为什么 mypy 会失败,我该如何让它工作?是否存在隐藏的潜在问题?
为什么 MyPy 会失败?
MyPy 使用一组称为 Typeshed 的类型存根来定义标准库的类型。在 Typeshed 中,gzip.GzipFile
不继承自 typing.IO[bytes]
。
class 层次结构是:gzip.GzipFile -> _compression.BaseStream -> io.BufferedIOBase -> io.IOBase
。
如何让它发挥作用?
您可以使用 typing.cast(IO[bytes], gzip_handler)
向 MyPy 提示 GzipFile
实例应被视为二进制文件对象。有关转换的更多信息,请参阅 documentation。
或者,您可以使用 gzip.open(inmem, mode='wt', encoding="utf-8")
直接获取文本文件对象(与您正在做的基本相同,见下文)。此函数在 Typeshed 中具有 return 类型 IO[Any]
。
是否存在隐藏的潜在问题?
gzip
documentation 关于 gzip.open()
函数的说法:
For text mode, a
GzipFile
object is created, and wrapped in anio.TextIOWrapper
instance with the specified encoding, error handling behavior, and line ending(s).
因此您的代码在实践中应该可以正常工作。
这可以在 Typeshed 中修复吗?
我尝试在 Typeshed 中添加 IO[bytes]
作为 GZipFile
的超级 class,但我在测试中遇到一个错误:
stdlib/3/gzip.pyi:17: error: Definition of "__enter__" in base class "IOBase" is incompatible with definition in base class "IO"
此问题的解决方案留作 reader 的练习。