How can I wrap an open binary stream – a Python 2 file
, a Python 3 io.BufferedReader
, an io.BytesIO
– in an io.TextIOWrapper
?
I'm trying to write code that will work unchanged:
- Running on Python 2.
- Running on Python 3.
- With binary streams generated from the standard library (i.e. I can't control what type they are)
- With binary streams made to be test doubles (i.e. no file handle, can't re-open).
Example: wrapping the binary stream presented as the subprocess.Popen.stdout
attribute:
import subprocess
import io
gnupg_subprocess = subprocess.Popen(
["gpg", "--version"], stdout=subprocess.PIPE)
gnupg_stdout = io.TextIOWrapper(gnupg_subprocess.stdout)
In unit tests, the stream is replaced with an io.BytesIO
instance to control its content without touching any subprocesses or filesystems.
gnupg_subprocess.stdout = io.BytesIO("Lorem ipsum".encode("utf-8"))
That works fine on the streams created by Python 3's standard library. The same code, though, fails on streams generated by Python 2:
[Python 2]
>>> type(gnupg_subprocess.stdout)
<type 'file'>
>>> gnupg_stdout = io.TextIOWrapper(gnupg_subprocess.stdout)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'file' object has no attribute 'readable'
Some suggest re-opening (e.g. with io.open
) the underlying file handle:
gnupg_stdout = io.open(gnupg_subprocess.stdout, mode='r', encoding="utf-8")
That fails in unit tests when the test double is an io.BytesIO
instance:
>>> type(gnupg_subprocess.stdout)
<type '_io.BytesIO'>
>>> gnupg_stdout = io.open(gnupg_subprocess.stdout, mode='r', encoding="utf-8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: invalid file: <_io.BytesIO object at 0x7f23162fb290>
So how can I write code that works for both Python 2 and Python 3, with both the test doubles and the real objects, which wraps the byte stream as a text stream?
Aucun commentaire:
Enregistrer un commentaire