使用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 subprocess

import 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 codecs

gnupg_stdout = codecs.getreader("utf-8")(gnupg_subprocess.stdout)

很好,因为它不会尝试重新打开流。但是它无法提供io.TextIOWrapperAPI。具体来说,它 并且

>>> 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

回到顶部