pytest_tap-3.5/ 0000775 0001750 0001750 00000000000 15031433622 014134 5 ustar debalance debalance pytest_tap-3.5/pytest_tap/ 0000775 0001750 0001750 00000000000 15031433622 016330 5 ustar debalance debalance pytest_tap-3.5/pytest_tap/plugin.py 0000644 0001750 0001750 00000016555 13615410400 020205 0 ustar debalance debalance import argparse
import sys
import pytest
from tap.formatter import format_as_diagnostics
from tap.tracker import Tracker
SHOW_CAPTURE_LOG = ("log", "all")
SHOW_CAPTURE_OUT = ("stdout", "all")
SHOW_CAPTUER_ERR = ("stderr", "all")
class TAPPlugin:
def __init__(self, config: pytest.Config) -> None:
self._tracker = Tracker(
outdir=config.option.tap_outdir,
combined=config.option.tap_combined,
streaming=config.option.tap_stream,
stream=sys.stdout,
)
if self._tracker.streaming:
reporter = config.pluginmanager.getplugin("terminalreporter")
if reporter:
config.pluginmanager.unregister(reporter)
# A common pytest pattern is to use test functions without classes.
# The header looks really dumb for that pattern because it puts
# out a lot of line noise since every function gets its own header.
# Disable it automatically for streaming.
self._tracker.header = False
self.show_capture = config.option.showcapture
self.log_passing_tests = config.option.tap_log_passing_tests
@pytest.hookimpl()
def pytest_runtestloop(self, session):
"""Output the plan line first."""
option = session.config.option
if option.tap_stream or option.tap_combined:
self._tracker.set_plan(session.testscollected)
@pytest.hookimpl(optionalhook=True)
def pytest_xdist_node_collection_finished(self, node, ids):
"""Output the plan line first when using xdist."""
if self._tracker.streaming or self._tracker.combined:
self._tracker.set_plan(len(ids))
@pytest.hookimpl()
def pytest_runtest_logreport(self, report: pytest.TestReport):
"""Add a test result to the tracker."""
is_trackable_result = (
(report.when == "setup" and report.outcome == "skipped")
or (report.when == "setup" and report.outcome == "failed")
or report.when == "call"
)
if not is_trackable_result:
return
description = str(report.location[0]) + "::" + str(report.location[2])
testcase = report.location[0]
# Handle xfails first because they report in unusual ways.
# Non-strict xfails will include `wasxfail` while strict xfails won't.
if hasattr(report, "wasxfail"):
reason = ""
# pytest adds an ugly "reason: " for expectedFailure
# even though the standard library doesn't accept a reason
# for that decorator.
# Ignore the "reason: " from pytest.
if report.wasxfail and report.wasxfail != "reason: ":
reason = f": {report.wasxfail}"
if report.skipped:
directive = f"TODO expected failure{reason}"
self._tracker.add_not_ok(testcase, description, directive=directive)
elif report.passed:
directive = f"TODO unexpected success{reason}"
self._tracker.add_ok(testcase, description, directive=directive)
elif report.passed:
diagnostics = None
if self.log_passing_tests:
diagnostics = _make_as_diagnostics(report, self.show_capture)
self._tracker.add_ok(testcase, description, diagnostics=diagnostics)
elif report.failed:
diagnostics = _make_as_diagnostics(report, self.show_capture)
# pytest treats an unexpected success from unitest.expectedFailure
# as a failure.
# To match up with TAPTestResult and the TAP spec, treat the pass
# as an ok with a todo directive instead.
if "Unexpected success" in str(report.longrepr):
self._tracker.add_ok(
testcase, description, directive="TODO unexpected success"
)
return
# A strict xfail that passes (i.e., XPASS) should be marked as a failure.
# The only indicator that strict xfail occurred
# for XPASS is to check longrepr.
if (
isinstance(report.longrepr, str)
and "[XPASS(strict)]" in report.longrepr
):
self._tracker.add_not_ok(
testcase,
description,
directive=f"unexpected success: {report.longrepr}",
)
return
self._tracker.add_not_ok(testcase, description, diagnostics=diagnostics)
elif report.skipped:
reason = report.longrepr[2].split(":", 1)[1].strip() # type: ignore
self._tracker.add_skip(testcase, description, reason)
@pytest.hookimpl()
def pytest_unconfigure(self, config: pytest.Config):
"""Dump the results."""
self._tracker.generate_tap_reports()
def pytest_addoption(parser):
"""Include all the command line options."""
group = parser.getgroup("terminal reporting", "reporting", after="general")
group.addoption(
"--tap",
default=False,
dest="tap_stream",
action="store_true",
help="Stream TAP output instead of the default test runner output.",
)
# Deprecated, but keeping for backwards compatibility.
group.addoption(
"--tap-stream", default=False, action="store_true", help=argparse.SUPPRESS
)
group.addoption(
"--tap-files",
default=False,
action="store_true",
help="Store all TAP test results into individual files per test case.",
)
group.addoption(
"--tap-combined",
default=False,
action="store_true",
help="Store all TAP test results into a combined output file.",
)
group.addoption(
"--tap-outdir",
metavar="path",
help=(
"An optional output directory to write TAP files to. "
"If the directory does not exist, it will be created."
),
)
group.addoption(
"--tap-log-passing-tests",
default=False,
action="store_true",
help="Capture log information for passing tests to TAP report",
)
@pytest.hookimpl(trylast=True)
def pytest_configure(config: pytest.Config) -> None:
"""Enable the plugin if the TAP flags are used."""
# The help printing uses the terminalreporter,
# which is unregistered by the streaming mode.
if config.option.help:
return
if (
config.option.tap_stream
or config.option.tap_combined
or config.option.tap_files
):
config.pluginmanager.register(TAPPlugin(config), "tapplugin")
def _make_as_diagnostics(report, show_capture):
"""Format a report as TAP diagnostic output."""
lines = report.longreprtext.splitlines(keepends=True)
if show_capture in SHOW_CAPTURE_LOG:
if lines:
lines[-1] += "\n"
lines += ["--- Captured Log ---\n"] + (
report.caplog.splitlines(keepends=True) or [""]
)
if show_capture in SHOW_CAPTURE_OUT:
if lines:
lines[-1] += "\n"
lines += ["--- Captured Out ---\n"] + (
report.capstdout.splitlines(keepends=True) or [""]
)
if show_capture in SHOW_CAPTUER_ERR:
if lines:
lines[-1] += "\n"
lines += ["--- Captured Err ---\n"] + (
report.capstderr.splitlines(keepends=True) or [""]
)
return format_as_diagnostics(lines)
pytest_tap-3.5/pytest_tap/__init__.py 0000644 0001750 0001750 00000000024 13615410400 020426 0 ustar debalance debalance __version__ = "3.5"
pytest_tap-3.5/docs/ 0000775 0001750 0001750 00000000000 15031433622 015064 5 ustar debalance debalance pytest_tap-3.5/docs/releases.rst 0000644 0001750 0001750 00000007114 13615410400 017415 0 ustar debalance debalance pytest-tap is a reporting plugin for pytest that outputs
`Test Anything Protocol (TAP) `_ data.
TAP is a line based test protocol for recording test data in a standard way.
Use ``pytest --tap`` after installing to get started.
Follow `GitHub `_
for more information or to follow this plugin's development.
Additional developer documentation about Python and TAP is on
`Read the Docs `_.
Releases
========
Version 3.5, January 30, 2025
-----------------------------
* Diagnostics now output logs, stdout, stderr for failed tests.
Use the standard ``--show-capture`` flag to control the output.
* Diagnostics can display for passing tests using the
``--tap-log-passing-tests`` flag.
* Add support for Python 3.12.
* Add support for Python 3.13.
* Drop support for Python 3.8 (it is end-of-life).
Version 3.4, July 15, 2023
--------------------------
* Deprecate ``--tap-stream`` in favor of ``--tap`` for streaming mode.
* When using xdist, report the plan at the beginning of execution.
* Add support for Python 3.11.
* Drop support for Python 3.7 (it is end-of-life).
* Drop support for Python 3.6 (it is end-of-life).
* Drop support for PyPy.
Version 3.3, October 27, 2021
-----------------------------
* Add support for Python 3.10.
* Fix bug with help printing when streaming mode is enabled (#59).
* Drop support for Python 3.5 (it is end-of-life).
* Remove unmaintained (and likely inaccurate) locale info.
Version 3.2, November 7, 2020
-----------------------------
* Add support for Python 3.8.
* Add support for Python 3.9.
* Handle ``unittest.expectedFailure`` and ``pytest.xfail``
in a way that is more consistent
with the TAP specification.
Version 3.1, Released March 25, 2020
------------------------------------
* Fix reporting that was broken by the removal
of a deprecated feature in pytest 5.4.
Version 3.0, Released January 28, 2020
--------------------------------------
* Drop support for Python 2.
Version 2.5, Released December 26, 2019
---------------------------------------
* Last supported version for Python 2.
* Pin tap.py to a version range that supports Python 2.
Version 2.4, Released October 21, 2019
--------------------------------------
* Handle failures that occur from setup.
This will catch errors that may happen in fixtures.
* Drop support for Python 3.4 (it is end-of-life).
* Add support for Python 3.7.
Version 2.3, Released September 16, 2018
----------------------------------------
* Improve xfail handling.
Honor strict xfail mode.
Use TODO instead of SKIP directive to better align with TAP specification.
* Output the plan line (``1..N``) first.
Version 2.2, Released January 9, 2018
-------------------------------------
* Update output format to match closer to pytest styling.
* Drop support for Python 3.3 (it is end-of-life).
Version 2.1, Released August 12, 2017
-------------------------------------
* Add support for Python 3.6.
* Fix crash when running with pytest-xdist (#27).
Version 2.0, Released August 1, 2016
------------------------------------
* Update to tap.py 2.0.
This update drops the indirect dependencies on nose and pygments.
* Improve handling of skips and xfails.
* Suppress ``# TAP results for TestCase`` for streaming.
This header makes little sense for pytest's test function paradigm.
Including the header generated extra noise for each function.
* Drop support for Python 2.6
Version 1.9, Released June 11, 2016
-----------------------------------
* Initial release as stand-alone plugin.
The version number aligns with tappy.
pytest_tap-3.5/LICENSE 0000644 0001750 0001750 00000002476 13615410400 015143 0 ustar debalance debalance Copyright (c) 2021, Matt Layman and contributors. See AUTHORS for more details.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pytest_tap-3.5/AUTHORS 0000644 0001750 0001750 00000000417 13615410400 015177 0 ustar debalance debalance pytest-tap was originally created by Matt Layman.
Contributors
------------
* Allison Karlitskaya
* Cody D'Ambrosio
* Dan Dofter
* Erik Cederstrand
* Frédéric Mangano-Tarumi
* Greg Sadetsky
* Matt Layman
* Måns Ansgariusson - ARM Sweden
* meejah (https://meejah.ca)
pytest_tap-3.5/pyproject.toml 0000644 0001750 0001750 00000003267 13615410400 017051 0 ustar debalance debalance [project]
name = "pytest-tap"
version = "3.5"
description = "Test Anything Protocol (TAP) reporting plugin for pytest"
readme = "docs/releases.rst"
authors = [
{ name = "Matt Layman", email = "matthewlayman@gmail.com" }
]
license = { text = "BSD" }
homepage = "https://github.com/python-tap/pytest-tap"
dependencies = [
"pytest>=3.0",
"tap.py>=3.2,<4.0"
]
requires-python = ">=3.9"
keywords = ["TAP", "unittest", "pytest"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Framework :: Pytest",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Testing"
]
[project.entry-points.pytest11]
tap = "pytest_tap.plugin"
[dependency-groups]
dev = [
"pytest-tap",
"tox>=4.24.1",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.sdist]
include = [
"/src",
"/docs",
"/tests",
]
sources = ["src"]
[tool.hatch.build.targets.wheel]
sources = ["src"]
packages = ["pytest_tap"]
[tool.pytest.ini_options]
pythonpath = [".", "src"]
[tool.uv.sources]
pytest-tap = { workspace = true }
[tool.ruff.lint]
select = [
# pycodestyle
"E",
"W",
# Pyflakes
"F",
# pyupgrade
"UP",
# flake8-bandit
"S",
# flake8-bugbear
"B",
# flake8-simplify
"SIM",
# isort
"I",
]
ignore = [
# bandit: Use of `assert` detected
"S101",
]
pytest_tap-3.5/tests/ 0000775 0001750 0001750 00000000000 15031433622 015276 5 ustar debalance debalance pytest_tap-3.5/tests/test_plugin.py 0000644 0001750 0001750 00000016526 13615410400 020210 0 ustar debalance debalance from tap.tracker import ENABLE_VERSION_13
def test_stream(testdir, sample_test_file):
"""Results are streamed to stdout."""
result = testdir.runpytest_subprocess("--tap-stream")
result.stdout.fnmatch_lines(
[
"1..6",
"ok 1 test_stream.py::test_ok",
"not ok 2 test_stream.py::test_not_ok",
"ok 3 test_stream.py::test_params[foo]",
"ok 4 test_stream.py::test_params[bar]",
"ok 5 test_stream.py::test_skipped # SKIP some reason",
"not ok 6 test_stream.py::test_broken # TODO expected failure: a reason",
]
)
def test_stream_simple_flag(testdir, sample_test_file):
"""Results are streamed to stdout when the shorter streaming flag."""
result = testdir.runpytest_subprocess("--tap")
result.stdout.fnmatch_lines(
[
"1..6",
"ok 1 test_stream_simple_flag.py::test_ok",
"not ok 2 test_stream_simple_flag.py::test_not_ok",
"ok 3 test_stream_simple_flag.py::test_params[foo]",
"ok 4 test_stream_simple_flag.py::test_params[bar]",
"ok 5 test_stream_simple_flag.py::test_skipped # SKIP some reason",
"not ok 6 test_stream_simple_flag.py::test_broken "
"# TODO expected failure: a reason",
]
)
def test_combined(testdir, sample_test_file):
"""Tests are combined into a single output file."""
testdir.runpytest_subprocess("--tap-combined")
testresults = testdir.tmpdir.join("testresults.tap")
assert testresults.check()
actual_results = [
line.strip() for line in testresults.readlines() if not line.startswith("#")
]
expected_results = [
"1..6",
"ok 1 test_combined.py::test_ok",
"not ok 2 test_combined.py::test_not_ok",
"ok 3 test_combined.py::test_params[foo]",
"ok 4 test_combined.py::test_params[bar]",
"ok 5 test_combined.py::test_skipped # SKIP some reason",
"not ok 6 test_combined.py::test_broken # TODO expected failure: a reason",
]
# If the dependencies for version 13 happen to be installed, tweak the output.
if ENABLE_VERSION_13:
expected_results.insert(0, "TAP version 13")
assert actual_results == expected_results
def test_files(testdir, sample_test_file):
"""Tests are split into separate files."""
testdir.makepyfile(
test_other_file="""
def test_other_ok():
assert True
"""
)
testdir.runpytest_subprocess("--tap-files")
sample_tap = testdir.tmpdir.join("test_files.py.tap")
assert sample_tap.check()
other_tap = testdir.tmpdir.join("test_other_file.py.tap")
assert other_tap.check()
def test_outdir(testdir, sample_test_file):
"""Tests are put in the output directory."""
testdir.runpytest_subprocess("--tap-outdir", "results", "--tap-combined")
outdir = testdir.tmpdir.join("results")
testresults = outdir.join("testresults.tap")
assert testresults.check()
def test_logging(testdir, sample_test_file):
"""Test logs are added to TAP diagnostics."""
result = testdir.runpytest_subprocess("--tap")
result.stdout.fnmatch_lines(
[
"# --- Captured Log ---",
"*Running test_not_ok*",
"# --- Captured Out ---",
"# --- Captured Err ---",
]
)
result.stdout.no_fnmatch_line("*Running test_ok*")
def test_log_passing_tests(testdir, sample_test_file):
"""Test logs are added to TAP diagnostics."""
result = testdir.runpytest_subprocess(
"--tap", "--tap-log-passing-tests", "--log-level", "INFO"
)
result.stdout.fnmatch_lines(
[
"# --- Captured Log ---",
"*Running test_ok*",
]
)
result.stdout.no_fnmatch_line("*Debug logging info*")
def test_xfail_no_reason(testdir):
"""xfails output gracefully when no reason is provided."""
testdir.makepyfile(
"""
import pytest
@pytest.mark.xfail(strict=False)
def test_unexpected_success():
assert True
@pytest.mark.xfail(strict=False)
def test_expected_failure():
assert False
"""
)
result = testdir.runpytest_subprocess("--tap")
result.stdout.fnmatch_lines(
[
"ok 1 test_xfail_no_reason.py::test_unexpected_success "
"# TODO unexpected success",
"not ok 2 test_xfail_no_reason.py::test_expected_failure "
"# TODO expected failure",
]
)
def test_xfail_nonstrict(testdir):
"""Non-strict xfails are treated as TODO directives."""
testdir.makepyfile(
"""
import pytest
@pytest.mark.xfail(strict=False, reason='a reason')
def test_unexpected_success():
assert True
@pytest.mark.xfail(strict=False, reason='a reason')
def test_expected_failure():
assert False
"""
)
result = testdir.runpytest_subprocess("--tap")
result.stdout.fnmatch_lines(
[
"ok 1 test_xfail_nonstrict.py::test_unexpected_success "
"# TODO unexpected success: a reason",
"not ok 2 test_xfail_nonstrict.py::test_expected_failure "
"# TODO expected failure: a reason",
]
)
def test_xfail_strict(testdir):
"""xfail strict mode handles expected behavior."""
testdir.makepyfile(
"""
import pytest
@pytest.mark.xfail(strict=True, reason='a reason')
def test_unexpected_success():
assert True
@pytest.mark.xfail(strict=True, reason='a reason')
def test_expected_failure():
assert False
"""
)
result = testdir.runpytest_subprocess("--tap")
result.stdout.fnmatch_lines(
[
"not ok 1 test_xfail_strict.py::test_unexpected_success "
"# unexpected success: [XPASS(strict)] a reason",
"not ok 2 test_xfail_strict.py::test_expected_failure "
"# TODO expected failure: a reason",
]
)
def test_unittest_expected_failure(testdir):
"""The plugin handles unittest's expectedFailure decorator behavior."""
testdir.makepyfile(
"""
import pytest
import unittest
class TestExpectedFailure(unittest.TestCase):
@unittest.expectedFailure
def test_when_failing(self):
assert False
@unittest.expectedFailure
def test_when_passing(self):
assert True
"""
)
result = testdir.runpytest_subprocess("--tap")
expected = [
"not ok 1 test_unittest_expected_failure.py::"
"TestExpectedFailure.test_when_failing # TODO expected failure",
"ok 2 test_unittest_expected_failure.py::"
"TestExpectedFailure.test_when_passing # TODO unexpected success",
]
result.stdout.fnmatch_lines(expected)
def test_setup_failure(testdir):
"""A failure in test setup is marked as an error.
See https://github.com/python-tap/pytest-tap/issues/39.
"""
testdir.makepyfile(
"""
import pytest
@pytest.fixture
def bad_fixture():
raise Exception('boom')
def test_with_bad_fixture(bad_fixture):
assert True
"""
)
result = testdir.runpytest_subprocess("--tap")
result.stdout.fnmatch_lines(
["1..1", "not ok 1 test_setup_failure.py::test_with_bad_fixture"]
)
pytest_tap-3.5/tests/test_xdist.py 0000644 0001750 0001750 00000001470 13615410400 020035 0 ustar debalance debalance """The xdist plugin isn't installed so these tests check against the hook contract."""
from unittest import mock
import pytest
from pytest_tap.plugin import TAPPlugin
@pytest.mark.parametrize(
"combined, stream, expected",
[
(False, True, True),
(True, False, True),
(False, False, False),
],
)
def test_sets_plan_streaming(combined, stream, expected):
"""The plan is set for the given mode conditions by a node's collection report."""
config = mock.Mock()
config.option.tap_outdir = "."
config.option.tap_combined = combined
config.option.tap_stream = stream
plugin = TAPPlugin(config)
node = mock.Mock()
test_ids = ["a", "b", "c"]
plugin.pytest_xdist_node_collection_finished(node, test_ids)
assert (plugin._tracker.plan == 3) is expected
pytest_tap-3.5/tests/__init__.py 0000644 0001750 0001750 00000000000 13615410400 017366 0 ustar debalance debalance pytest_tap-3.5/tests/test_help.py 0000644 0001750 0001750 00000001305 13615410400 017627 0 ustar debalance debalance def test_includes_options(testdir):
"""All options are present in the help."""
result = testdir.runpytest("--help")
expected_option_flags = [
"*--tap *",
"*--tap-files*",
"*--tap-combined*",
"*--tap-outdir=path*",
"*--tap-log-passing-tests*",
]
result.stdout.fnmatch_lines(expected_option_flags)
def test_handle_help_with_stream(testdir):
"""The help prints when the stream option is given.
This demonstrates behavior reported in:
https://github.com/python-tap/pytest-tap/issues/59
"""
result = testdir.runpytest("--tap", "-h")
expected_option_flags = ["*--tap *"]
result.stdout.fnmatch_lines(expected_option_flags)
pytest_tap-3.5/PKG-INFO 0000644 0001750 0001750 00000010736 13615410400 015231 0 ustar debalance debalance Metadata-Version: 2.4
Name: pytest-tap
Version: 3.5
Summary: Test Anything Protocol (TAP) reporting plugin for pytest
Author-email: Matt Layman
License: BSD
License-File: AUTHORS
License-File: LICENSE
Keywords: TAP,pytest,unittest
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Pytest
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.9
Requires-Dist: pytest>=3.0
Requires-Dist: tap-py<4.0,>=3.2
Description-Content-Type: text/x-rst
pytest-tap is a reporting plugin for pytest that outputs
`Test Anything Protocol (TAP) `_ data.
TAP is a line based test protocol for recording test data in a standard way.
Use ``pytest --tap`` after installing to get started.
Follow `GitHub `_
for more information or to follow this plugin's development.
Additional developer documentation about Python and TAP is on
`Read the Docs `_.
Releases
========
Version 3.5, January 30, 2025
-----------------------------
* Diagnostics now output logs, stdout, stderr for failed tests.
Use the standard ``--show-capture`` flag to control the output.
* Diagnostics can display for passing tests using the
``--tap-log-passing-tests`` flag.
* Add support for Python 3.12.
* Add support for Python 3.13.
* Drop support for Python 3.8 (it is end-of-life).
Version 3.4, July 15, 2023
--------------------------
* Deprecate ``--tap-stream`` in favor of ``--tap`` for streaming mode.
* When using xdist, report the plan at the beginning of execution.
* Add support for Python 3.11.
* Drop support for Python 3.7 (it is end-of-life).
* Drop support for Python 3.6 (it is end-of-life).
* Drop support for PyPy.
Version 3.3, October 27, 2021
-----------------------------
* Add support for Python 3.10.
* Fix bug with help printing when streaming mode is enabled (#59).
* Drop support for Python 3.5 (it is end-of-life).
* Remove unmaintained (and likely inaccurate) locale info.
Version 3.2, November 7, 2020
-----------------------------
* Add support for Python 3.8.
* Add support for Python 3.9.
* Handle ``unittest.expectedFailure`` and ``pytest.xfail``
in a way that is more consistent
with the TAP specification.
Version 3.1, Released March 25, 2020
------------------------------------
* Fix reporting that was broken by the removal
of a deprecated feature in pytest 5.4.
Version 3.0, Released January 28, 2020
--------------------------------------
* Drop support for Python 2.
Version 2.5, Released December 26, 2019
---------------------------------------
* Last supported version for Python 2.
* Pin tap.py to a version range that supports Python 2.
Version 2.4, Released October 21, 2019
--------------------------------------
* Handle failures that occur from setup.
This will catch errors that may happen in fixtures.
* Drop support for Python 3.4 (it is end-of-life).
* Add support for Python 3.7.
Version 2.3, Released September 16, 2018
----------------------------------------
* Improve xfail handling.
Honor strict xfail mode.
Use TODO instead of SKIP directive to better align with TAP specification.
* Output the plan line (``1..N``) first.
Version 2.2, Released January 9, 2018
-------------------------------------
* Update output format to match closer to pytest styling.
* Drop support for Python 3.3 (it is end-of-life).
Version 2.1, Released August 12, 2017
-------------------------------------
* Add support for Python 3.6.
* Fix crash when running with pytest-xdist (#27).
Version 2.0, Released August 1, 2016
------------------------------------
* Update to tap.py 2.0.
This update drops the indirect dependencies on nose and pygments.
* Improve handling of skips and xfails.
* Suppress ``# TAP results for TestCase`` for streaming.
This header makes little sense for pytest's test function paradigm.
Including the header generated extra noise for each function.
* Drop support for Python 2.6
Version 1.9, Released June 11, 2016
-----------------------------------
* Initial release as stand-alone plugin.
The version number aligns with tappy.