pytest_tap-3.5/0000775000175000017500000000000015031433622014134 5ustar debalancedebalancepytest_tap-3.5/pytest_tap/0000775000175000017500000000000015031433622016330 5ustar debalancedebalancepytest_tap-3.5/pytest_tap/plugin.py0000644000175000017500000001655513615410400020205 0ustar debalancedebalanceimport 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__.py0000644000175000017500000000002413615410400020426 0ustar debalancedebalance__version__ = "3.5" pytest_tap-3.5/docs/0000775000175000017500000000000015031433622015064 5ustar debalancedebalancepytest_tap-3.5/docs/releases.rst0000644000175000017500000000711413615410400017415 0ustar debalancedebalancepytest-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/LICENSE0000644000175000017500000000247613615410400015143 0ustar debalancedebalanceCopyright (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/AUTHORS0000644000175000017500000000041713615410400015177 0ustar debalancedebalancepytest-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.toml0000644000175000017500000000326713615410400017051 0ustar debalancedebalance[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/0000775000175000017500000000000015031433622015276 5ustar debalancedebalancepytest_tap-3.5/tests/test_plugin.py0000644000175000017500000001652613615410400020210 0ustar debalancedebalancefrom 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.py0000644000175000017500000000147013615410400020035 0ustar debalancedebalance"""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__.py0000644000175000017500000000000013615410400017366 0ustar debalancedebalancepytest_tap-3.5/tests/test_help.py0000644000175000017500000000130513615410400017627 0ustar debalancedebalancedef 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-INFO0000644000175000017500000001073613615410400015231 0ustar debalancedebalanceMetadata-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.