Pytest: INTERNALERROR when skipping a test if using ``--html=report.html`` (pytest 6.0.0)

Created on 28 Jul 2020  ·  7Comments  ·  Source: pytest-dev/pytest

INTERNALERROR> AttributeError: 'tuple' object has no attribute 'rsplit'

Here's the file I was running with pytest: (skip_test.py)

import pytest

class TestClass():
    def test_skip(self):
        pytest.skip()

The run command (environment is a Bash shell on a MacBook Pro running macOS Mojave):

pytest skip_test.py --html=report.html
=========================== test session starts ===========================
platform darwin -- Python 3.7.0, pytest-6.0.0, py-1.9.0, pluggy-0.13.1
rootdir: /Users/michael/github/SeleniumBase, configfile: pytest.ini
plugins: html-2.0.1, rerunfailures-9.0, metadata-1.10.0, cov-2.10.0, xdist-1.34.0, ordering-0.6, allure-pytest-2.8.17, forked-1.3.0

INTERNALERROR> Traceback (most recent call last):
...
INTERNALERROR> AttributeError: 'tuple' object has no attribute 'rsplit'
=========================== 1 skipped in 0.03s ============================

Here's the pip list:

allure-pytest         2.8.17
allure-python-commons 2.8.17
apipkg                1.5
appnope               0.1.0
attrs                 19.3.0
backcall              0.2.0
beautifulsoup4        4.9.1
boto                  2.49.0
brython               3.8.9
certifi               2020.6.20
cffi                  1.14.1
chardet               3.0.4
colorama              0.4.3
commonmark            0.9.1
coverage              5.2.1
cryptography          3.0
decorator             4.4.2
execnet               1.7.1
flake8                3.8.3
idna                  2.10
importlib-metadata    1.7.0
iniconfig             1.0.0
ipdb                  0.13.3
ipython               7.16.1
ipython-genutils      0.2.0
jedi                  0.17.2
mccabe                0.6.1
more-itertools        8.4.0
nose                  1.3.7
packaging             20.4
parameterized         0.7.4
parso                 0.7.1
pdfminer.six          20200726
pexpect               4.8.0
pickleshare           0.7.5
pip                   20.1.1
pluggy                0.13.1
pprintpp              0.4.0
prompt-toolkit        3.0.5
ptyprocess            0.6.0
py                    1.9.0
pycodestyle           2.6.0
pycparser             2.20
pyflakes              2.2.0
Pygments              2.6.1
PyMySQL               0.10.0
pyOpenSSL             19.1.0
pyotp                 2.3.0
pyparsing             2.4.7
pytest                6.0.0
pytest-cov            2.10.0
pytest-forked         1.3.0
pytest-html           2.0.1
pytest-metadata       1.10.0
pytest-ordering       0.6
pytest-rerunfailures  9.0
pytest-xdist          1.34.0
requests              2.24.0
rich                  4.2.0
selenium              3.141.0
setuptools            49.2.0
setuptools-scm        4.1.2
six                   1.15.0
sortedcontainers      2.2.2
soupsieve             2.0.1
toml                  0.10.1
traitlets             4.3.3
typing-extensions     3.7.4.2
urllib3               1.25.10
wcwidth               0.2.5
wheel                 0.34.2
zipp                  3.1.0

CC @nicoddemus

reporting regression

Most helpful comment

PR up: https://github.com/pytest-dev/pytest/pull/7561

Thanks again for the report and easy reproducer. 👍

All 7 comments

Can you please show the full traceback?

@The-Compiler

pytest skip_test.py --html=report.html
============================= test session starts ==============================
platform darwin -- Python 3.7.0, pytest-6.0.0, py-1.9.0, pluggy-0.13.1
rootdir: /Users/michael/github/SeleniumBase, configfile: pytest.ini
plugins: html-2.0.1, rerunfailures-9.0, metadata-1.10.0, cov-2.10.0, xdist-1.34.0, ordering-0.6, allure-pytest-2.8.17, forked-1.3.0
collected 1 item                                                               

