I am having difficulty getting my testing framework to work for a C-extension module for both Python2 and Python3. I like to run my docstrings through doctest
to make sure that I am not feeding my users bad information, so I want to run doctest
as part of my testing.
I don't believe that the source of my problem is the docstrings themselves, but rather how the doctest
module is trying to read my extension module. If I run doctest
with Python2 (on the module compiled against Python2), I get the output that I expect:
$ python -m doctest myext.so -v
...
1 items passed all tests:
98 tests in myext.so
98 tests in 1 items.
98 passed and 0 failed.
Test passed.
However, when I do the same but with Python3, I get a UnicodeDecodeError
:
$ python3 -m doctest myext3.so -v
Traceback (most recent call last):
...
File "/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/python3.3/doctest.py", line 223, in _load_testfile
return f.read(), filename
File "/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/python3.3/codecs.py", line 301, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcf in position 0: invalid continuation byte
To get some more info, I ran it through pytest
with full traceback:
$ python3 -m pytest --doctest-glob "*.so" --full-trace
...
self = <encodings.utf_8.IncrementalDecoder object at 0x102ff5110>
input = b'\xcf\xfa\xed\xfe\x07\x00\x00\x01\x03\x00\x00\x00\x08\x00\x00\x00\r\x00\x00\x00\xd0\x05\x00\x00\x85\x00\x00\x00\x00\x...edString\x00_PyUnicode_FromString\x00_Py_BuildValue\x00__Py_FalseStruct\x00__Py_TrueStruct\x00dyld_stub_binder\x00\x00'
final = True
def decode(self, input, final=False):
# decode input (taking the buffer into account)
data = self.buffer + input
> (result, consumed) = self._buffer_decode(data, self.errors, final)
E UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcf in position 0: invalid continuation byte
/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/python3.3/codecs.py:301: UnicodeDecodeError
It looks like doctest
is actually reading the .so
file to get the docstrings (rather than importing the module), but Python3 doesn't know how to decode the input. I can confirm this by replicating the byte string and traceback by trying to read the .so
file myself:
$ python3
Python 3.3.3 (default, Dec 10 2013, 20:13:18)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> open('myext3.so').read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/python3.3/codecs.py", line 301, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcf in position 0: invalid continuation byte
>>> open('myext3.so', 'rb').read()
b'\xcf\xfa\xed\xfe\x07\x00\x00\x01\x03\x00\x00\x00\x08\x00\x00\x00\r\x00\x00\x00\xd0\x05...'
Has anyone else run into this problem before? Is there a standard (or not-so-standard) way to get doctest
to execute tests on C extension modules on python3?
Update: I should also add that I get identical results on Travis-CI (see here), so it's not specific to my local build.
doctest
you need to compile for Python 3? – Unscrewdoctest
before, didn't realize it was a built in module. Maybe your PYTHONPATH is putting the version 2 module ahead of the version 3 one? – Unscrewsys.path
. Also, in the first traceback you can see that thedoctest.py
file is in the python 3.3 standard library location, so I don't think that is the problem. I appreciate your suggestions, keep them coming! – Chiachiack