当前位置: 首页 > 面试题库 >

使用io.TextIOWrapper包装一个开放流

岳均
2023-03-14
问题内容

如何将打开的二进制流(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。具体来说,它 不继承io.IOBase并且
不具有encoding属性

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


问题答案:

基于各种论坛上的多项建议,并尝试使用标准库来满足标准,我目前的结论是 这无法 像我们目前所拥有的 那样 使用库和类型 来完成



 类似资料:
  • 问题内容: 我希望能够放大HTML 5画布中鼠标下方的点,例如Google Maps上的。我该如何实现? 问题答案: 终于解决了: 关键是计算轴位置,以便缩放点(鼠标指针)在缩放后保持在同一位置。 最初,鼠标与角之间有一段距离,我们希望鼠标下方的点在缩放后保持在同一位置,但这是远离角的地方。因此,我们需要移动(角的坐标)以解决此问题。 然后,其余代码需要应用缩放并转换到绘制上下文,以便其原点与画布

  • 我想创建一个组件,它是一个具有自定义样式的DIV:背景色蓝色。在那之后,我想引用它并添加文本作为子对象。我正在尝试这样做: 包装器: 我是这样实例化的: 实例: 但它不起作用。我怎么能这样做?。非常感谢。

  • 我们有一个使用< code>Spring OAuth2的rest API。用户通过身份验证后,所有JSON响应都采用以下格式: 但是,身份验证失败的JSON响应与上述格式不符,因为这是由Spring处理的。 例如,在凭据不正确的情况下,客户端会获得带有JSON响应的HTTP状态代码400,如下所示: 如果用户帐户被锁定,客户端将获得 HTTP 状态代码 400,并按 JSON 响应进行如下操作 所

  • 我有一个上传包和安装curl命令的问题,它不适合我。这在AEM 6.1中不可用吗? curl-u admin:admin-F file=@“zip文件名”-F name=“包名”-F force=true-F install=truehttp://localhost:4502/crx/packmgr/service.jsp 当我第一次上传带有curl-u admin:admin-F package

  • 问题内容: 创建函数saveTxtIndividualTracks(track,folder,i)基于python3.4.3和Windows 7: 使用功能: 运行代码时,出现以下错误: FileNotFoundError:[错误2]没有这样的文件或目录:’E:/phoneTracks/TA92903URN7ff/0.txt’ 我在E中创建了文件夹。我对mode的功能感到困惑,该模式用于创建新文件

  • 问题内容: 我目前正在使用Boost.Python,希望获得一些帮助来解决棘手的问题。 语境 当C 方法/函数暴露给Python时,它需要释放GIL(全局解释器锁)以允许其他线程使用解释器。这样,当python代码调用C 函数时,解释器可以被其他线程使用。现在,每个C ++函数如下所示: 为了通过它来增强python,我这样做: 问题 该方案可以正常工作,但是这意味着没有充分理由依赖。理想情况下,