skip_test.py s
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/main.py", line 240, in wrap_session
INTERNALERROR>     session.exitstatus = doit(config, session) or 0
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/main.py", line 296, in _main
INTERNALERROR>     config.hook.pytest_runtestloop(session=session)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR>     return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/manager.py", line 87, in <lambda>
INTERNALERROR>     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/main.py", line 321, in pytest_runtestloop
INTERNALERROR>     item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR>     return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/manager.py", line 87, in <lambda>
INTERNALERROR>     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/runner.py", line 100, in pytest_runtest_protocol
INTERNALERROR>     runtestprotocol(item, nextitem=nextitem)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/runner.py", line 117, in runtestprotocol
INTERNALERROR>     reports.append(call_and_report(item, "call", log))
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/runner.py", line 211, in call_and_report
INTERNALERROR>     hook.pytest_runtest_logreport(report=report)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR>     return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/manager.py", line 87, in <lambda>
INTERNALERROR>     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pytest_html/plugin.py", line 536, in pytest_runtest_logreport
INTERNALERROR>     self.append_skipped(report)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pytest_html/plugin.py", line 320, in append_skipped
INTERNALERROR>     self._appendrow("Skipped", report)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pytest_html/plugin.py", line 280, in _appendrow
INTERNALERROR>     result = self.TestResult(outcome, report, self.logfile, self.config)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pytest_html/plugin.py", line 124, in __init__
INTERNALERROR>     self.append_log_html(report, self.additional_html)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/pytest_html/plugin.py", line 252, in append_log_html
INTERNALERROR>     for line in report.longreprtext.splitlines():
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/reports.py", line 105, in longreprtext
INTERNALERROR>     self.toterminal(tw)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/reports.py", line 85, in toterminal
INTERNALERROR>     out.line(longrepr)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/_io/terminalwriter.py", line 168, in line
INTERNALERROR>     self.write(s, **markup)
INTERNALERROR>   File "/Users/michael/.virtualenvs/myvenv/lib/python3.7/site-packages/_pytest/_io/terminalwriter.py", line 144, in write
INTERNALERROR>     current_line = msg.rsplit("\n", 1)[-1]
INTERNALERROR> AttributeError: 'tuple' object has no attribute 'rsplit'

============================== 1 skipped in 0.03s ==============================

I'm facing the same issue:

If there are skipped tests, I get the errors below.
If there are no skipped tests, none of my logger.info messages are printed to terminal.

Running command:
python -m pytest -s -v -rs --junitxml=reports/results.xml --html=reports/report.html tests/sabre_pool/get_and_release_session_test.py

