使用io.TextIOWrapper包装一个开放流
如何将打开的二进制流(Python 2 file
,Python
3io.BufferedReader
和an)包装io.BytesIO
在中io.TextIOWrapper
?
我正在尝试编写将保持不变的代码:
- 在Python 2上运行。
- 在Python 3上运行。
- 使用从标准库生成的二进制流(即,我无法控制它们是什么类型)
- 将二进制流设为测试双倍(即没有文件句柄,无法重新打开)。
- 产生一个
io.TextIOWrapper
包装指定流的。
io.TextIOWrapper
之所以需要,是因为标准库的其他部分需要使用它的API。存在其他类似文件的类型,但是没有提供正确的API。
例
包装作为subprocess.Popen.stdout
属性显示的二进制流:
import subprocessimport io
gnupg_subprocess = subprocess.Popen(
["gpg", "--version"], stdout=subprocess.PIPE)
gnupg_stdout = io.TextIOWrapper(gnupg_subprocess.stdout, encoding="utf-8")
在单元测试中,用io.BytesIO
实例替换流以控制其内容,而不用触摸任何子进程或文件系统。
gnupg_subprocess.stdout = io.BytesIO("Lorem ipsum".encode("utf-8"))
在Python 3的标准库创建的流上,效果很好。但是,相同的代码在Python 2生成的流上失败:
[Python 2]>>> type(gnupg_subprocess.stdout)
<type 'file'>
>>> gnupg_stdout = io.TextIOWrapper(gnupg_subprocess.stdout, encoding="utf-8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'file' object has no attribute 'readable'
不是解决方案: file
一个明显的响应是在代码中具有一个分支,以测试流是否实际上是Python 2file
对象,并以与io.*
对象不同的方式处理该对象。
这不是经过良好测试的代码的选项,因为它会生成一个要进行单元测试的分支-为了尽快运行,该分支不得创建任何 真实的 文件系统对象-不能执行。
单元测试将提供测试加倍,而不是真实的file
对象。因此,创建那些测试双打不会使用的分支将破坏测试套件。
没有解决方案: io.open
一些受访者建议重新打开(例如使用io.open
)基础文件句柄:
gnupg_stdout = io.open( gnupg_subprocess.stdout.fileno(), mode='r', encoding="utf-8")
在Python 3和Python 2上均可使用
[Python 3]>>> type(gnupg_subprocess.stdout)
<class '_io.BufferedReader'>
>>> gnupg_stdout = io.open(gnupg_subprocess.stdout.fileno(), mode='r', encoding="utf-8")
>>> type(gnupg_stdout)
<class '_io.TextIOWrapper'>
[Python 2]
>>> type(gnupg_subprocess.stdout)
<type 'file'>
>>> gnupg_stdout = io.open(gnupg_subprocess.stdout.fileno(), mode='r', encoding="utf-8")
>>> type(gnupg_stdout)
<type '_io.TextIOWrapper'>
但是,当然,它 从文件句柄中
。因此,当测试double是一个io.BytesIO
实例时,它在单元测试中将失败:
>>> gnupg_subprocess.stdout = io.BytesIO("Lorem ipsum".encode("utf-8"))>>> type(gnupg_subprocess.stdout)
<type '_io.BytesIO'>
>>> gnupg_stdout = io.open(gnupg_subprocess.stdout.fileno(), mode='r', encoding="utf-8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
io.UnsupportedOperation: fileno
没有解决方案: codecs.getreader
标准库还具有该codecs
模块,该模块提供包装器功能:
import codecsgnupg_stdout = codecs.getreader("utf-8")(gnupg_subprocess.stdout)
很好,因为它不会尝试重新打开流。但是它无法提供io.TextIOWrapper
API。具体来说,它 并且
:
>>> type(gnupg_subprocess.stdout)<type 'file'>
>>> gnupg_stdout = codecs.getreader("utf-8")(gnupg_subprocess.stdout)
>>> type(gnupg_stdout)
<type 'instance'>
>>> isinstance(gnupg_stdout, io.IOBase)
False
>>> gnupg_stdout.encoding
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/codecs.py", line 643, in __getattr__
return getattr(self.stream, name)
AttributeError: '_io.BytesIO' object has no attribute 'encoding'
因此codecs
不提供替代的对象io.TextIOWrapper
。
该怎么办?
那么,如何通过测试倍数和真实对象编写适用于Python 2和Python 3的代码,这些对象
?
回答:
基于各种论坛上的多项建议,并尝试使用标准库来满足标准,我目前的结论是 像我们目前所拥有的 使用库和类型 。
以上是 使用io.TextIOWrapper包装一个开放流 的全部内容, 来源链接: utcz.com/qa/427948.html