```=================================================== test session starts ====================================================
platform darwin -- Python 3.7.3, pytest-6.0.0, py-1.9.0, pluggy-0.13.1 -- /Users/william/git-repos/ws-testing-api/venv/bin/python
cachedir: .pytest_cache
metadata: {'Python': '3.7.3', 'Platform': 'Darwin-19.6.0-x86_64-i386-64bit', 'Packages': {'pytest': '6.0.0', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'metadata': '1.10.0', 'html': '2.1.1'}, 'JAVA_HOME': '/Users/william/.jenv/versions/oracle64-1.8.0.181'}
rootdir: /Users/william/git-repos/ws-testing-api, configfile: pytest.ini
plugins: metadata-1.10.0, html-2.1.1
collected 15 items

tests/sabre_pool/get_and_release_session_test.py::test_eval[AZ-4] SKIPPED
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/main.py", line 240, in wrap_session
INTERNALERROR> session.exitstatus = doit(config, session) or 0
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/main.py", line 296, in _main
INTERNALERROR> config.hook.pytest_runtestloop(session=session)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/manager.py", line 87, in
INTERNALERROR> firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR> res = hook_impl.function(args)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/main.py", line 321, in pytest_runtestloop
INTERNALERROR> item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/manager.py", line 87, in
INTERNALERROR> firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR> res = hook_impl.function(
args)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/runner.py", line 100, in pytest_runtest_protocol
INTERNALERROR> runtestprotocol(item, nextitem=nextitem)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/runner.py", line 117, in runtestprotocol
INTERNALERROR> reports.append(call_and_report(item, "call", log))
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/runner.py", line 211, in call_and_report
INTERNALERROR> hook.pytest_runtest_logreport(report=report)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/manager.py", line 87, in
INTERNALERROR> firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR> res = hook_impl.function(args)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pytest_html/plugin.py", line 602, in pytest_runtest_logreport
INTERNALERROR> self.append_skipped(report)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pytest_html/plugin.py", line 380, in append_skipped
INTERNALERROR> self._appendrow("Skipped", report)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pytest_html/plugin.py", line 340, in _appendrow
INTERNALERROR> result = self.TestResult(outcome, report, self.logfile, self.config)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pytest_html/plugin.py", line 157, in __init__
INTERNALERROR> self.append_log_html(report, self.additional_html)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/pytest_html/plugin.py", line 266, in append_log_html
INTERNALERROR> for line in report.longreprtext.splitlines():
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/reports.py", line 105, in longreprtext
INTERNALERROR> self.toterminal(tw)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/reports.py", line 85, in toterminal
INTERNALERROR> out.line(longrepr)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/_io/terminalwriter.py", line 168, in line
INTERNALERROR> self.write(s, *
markup)
INTERNALERROR> File "/Users/william/git-repos/ws-testing-api/venv/lib/python3.7/site-packages/_pytest/_io/terminalwriter.py", line 144, in write
INTERNALERROR> current_line = msg.rsplit("\n", 1)[-1]
INTERNALERROR> AttributeError: 'tuple' object has no attribute 'rsplit'

==================================================== 1 skipped in 0.32s ====================================================```

Thanks folks for the report!

I tracked down the issue:

On 5.x we use TerminalWriter from py, with this implementation of the write method:

    def write(self, msg, **kw):
        if msg:
            if not isinstance(msg, (bytes, text)):
                msg = text(msg)

We vendored TerminalWriter into pytest 6, and removed that if not isinstance(msg, (bytes, text)): check which was intended to support bytes:

https://github.com/pytest-dev/pytest/blob/38029828d1d6bdc15b63a873142b1e91265e1a1c/src/_pytest/_io/terminalwriter.py#L142-L144

What's happening is that msg in this case is a tuple, which in 5.x is converted to str by that text(msg) call, which is no longer done in pytest 6.

This diff restores the previous behavior:

diff --git a/src/_pytest/reports.py b/src/_pytest/reports.py
index 186c53ed3..fcac039c9 100644
--- a/src/_pytest/reports.py
+++ b/src/_pytest/reports.py
@@ -82,7 +82,7 @@ class BaseReport:
             longrepr.toterminal(out)
         else:
             try:
-                out.line(longrepr)
+                out.line(str(longrepr))
             except UnicodeEncodeError:
                 out.line("<unprintable longrepr>")

IMHO write is correct in not supporting anything and convert it implicitly to str(), but we need to then convert things explicitly on those places which are not actual text but can be anything (which is unfortunately the case for TestReport.longrepr).

I suspect this wasn't caught by our suite because longreprtext is not used much.

I won't be able to tackle this today, but I'm leaving this here for now in case others want to pick it up.

Working on it, PR coming up.

PR up: https://github.com/pytest-dev/pytest/pull/7561

Thanks again for the report and easy reproducer. 👍

Thank you for releasing pytest 6.0.1 with the fix to this issue! ✅ 🚀
I set SeleniumBase v1.45.0 to use pytest==6.0.1, and now everything works.
(https://github.com/seleniumbase/SeleniumBase/releases/tag/v1.45.0)
Thank you @nicoddemus and the rest of the pytest team!

Was this page helpful?
0 / 5 - 0 ratings