From eace37e1ee1887574a049c4a342381849e81df25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Wed, 2 Feb 2022 18:49:23 +0200 Subject: [PATCH 01/20] Add extra envs. --- tox.ini | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 20a1561b..99e1fff6 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ envlist = check py{36,37,py,py3}-pytest46-xdist127-coverage{55} py{36,37,38,py3}-pytest{46,54}-xdist133-coverage{55} - py{36,37,38,39,310,py3}-pytest{62}-xdist202-coverage{55} + py{36,37,38,39,310,py3}-pytest{62}-xdist250-coverage{55,60,61,62,63} docs [testenv] @@ -40,6 +40,7 @@ setenv = xdist200: _DEP_PYTESTXDIST=pytest-xdist==2.0.0 xdist201: _DEP_PYTESTXDIST=pytest-xdist==2.1.0 xdist202: _DEP_PYTESTXDIST=pytest-xdist==2.2.0 + xdist250: _DEP_PYTESTXDIST=pytest-xdist==2.5.0 xdistdev: _DEP_PYTESTXDIST=git+https://github.com/pytest-dev/pytest-xdist.git#egg=pytest-xdist coverage45: _DEP_COVERAGE=coverage==4.5.4 @@ -49,6 +50,10 @@ setenv = coverage53: _DEP_COVERAGE=coverage==5.3.1 coverage54: _DEP_COVERAGE=coverage==5.4 coverage55: _DEP_COVERAGE=coverage==5.5 + coverage60: _DEP_COVERAGE=coverage==6.0.2 + coverage61: _DEP_COVERAGE=coverage==6.1.2 + coverage62: _DEP_COVERAGE=coverage==6.2 + coverage63: _DEP_COVERAGE=coverage==6.3 # For testing against a coverage.py working tree. coveragedev: _DEP_COVERAGE=-e{env:COVERAGE_HOME} passenv = From a694f16c4212b58131061db15700db62f0ac4ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Wed, 2 Feb 2022 19:34:59 +0200 Subject: [PATCH 02/20] Skip this on newer xdist. --- tests/test_pytest_cov.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 6d979495..32804bc0 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -994,6 +994,8 @@ def test_invalid_coverage_source(testdir): @pytest.mark.skipif("'dev' in pytest.__version__") @pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"') +@pytest.mark.skipif('tuple(map(int, xdist.__version__.split("."))) >= (2, 3, 0)', + reason="Since pytest-xdist 2.3.0 the parent sys.path is copied in the child process") def test_dist_missing_data(testdir): """Test failure when using a worker without pytest-cov installed.""" venv_path = os.path.join(str(testdir.tmpdir), 'venv') From 5723c0e6114ae9d3ff65fbd1f0541d1b0b29607f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Wed, 2 Feb 2022 19:36:42 +0200 Subject: [PATCH 03/20] Parametrize the spawn method. --- tests/test_pytest_cov.py | 60 ++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 32804bc0..e94d59be 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -157,6 +157,15 @@ def test_foo(cov): pytest.param('-n 1', marks=pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"')) ], ids=['nodist', 'xdist']) +skipif_multiprocessing_is_broken = pytest.mark.skipif( + 'sys.version_info[:2] >= (3, 8)', + reason="deadlocks on Python 3.8+, see: https://bugs.python.org/issue38227" +) +method_params = pytest.mark.parametrize('method', [ + pytest.param('fork', marks=skipif_multiprocessing_is_broken), + pytest.param('spawn', marks=skipif_multiprocessing_is_broken), +]) + @pytest.fixture(scope='session', autouse=True) def adjust_sys_path(): @@ -1025,7 +1034,7 @@ def test_dist_missing_data(testdir): '--dist=load', '--tx=popen//python=%s' % exe, max_worker_restart_0, - script) + str(script)) result.stdout.fnmatch_lines([ 'The following workers failed to return coverage data, ensure that pytest-cov is installed on these workers.' ]) @@ -1062,18 +1071,19 @@ def test_funcarg_not_active(testdir): @pytest.mark.skipif("sys.version_info[0] < 3", reason="no context manager api on Python 2") @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") @pytest.mark.skipif('platform.python_implementation() == "PyPy"', reason="often deadlocks on PyPy") -@pytest.mark.skipif('sys.version_info[:2] >= (3, 8)', reason="deadlocks on Python 3.8+, see: https://bugs.python.org/issue38227") -def test_multiprocessing_pool(testdir): +@method_params +def test_multiprocessing_pool(testdir, method): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' import multiprocessing def target_fn(a): - %sse: # pragma: nocover + {}se: # pragma: nocover return None def test_run_target(): + multiprocessing.set_start_method({!r}) from pytest_cov.embed import cleanup_on_sigterm cleanup_on_sigterm() @@ -1081,9 +1091,9 @@ def test_run_target(): with multiprocessing.Pool(3) as p: p.map(target_fn, [i * 3 + j for j in range(3)]) p.join() -''' % ''.join('''if a == %r: +'''.format(''.join('''if a == %r: return a - el''' % i for i in range(99))) + el''' % i for i in range(99)), method)) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), @@ -1103,18 +1113,19 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") @pytest.mark.skipif('platform.python_implementation() == "PyPy"', reason="often deadlocks on PyPy") -@pytest.mark.skipif('sys.version_info[:2] >= (3, 8)', reason="deadlocks on Python 3.8, see: https://bugs.python.org/issue38227") -def test_multiprocessing_pool_terminate(testdir): +@method_params +def test_multiprocessing_pool_terminate(testdir, method): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' import multiprocessing def target_fn(a): - %sse: # pragma: nocover + {}se: # pragma: nocover return None def test_run_target(): + multiprocessing.set_start_method({!r}) from pytest_cov.embed import cleanup_on_sigterm cleanup_on_sigterm() @@ -1125,9 +1136,9 @@ def test_run_target(): finally: p.terminate() p.join() -''' % ''.join('''if a == %r: +'''.format(''.join('''if a == %r: return a - el''' % i for i in range(99))) + el''' % i for i in range(99)), method)) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), @@ -1147,17 +1158,19 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") @pytest.mark.skipif('sys.version_info[0] > 2 and platform.python_implementation() == "PyPy"', reason="broken on PyPy3") -def test_multiprocessing_pool_close(testdir): +@method_params +def test_multiprocessing_pool_close(testdir, method): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' import multiprocessing def target_fn(a): - %sse: # pragma: nocover + {}se: # pragma: nocover return None def test_run_target(): + multiprocessing.set_start_method({!r}) for i in range(33): p = multiprocessing.Pool(3) try: @@ -1165,9 +1178,9 @@ def test_run_target(): finally: p.close() p.join() -''' % ''.join('''if a == %r: +'''.format(''.join('''if a == %r: return a - el''' % i for i in range(99))) + el''' % i for i in range(99)), method)) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), @@ -1185,7 +1198,8 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -def test_multiprocessing_process(testdir): +@method_params +def test_multiprocessing_process(testdir, method): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' @@ -1196,10 +1210,11 @@ def target_fn(): return a def test_run_target(): + multiprocessing.set_start_method({!r}) p = multiprocessing.Process(target=target_fn) p.start() p.join() -''') +'''.format(method)) result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), @@ -1215,7 +1230,8 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -def test_multiprocessing_process_no_source(testdir): +@method_params +def test_multiprocessing_process_no_source(testdir, method): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' @@ -1245,7 +1261,8 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -def test_multiprocessing_process_with_terminate(testdir): +@method_params +def test_multiprocessing_process_with_terminate(testdir, method): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' @@ -1783,6 +1800,7 @@ def test_not_started_plugin_does_not_fail(testdir): class ns: cov_source = [True] cov_report = '' + plugin = pytest_cov.plugin.CovPlugin(ns, None, start=False) plugin.pytest_runtestloop(None) plugin.pytest_terminal_summary(None) @@ -1900,7 +1918,7 @@ def test_append_coverage(testdir, opts, prop): result = testdir.runpytest('-v', '--cov=%s' % script.dirpath(), script, - *opts.split()+prop.args) + *opts.split() + prop.args) result.stdout.fnmatch_lines([ 'test_1* %s*' % prop.result, ]) @@ -1909,7 +1927,7 @@ def test_append_coverage(testdir, opts, prop): '--cov-append', '--cov=%s' % script2.dirpath(), script2, - *opts.split()+prop.args) + *opts.split() + prop.args) result.stdout.fnmatch_lines([ 'test_1* %s*' % prop.result, 'test_2* %s*' % prop.result2, From 45d9fef0b41e358ee480e6e8980350a76c734e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Wed, 2 Feb 2022 19:45:01 +0200 Subject: [PATCH 04/20] Remove appveyor and update various skel things. --- .appveyor.yml | 46 -- .cookiecutterrc | 14 +- .github/workflows/test.yml | 864 ++++++++++++++++++++++-- MANIFEST.in | 9 +- README.rst | 3 +- ci/appveyor-with-compiler.cmd | 23 - ci/bootstrap.py | 34 +- ci/requirements.txt | 1 + ci/templates/.appveyor.yml | 53 -- ci/templates/.github/workflows/test.yml | 65 ++ setup.py | 5 + tox.ini | 1 - 12 files changed, 893 insertions(+), 225 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 ci/appveyor-with-compiler.cmd delete mode 100644 ci/templates/.appveyor.yml create mode 100644 ci/templates/.github/workflows/test.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 9f176ee5..00000000 --- a/.appveyor.yml +++ /dev/null @@ -1,46 +0,0 @@ -# NOTE: this file is auto-generated via ci/bootstrap.py (ci/templates/.appveyor.yml). -version: '{branch}-{build}' -build: off -image: - - Visual Studio 2015 - - Visual Studio 2019 -environment: - matrix: - - TOXENV: check - - TOXENV: 'py36-pytest46-xdist127-coverage55,py36-pytest46-xdist133-coverage55,py36-pytest54-xdist133-coverage55,py36-pytest62-xdist202-coverage55' - - TOXENV: 'py37-pytest46-xdist127-coverage55,py37-pytest46-xdist133-coverage55,py37-pytest54-xdist133-coverage55,py37-pytest62-xdist202-coverage55' - - TOXENV: 'py38-pytest46-xdist133-coverage55,py38-pytest54-xdist133-coverage55,py38-pytest62-xdist202-coverage55' - - TOXENV: 'py39-pytest62-xdist202-coverage55' - - TOXENV: 'pypy3-pytest46-xdist127-coverage55,pypy3-pytest46-xdist133-coverage55,pypy3-pytest54-xdist133-coverage55,pypy3-pytest62-xdist202-coverage55' -matrix: - exclude: - - image: Visual Studio 2015 - TOXENV: 'py36-pytest46-xdist127-coverage55,py36-pytest46-xdist133-coverage55,py36-pytest54-xdist133-coverage55,py36-pytest62-xdist202-coverage55' - - image: Visual Studio 2015 - TOXENV: 'py37-pytest46-xdist127-coverage55,py37-pytest46-xdist133-coverage55,py37-pytest54-xdist133-coverage55,py37-pytest62-xdist202-coverage55' - - image: Visual Studio 2015 - TOXENV: 'py38-pytest46-xdist133-coverage55,py38-pytest54-xdist133-coverage55,py38-pytest62-xdist202-coverage55' - - image: Visual Studio 2015 - TOXENV: 'py39-pytest62-xdist202-coverage55' - - image: Visual Studio 2015 - TOXENV: 'pypy3-pytest46-xdist127-coverage55,pypy3-pytest46-xdist133-coverage55,pypy3-pytest54-xdist133-coverage55,pypy3-pytest62-xdist202-coverage55' -init: - - ps: echo $env:TOXENV - - ps: ls C:\Python* -install: - - IF "%TOXENV:~0,6%" == "pypy3-" choco install --no-progress pypy3 - - SET PATH=C:\tools\pypy\pypy;%PATH% - - C:\Python37\python -m pip install --progress-bar=off tox -rci/requirements.txt - -test_script: - - cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd C:\Python37\python -m tox - -on_failure: - - ps: dir "env:" - - ps: get-content .tox\*\log\* -artifacts: - - path: dist\* - -### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker): -# on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/.cookiecutterrc b/.cookiecutterrc index 9cad1178..49e9880e 100644 --- a/.cookiecutterrc +++ b/.cookiecutterrc @@ -2,7 +2,7 @@ default_context: allow_tests_inside_package: no - appveyor: yes + appveyor: no c_extension_function: '-' c_extension_module: '-' c_extension_optional: no @@ -16,10 +16,10 @@ default_context: command_line_interface: no command_line_interface_bin_name: '-' coveralls: no - coveralls_token: '[Required for Appveyor, take it from https://coveralls.io/github/ionelmc/pytest-cov]' distribution_name: pytest-cov email: contact@ionelmc.ro full_name: Ionel Cristian Mărieș + github_actions: yes legacy_python: yes license: MIT license linter: flake8 @@ -29,9 +29,10 @@ default_context: project_short_description: This plugin produces coverage reports. It supports centralised testing and distributed testing in both load and each modes. It also supports coverage of subprocesses. pypi_badge: yes pypi_disable_upload: no - release_date: '2020-06-12' + release_date: '2021-10-04' repo_hosting: github.com repo_hosting_domain: github.com + repo_main_branch: master repo_name: pytest-cov repo_username: pytest-dev requiresio: yes @@ -45,9 +46,10 @@ default_context: test_matrix_configurator: no test_matrix_separate_coverage: no test_runner: pytest - travis: yes + travis: no travis_osx: no - version: 2.10.1 + version: 3.0.0 + version_manager: bump2version website: http://blog.ionelmc.ro year_from: '2010' - year_to: '2020' + year_to: '2022' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b9f7c11c..18299c41 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,81 +1,797 @@ -name: Test - -on: [push, pull_request, workflow_dispatch] - -env: - FORCE_COLOR: 1 - +name: build +on: [push, pull_request] jobs: test: - runs-on: ubuntu-latest + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + timeout-minutes: 30 strategy: fail-fast: false matrix: - python-version: ["pypy-3.6", "pypy-3.7", "3.6", "3.7", "3.8", "3.9", "3.10-dev"] - tox-extra-versions: [ - "pytest46-xdist127", - "pytest46-xdist133", - "pytest54-xdist133", - "pytest62-xdist202", - ] include: - # Add new helper variables to existing jobs - - {python-version: "pypy-3.6", tox-python-version: "pypy3"} - - {python-version: "pypy-3.7", tox-python-version: "pypy3"} - - {python-version: "3.6", tox-python-version: "py36"} - - {python-version: "3.7", tox-python-version: "py37"} - - {python-version: "3.8", tox-python-version: "py38"} - - {python-version: "3.9", tox-python-version: "py39"} - - {python-version: "3.10-dev", tox-python-version: "py310"} - exclude: - # Remove some jobs from the matrix - - {tox-extra-versions: "pytest46-xdist127", python-version: "3.8"} - - {tox-extra-versions: "pytest46-xdist127", python-version: "3.9"} - - {tox-extra-versions: "pytest46-xdist133", python-version: "3.9"} - - {tox-extra-versions: "pytest54-xdist133", python-version: "3.9"} - - {tox-extra-versions: "pytest46-xdist127", python-version: "3.10-dev"} - - {tox-extra-versions: "pytest46-xdist133", python-version: "3.10-dev"} - - {tox-extra-versions: "pytest54-xdist133", python-version: "3.10-dev"} - + - name: 'check' + python: '3.9' + toxpython: 'python3.9' + tox_env: 'check' + os: 'ubuntu-latest' + - name: 'docs' + python: '3.9' + toxpython: 'python3.9' + tox_env: 'docs' + os: 'ubuntu-latest' + - name: 'py36-pytest46-xdist127-coverage55 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest46-xdist127-coverage55' + os: 'ubuntu-latest' + - name: 'py36-pytest46-xdist127-coverage55 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest46-xdist127-coverage55' + os: 'windows-latest' + - name: 'py36-pytest46-xdist127-coverage55 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest46-xdist127-coverage55' + os: 'macos-latest' + - name: 'py37-pytest46-xdist127-coverage55 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest46-xdist127-coverage55' + os: 'ubuntu-latest' + - name: 'py37-pytest46-xdist127-coverage55 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest46-xdist127-coverage55' + os: 'windows-latest' + - name: 'py37-pytest46-xdist127-coverage55 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest46-xdist127-coverage55' + os: 'macos-latest' + - name: 'pypy-pytest46-xdist127-coverage55 (ubuntu)' + python: 'pypy-.' + toxpython: 'pypy.' + python_arch: 'x64' + tox_env: 'pypy-pytest46-xdist127-coverage55' + os: 'ubuntu-latest' + - name: 'pypy-pytest46-xdist127-coverage55 (windows)' + python: 'pypy-.' + toxpython: 'pypy.' + python_arch: 'x64' + tox_env: 'pypy-pytest46-xdist127-coverage55' + os: 'windows-latest' + - name: 'pypy-pytest46-xdist127-coverage55 (macos)' + python: 'pypy-.' + toxpython: 'pypy.' + python_arch: 'x64' + tox_env: 'pypy-pytest46-xdist127-coverage55' + os: 'macos-latest' + - name: 'pypy3-pytest46-xdist127-coverage55 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest46-xdist127-coverage55' + os: 'ubuntu-latest' + - name: 'pypy3-pytest46-xdist127-coverage55 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest46-xdist127-coverage55' + os: 'windows-latest' + - name: 'pypy3-pytest46-xdist127-coverage55 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest46-xdist127-coverage55' + os: 'macos-latest' + - name: 'py36-pytest46-xdist133-coverage55 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest46-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'py36-pytest46-xdist133-coverage55 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest46-xdist133-coverage55' + os: 'windows-latest' + - name: 'py36-pytest46-xdist133-coverage55 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest46-xdist133-coverage55' + os: 'macos-latest' + - name: 'py36-pytest54-xdist133-coverage55 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest54-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'py36-pytest54-xdist133-coverage55 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest54-xdist133-coverage55' + os: 'windows-latest' + - name: 'py36-pytest54-xdist133-coverage55 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest54-xdist133-coverage55' + os: 'macos-latest' + - name: 'py37-pytest46-xdist133-coverage55 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest46-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'py37-pytest46-xdist133-coverage55 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest46-xdist133-coverage55' + os: 'windows-latest' + - name: 'py37-pytest46-xdist133-coverage55 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest46-xdist133-coverage55' + os: 'macos-latest' + - name: 'py37-pytest54-xdist133-coverage55 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest54-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'py37-pytest54-xdist133-coverage55 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest54-xdist133-coverage55' + os: 'windows-latest' + - name: 'py37-pytest54-xdist133-coverage55 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest54-xdist133-coverage55' + os: 'macos-latest' + - name: 'py38-pytest46-xdist133-coverage55 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest46-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'py38-pytest46-xdist133-coverage55 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest46-xdist133-coverage55' + os: 'windows-latest' + - name: 'py38-pytest46-xdist133-coverage55 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest46-xdist133-coverage55' + os: 'macos-latest' + - name: 'py38-pytest54-xdist133-coverage55 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest54-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'py38-pytest54-xdist133-coverage55 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest54-xdist133-coverage55' + os: 'windows-latest' + - name: 'py38-pytest54-xdist133-coverage55 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest54-xdist133-coverage55' + os: 'macos-latest' + - name: 'pypy3-pytest46-xdist133-coverage55 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest46-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'pypy3-pytest46-xdist133-coverage55 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest46-xdist133-coverage55' + os: 'windows-latest' + - name: 'pypy3-pytest46-xdist133-coverage55 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest46-xdist133-coverage55' + os: 'macos-latest' + - name: 'pypy3-pytest54-xdist133-coverage55 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest54-xdist133-coverage55' + os: 'ubuntu-latest' + - name: 'pypy3-pytest54-xdist133-coverage55 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest54-xdist133-coverage55' + os: 'windows-latest' + - name: 'pypy3-pytest54-xdist133-coverage55 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest54-xdist133-coverage55' + os: 'macos-latest' + - name: 'py36-pytest62-xdist250-coverage55 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage55' + os: 'ubuntu-latest' + - name: 'py36-pytest62-xdist250-coverage55 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage55' + os: 'windows-latest' + - name: 'py36-pytest62-xdist250-coverage55 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage55' + os: 'macos-latest' + - name: 'py36-pytest62-xdist250-coverage60 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage60' + os: 'ubuntu-latest' + - name: 'py36-pytest62-xdist250-coverage60 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage60' + os: 'windows-latest' + - name: 'py36-pytest62-xdist250-coverage60 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage60' + os: 'macos-latest' + - name: 'py36-pytest62-xdist250-coverage61 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage61' + os: 'ubuntu-latest' + - name: 'py36-pytest62-xdist250-coverage61 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage61' + os: 'windows-latest' + - name: 'py36-pytest62-xdist250-coverage61 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage61' + os: 'macos-latest' + - name: 'py36-pytest62-xdist250-coverage62 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage62' + os: 'ubuntu-latest' + - name: 'py36-pytest62-xdist250-coverage62 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage62' + os: 'windows-latest' + - name: 'py36-pytest62-xdist250-coverage62 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage62' + os: 'macos-latest' + - name: 'py36-pytest62-xdist250-coverage63 (ubuntu)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage63' + os: 'ubuntu-latest' + - name: 'py36-pytest62-xdist250-coverage63 (windows)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage63' + os: 'windows-latest' + - name: 'py36-pytest62-xdist250-coverage63 (macos)' + python: '3.6' + toxpython: 'python3.6' + python_arch: 'x64' + tox_env: 'py36-pytest62-xdist250-coverage63' + os: 'macos-latest' + - name: 'py37-pytest62-xdist250-coverage55 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage55' + os: 'ubuntu-latest' + - name: 'py37-pytest62-xdist250-coverage55 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage55' + os: 'windows-latest' + - name: 'py37-pytest62-xdist250-coverage55 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage55' + os: 'macos-latest' + - name: 'py37-pytest62-xdist250-coverage60 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage60' + os: 'ubuntu-latest' + - name: 'py37-pytest62-xdist250-coverage60 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage60' + os: 'windows-latest' + - name: 'py37-pytest62-xdist250-coverage60 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage60' + os: 'macos-latest' + - name: 'py37-pytest62-xdist250-coverage61 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage61' + os: 'ubuntu-latest' + - name: 'py37-pytest62-xdist250-coverage61 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage61' + os: 'windows-latest' + - name: 'py37-pytest62-xdist250-coverage61 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage61' + os: 'macos-latest' + - name: 'py37-pytest62-xdist250-coverage62 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage62' + os: 'ubuntu-latest' + - name: 'py37-pytest62-xdist250-coverage62 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage62' + os: 'windows-latest' + - name: 'py37-pytest62-xdist250-coverage62 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage62' + os: 'macos-latest' + - name: 'py37-pytest62-xdist250-coverage63 (ubuntu)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage63' + os: 'ubuntu-latest' + - name: 'py37-pytest62-xdist250-coverage63 (windows)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage63' + os: 'windows-latest' + - name: 'py37-pytest62-xdist250-coverage63 (macos)' + python: '3.7' + toxpython: 'python3.7' + python_arch: 'x64' + tox_env: 'py37-pytest62-xdist250-coverage63' + os: 'macos-latest' + - name: 'py38-pytest62-xdist250-coverage55 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage55' + os: 'ubuntu-latest' + - name: 'py38-pytest62-xdist250-coverage55 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage55' + os: 'windows-latest' + - name: 'py38-pytest62-xdist250-coverage55 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage55' + os: 'macos-latest' + - name: 'py38-pytest62-xdist250-coverage60 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage60' + os: 'ubuntu-latest' + - name: 'py38-pytest62-xdist250-coverage60 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage60' + os: 'windows-latest' + - name: 'py38-pytest62-xdist250-coverage60 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage60' + os: 'macos-latest' + - name: 'py38-pytest62-xdist250-coverage61 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage61' + os: 'ubuntu-latest' + - name: 'py38-pytest62-xdist250-coverage61 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage61' + os: 'windows-latest' + - name: 'py38-pytest62-xdist250-coverage61 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage61' + os: 'macos-latest' + - name: 'py38-pytest62-xdist250-coverage62 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage62' + os: 'ubuntu-latest' + - name: 'py38-pytest62-xdist250-coverage62 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage62' + os: 'windows-latest' + - name: 'py38-pytest62-xdist250-coverage62 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage62' + os: 'macos-latest' + - name: 'py38-pytest62-xdist250-coverage63 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage63' + os: 'ubuntu-latest' + - name: 'py38-pytest62-xdist250-coverage63 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage63' + os: 'windows-latest' + - name: 'py38-pytest62-xdist250-coverage63 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38-pytest62-xdist250-coverage63' + os: 'macos-latest' + - name: 'py39-pytest62-xdist250-coverage55 (ubuntu)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage55' + os: 'ubuntu-latest' + - name: 'py39-pytest62-xdist250-coverage55 (windows)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage55' + os: 'windows-latest' + - name: 'py39-pytest62-xdist250-coverage55 (macos)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage55' + os: 'macos-latest' + - name: 'py39-pytest62-xdist250-coverage60 (ubuntu)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage60' + os: 'ubuntu-latest' + - name: 'py39-pytest62-xdist250-coverage60 (windows)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage60' + os: 'windows-latest' + - name: 'py39-pytest62-xdist250-coverage60 (macos)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage60' + os: 'macos-latest' + - name: 'py39-pytest62-xdist250-coverage61 (ubuntu)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage61' + os: 'ubuntu-latest' + - name: 'py39-pytest62-xdist250-coverage61 (windows)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage61' + os: 'windows-latest' + - name: 'py39-pytest62-xdist250-coverage61 (macos)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage61' + os: 'macos-latest' + - name: 'py39-pytest62-xdist250-coverage62 (ubuntu)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage62' + os: 'ubuntu-latest' + - name: 'py39-pytest62-xdist250-coverage62 (windows)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage62' + os: 'windows-latest' + - name: 'py39-pytest62-xdist250-coverage62 (macos)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage62' + os: 'macos-latest' + - name: 'py39-pytest62-xdist250-coverage63 (ubuntu)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage63' + os: 'ubuntu-latest' + - name: 'py39-pytest62-xdist250-coverage63 (windows)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage63' + os: 'windows-latest' + - name: 'py39-pytest62-xdist250-coverage63 (macos)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39-pytest62-xdist250-coverage63' + os: 'macos-latest' + - name: 'py310-pytest62-xdist250-coverage55 (ubuntu)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage55' + os: 'ubuntu-latest' + - name: 'py310-pytest62-xdist250-coverage55 (windows)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage55' + os: 'windows-latest' + - name: 'py310-pytest62-xdist250-coverage55 (macos)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage55' + os: 'macos-latest' + - name: 'py310-pytest62-xdist250-coverage60 (ubuntu)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage60' + os: 'ubuntu-latest' + - name: 'py310-pytest62-xdist250-coverage60 (windows)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage60' + os: 'windows-latest' + - name: 'py310-pytest62-xdist250-coverage60 (macos)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage60' + os: 'macos-latest' + - name: 'py310-pytest62-xdist250-coverage61 (ubuntu)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage61' + os: 'ubuntu-latest' + - name: 'py310-pytest62-xdist250-coverage61 (windows)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage61' + os: 'windows-latest' + - name: 'py310-pytest62-xdist250-coverage61 (macos)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage61' + os: 'macos-latest' + - name: 'py310-pytest62-xdist250-coverage62 (ubuntu)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage62' + os: 'ubuntu-latest' + - name: 'py310-pytest62-xdist250-coverage62 (windows)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage62' + os: 'windows-latest' + - name: 'py310-pytest62-xdist250-coverage62 (macos)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage62' + os: 'macos-latest' + - name: 'py310-pytest62-xdist250-coverage63 (ubuntu)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage63' + os: 'ubuntu-latest' + - name: 'py310-pytest62-xdist250-coverage63 (windows)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage63' + os: 'windows-latest' + - name: 'py310-pytest62-xdist250-coverage63 (macos)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310-pytest62-xdist250-coverage63' + os: 'macos-latest' + - name: 'pypy3-pytest62-xdist250-coverage55 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage55' + os: 'ubuntu-latest' + - name: 'pypy3-pytest62-xdist250-coverage55 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage55' + os: 'windows-latest' + - name: 'pypy3-pytest62-xdist250-coverage55 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage55' + os: 'macos-latest' + - name: 'pypy3-pytest62-xdist250-coverage60 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage60' + os: 'ubuntu-latest' + - name: 'pypy3-pytest62-xdist250-coverage60 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage60' + os: 'windows-latest' + - name: 'pypy3-pytest62-xdist250-coverage60 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage60' + os: 'macos-latest' + - name: 'pypy3-pytest62-xdist250-coverage61 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage61' + os: 'ubuntu-latest' + - name: 'pypy3-pytest62-xdist250-coverage61 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage61' + os: 'windows-latest' + - name: 'pypy3-pytest62-xdist250-coverage61 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage61' + os: 'macos-latest' + - name: 'pypy3-pytest62-xdist250-coverage62 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage62' + os: 'ubuntu-latest' + - name: 'pypy3-pytest62-xdist250-coverage62 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage62' + os: 'windows-latest' + - name: 'pypy3-pytest62-xdist250-coverage62 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage62' + os: 'macos-latest' + - name: 'pypy3-pytest62-xdist250-coverage63 (ubuntu)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage63' + os: 'ubuntu-latest' + - name: 'pypy3-pytest62-xdist250-coverage63 (windows)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage63' + os: 'windows-latest' + - name: 'pypy3-pytest62-xdist250-coverage63 (macos)' + python: 'pypy-3.' + toxpython: 'pypy3.' + python_arch: 'x64' + tox_env: 'pypy3-pytest62-xdist250-coverage63' + os: 'macos-latest' steps: - - uses: actions/checkout@v2 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Get pip cache dir - id: pip-cache - run: | - echo "::set-output name=dir::$(pip cache dir)" - - - name: Cache - uses: actions/cache@v2 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: - test-${{ matrix.python-version }}-v1-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - test-${{ matrix.python-version }}-v1- - - - name: Install dependencies - run: | - python -m pip install -U pip - python -m pip install -U wheel - python -m pip install --progress-bar=off tox -rci/requirements.txt - virtualenv --version - pip --version - tox --version - - - name: Tox tests - run: | - tox -v -e ${{ matrix.tox-python-version }}-${{ matrix.tox-extra-versions }}-coverage55 - - allgood: - needs: test - runs-on: ubuntu-latest - name: Test successful - steps: - - name: Success - run: echo Test successful + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + architecture: ${{ matrix.python_arch }} + - name: install dependencies + run: | + python -mpip install --progress-bar=off -r ci/requirements.txt + virtualenv --version + pip --version + tox --version + pip list --format=freeze + - name: test + env: + TOXPYTHON: '${{ matrix.toxpython }}' + run: > + tox -e ${{ matrix.tox_env }} -v diff --git a/MANIFEST.in b/MANIFEST.in index af1581be..cbb88f74 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -12,16 +12,17 @@ graft ci graft tests include .bumpversion.cfg -include .coveragerc include .cookiecutterrc +include .coveragerc include .editorconfig - +include tox.ini +include .readthedocs.yml +include .pre-commit-config.yaml include AUTHORS.rst include CHANGELOG.rst include CONTRIBUTING.rst include LICENSE include README.rst -include tox.ini .appveyor.yml .readthedocs.yml .pre-commit-config.yaml -global-exclude *.py[cod] __pycache__/* *.so *.dylib .coverage .coverage.* +global-exclude *.py[cod] __pycache__/* *.so *.dylib diff --git a/README.rst b/README.rst index 508aff84..2137c118 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,8 @@ Overview * - docs - |docs| * - tests - - | |github-actions| |appveyor| |requires| + - | |github-actions| |requires| + | * - package - | |version| |conda-forge| |wheel| |supported-versions| |supported-implementations| | |commits-since| diff --git a/ci/appveyor-with-compiler.cmd b/ci/appveyor-with-compiler.cmd deleted file mode 100644 index 289585fc..00000000 --- a/ci/appveyor-with-compiler.cmd +++ /dev/null @@ -1,23 +0,0 @@ -:: Very simple setup: -:: - if WINDOWS_SDK_VERSION is set then activate the SDK. -:: - disable the WDK if it's around. - -SET COMMAND_TO_RUN=%* -SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows -SET WIN_WDK="c:\Program Files (x86)\Windows Kits\10\Include\wdf" -ECHO SDK: %WINDOWS_SDK_VERSION% ARCH: %PYTHON_ARCH% - -IF EXIST %WIN_WDK% ( - REM See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ - REN %WIN_WDK% 0wdf -) -IF "%WINDOWS_SDK_VERSION%"=="" GOTO main - -SET DISTUTILS_USE_SDK=1 -SET MSSdk=1 -"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% -CALL "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release - -:main -ECHO Executing: %COMMAND_TO_RUN% -CALL %COMMAND_TO_RUN% || EXIT 1 diff --git a/ci/bootstrap.py b/ci/bootstrap.py index 77daad5b..b0977495 100755 --- a/ci/bootstrap.py +++ b/ci/bootstrap.py @@ -3,13 +3,14 @@ import os import subprocess import sys -from collections import defaultdict from os.path import abspath from os.path import dirname from os.path import exists from os.path import join +from os.path import relpath base_path = dirname(dirname(abspath(__file__))) +templates_path = join(base_path, "ci", "templates") def check_call(args): @@ -51,7 +52,7 @@ def main(): print(f"Project path: {base_path}") jinja = jinja2.Environment( - loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")), + loader=jinja2.FileSystemLoader(templates_path), trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True @@ -59,22 +60,21 @@ def main(): tox_environments = [ line.strip() - # WARNING: 'tox' must be installed globally or in the project's virtualenv - for line in subprocess.check_output(['tox', '--listenvs'], universal_newlines=True).splitlines() + # 'tox' need not be installed globally, but must be importable + # by the Python that is running this script. + # This uses sys.executable the same way that the call in + # cookiecutter-pylibrary/hooks/post_gen_project.py + # invokes this bootstrap.py itself. + for line in subprocess.check_output([sys.executable, '-m', 'tox', '--listenvs'], universal_newlines=True).splitlines() ] - tox_environments = [line for line in tox_environments if line not in ['clean', 'report', 'docs', 'check']] - - template_vars = defaultdict(list) - template_vars['tox_environments'] = tox_environments - for env in tox_environments: - first, _ = env.split('-', 1) - template_vars['%s_environments' % first].append(env) - - for name in os.listdir(join("ci", "templates")): - with open(join(base_path, name), "w") as fh: - fh.write('# NOTE: this file is auto-generated via ci/bootstrap.py (ci/templates/%s).\n' % name) - fh.write(jinja.get_template(name).render(**template_vars)) - print(f"Wrote {name}") + tox_environments = [line for line in tox_environments if line.startswith('py')] + + for root, _, files in os.walk(templates_path): + for name in files: + relative = relpath(root, templates_path) + with open(join(base_path, relative, name), "w") as fh: + fh.write(jinja.get_template(join(relative, name)).render(tox_environments=tox_environments)) + print(f"Wrote {name}") print("DONE.") diff --git a/ci/requirements.txt b/ci/requirements.txt index d7f5177e..a0ef106f 100644 --- a/ci/requirements.txt +++ b/ci/requirements.txt @@ -2,3 +2,4 @@ virtualenv>=16.6.0 pip>=19.1.1 setuptools>=18.0.1 six>=1.14.0 +tox diff --git a/ci/templates/.appveyor.yml b/ci/templates/.appveyor.yml deleted file mode 100644 index 2b7e611c..00000000 --- a/ci/templates/.appveyor.yml +++ /dev/null @@ -1,53 +0,0 @@ -version: '{branch}-{build}' -build: off -image: - - Visual Studio 2015 - - Visual Studio 2019 -environment: - matrix: - - TOXENV: check - - TOXENV: '{{ py27_environments|join(",") }}' - - TOXENV: '{{ py35_environments|join(",") }}' - - TOXENV: '{{ py36_environments|join(",") }}' - - TOXENV: '{{ py37_environments|join(",") }}' - - TOXENV: '{{ py38_environments|join(",") }}' - - TOXENV: '{{ py39_environments|join(",") }}' - - TOXENV: '{{ pypy_environments|join(",") }}' - - TOXENV: '{{ pypy3_environments|join(",") }}' -matrix: - exclude: - - image: Visual Studio 2019 - TOXENV: '{{ py27_environments|join(",") }}' - - image: Visual Studio 2015 - TOXENV: '{{ py36_environments|join(",") }}' - - image: Visual Studio 2015 - TOXENV: '{{ py37_environments|join(",") }}' - - image: Visual Studio 2015 - TOXENV: '{{ py38_environments|join(",") }}' - - image: Visual Studio 2015 - TOXENV: '{{ py39_environments|join(",") }}' - - image: Visual Studio 2015 - TOXENV: '{{ pypy_environments|join(",") }}' - - image: Visual Studio 2015 - TOXENV: '{{ pypy3_environments|join(",") }}' -init: - - ps: echo $env:TOXENV - - ps: ls C:\Python* -install: - - IF "%TOXENV:~0,5%" == "pypy-" choco install --no-progress python.pypy - - IF "%TOXENV:~0,6%" == "pypy3-" choco install --no-progress pypy3 - - SET PATH=C:\tools\pypy\pypy;%PATH% - - C:\Python37\python -m pip install --progress-bar=off tox -rci/requirements.txt - -test_script: - - cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd C:\Python37\python -m tox - -on_failure: - - ps: dir "env:" - - ps: get-content .tox\*\log\* -artifacts: - - path: dist\* - -### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker): -# on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/ci/templates/.github/workflows/test.yml b/ci/templates/.github/workflows/test.yml new file mode 100644 index 00000000..96d24801 --- /dev/null +++ b/ci/templates/.github/workflows/test.yml @@ -0,0 +1,65 @@ +name: build +on: [push, pull_request] +jobs: + test: + name: {{ '${{ matrix.name }}' }} + runs-on: {{ '${{ matrix.os }}' }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - name: 'check' + python: '3.9' + toxpython: 'python3.9' + tox_env: 'check' + os: 'ubuntu-latest' + - name: 'docs' + python: '3.9' + toxpython: 'python3.9' + tox_env: 'docs' + os: 'ubuntu-latest' +{% for env in tox_environments %} +{% set prefix = env.split('-')[0] -%} +{% if prefix.startswith('pypy') %} +{% set python %}pypy-{{ prefix[4] }}.{{ prefix[5] }}{% endset %} +{% set cpython %}pp{{ prefix[4:5] }}{% endset %} +{% set toxpython %}pypy{{ prefix[4] }}.{{ prefix[5] }}{% endset %} +{% else %} +{% set python %}{{ prefix[2] }}.{{ prefix[3:] }}{% endset %} +{% set cpython %}cp{{ prefix[2:] }}{% endset %} +{% set toxpython %}python{{ prefix[2] }}.{{ prefix[3:] }}{% endset %} +{% endif %} +{% for os, python_arch in [ + ['ubuntu', 'x64'], + ['windows', 'x64'], + ['macos', 'x64'], +] %} + - name: '{{ env }} ({{ os }})' + python: '{{ python }}' + toxpython: '{{ toxpython }}' + python_arch: '{{ python_arch }}' + tox_env: '{{ env }}' + os: '{{ os }}-latest' +{% endfor %} +{% endfor %} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/setup-python@v2 + with: + python-version: {{ '${{ matrix.python }}' }} + architecture: {{ '${{ matrix.python_arch }}' }} + - name: install dependencies + run: | + python -mpip install --progress-bar=off -r ci/requirements.txt + virtualenv --version + pip --version + tox --version + pip list --format=freeze + - name: test + env: + TOXPYTHON: '{{ '${{ matrix.toxpython }}' }}' + run: > + tox -e {{ '${{ matrix.tox_env }}' }} -v diff --git a/setup.py b/setup.py index 0748d12e..21681887 100755 --- a/setup.py +++ b/setup.py @@ -115,6 +115,11 @@ def run(self): 'Topic :: Software Development :: Testing', 'Topic :: Utilities', ], + project_urls={ + 'Documentation': 'https://pytest-cov.readthedocs.io/', + 'Changelog': 'https://pytest-cov.readthedocs.io/en/latest/changelog.html', + 'Issue Tracker': 'https://github.com/pytest-dev/pytest-cov/issues', + }, keywords=[ 'cover', 'coverage', 'pytest', 'py.test', 'distributed', 'parallel', ], diff --git a/tox.ini b/tox.ini index 99e1fff6..6d7ab6eb 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,6 @@ [testenv:bootstrap] deps = jinja2 - matrix tox skip_install = true commands = From 6716d6043b992d191e742b05ad37b2b5c0318686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 3 Feb 2022 15:22:10 +0200 Subject: [PATCH 05/20] Remove unnecessary parametrization. Fix statement count. --- tests/test_pytest_cov.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index e94d59be..33814ef4 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1223,15 +1223,14 @@ def test_run_target(): result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', - 'test_multiprocessing_process* 8 * 100%*', + 'test_multiprocessing_process* 9 * 100%*', '*1 passed*' ]) assert result.ret == 0 @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -@method_params -def test_multiprocessing_process_no_source(testdir, method): +def test_multiprocessing_process_no_source(testdir): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' @@ -1261,8 +1260,7 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -@method_params -def test_multiprocessing_process_with_terminate(testdir, method): +def test_multiprocessing_process_with_terminate(testdir): pytest.importorskip('multiprocessing.util') script = testdir.makepyfile(''' From 700f230bc597485f25ac3db0397cd21fd638ae9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 19:45:22 +0300 Subject: [PATCH 06/20] Bump deps and trim deps to strictly necessary. --- .github/workflows/test.yml | 720 ++----------------------------------- tox.ini | 10 +- 2 files changed, 42 insertions(+), 688 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18299c41..0c182389 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,761 +19,113 @@ jobs: toxpython: 'python3.9' tox_env: 'docs' os: 'ubuntu-latest' - - name: 'py36-pytest46-xdist127-coverage55 (ubuntu)' + - name: 'py36-pytest70-xdist250-coverage62 (ubuntu)' python: '3.6' toxpython: 'python3.6' python_arch: 'x64' - tox_env: 'py36-pytest46-xdist127-coverage55' + tox_env: 'py36-pytest70-xdist250-coverage62' os: 'ubuntu-latest' - - name: 'py36-pytest46-xdist127-coverage55 (windows)' + - name: 'py36-pytest70-xdist250-coverage62 (windows)' python: '3.6' toxpython: 'python3.6' python_arch: 'x64' - tox_env: 'py36-pytest46-xdist127-coverage55' + tox_env: 'py36-pytest70-xdist250-coverage62' os: 'windows-latest' - - name: 'py36-pytest46-xdist127-coverage55 (macos)' + - name: 'py36-pytest70-xdist250-coverage62 (macos)' python: '3.6' toxpython: 'python3.6' python_arch: 'x64' - tox_env: 'py36-pytest46-xdist127-coverage55' + tox_env: 'py36-pytest70-xdist250-coverage62' os: 'macos-latest' - - name: 'py37-pytest46-xdist127-coverage55 (ubuntu)' + - name: 'py37-pytest71-xdist250-coverage64 (ubuntu)' python: '3.7' toxpython: 'python3.7' python_arch: 'x64' - tox_env: 'py37-pytest46-xdist127-coverage55' + tox_env: 'py37-pytest71-xdist250-coverage64' os: 'ubuntu-latest' - - name: 'py37-pytest46-xdist127-coverage55 (windows)' + - name: 'py37-pytest71-xdist250-coverage64 (windows)' python: '3.7' toxpython: 'python3.7' python_arch: 'x64' - tox_env: 'py37-pytest46-xdist127-coverage55' + tox_env: 'py37-pytest71-xdist250-coverage64' os: 'windows-latest' - - name: 'py37-pytest46-xdist127-coverage55 (macos)' + - name: 'py37-pytest71-xdist250-coverage64 (macos)' python: '3.7' toxpython: 'python3.7' python_arch: 'x64' - tox_env: 'py37-pytest46-xdist127-coverage55' + tox_env: 'py37-pytest71-xdist250-coverage64' os: 'macos-latest' - - name: 'pypy-pytest46-xdist127-coverage55 (ubuntu)' - python: 'pypy-.' - toxpython: 'pypy.' - python_arch: 'x64' - tox_env: 'pypy-pytest46-xdist127-coverage55' - os: 'ubuntu-latest' - - name: 'pypy-pytest46-xdist127-coverage55 (windows)' - python: 'pypy-.' - toxpython: 'pypy.' - python_arch: 'x64' - tox_env: 'pypy-pytest46-xdist127-coverage55' - os: 'windows-latest' - - name: 'pypy-pytest46-xdist127-coverage55 (macos)' - python: 'pypy-.' - toxpython: 'pypy.' - python_arch: 'x64' - tox_env: 'pypy-pytest46-xdist127-coverage55' - os: 'macos-latest' - - name: 'pypy3-pytest46-xdist127-coverage55 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest46-xdist127-coverage55' - os: 'ubuntu-latest' - - name: 'pypy3-pytest46-xdist127-coverage55 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest46-xdist127-coverage55' - os: 'windows-latest' - - name: 'pypy3-pytest46-xdist127-coverage55 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest46-xdist127-coverage55' - os: 'macos-latest' - - name: 'py36-pytest46-xdist133-coverage55 (ubuntu)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest46-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'py36-pytest46-xdist133-coverage55 (windows)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest46-xdist133-coverage55' - os: 'windows-latest' - - name: 'py36-pytest46-xdist133-coverage55 (macos)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest46-xdist133-coverage55' - os: 'macos-latest' - - name: 'py36-pytest54-xdist133-coverage55 (ubuntu)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest54-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'py36-pytest54-xdist133-coverage55 (windows)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest54-xdist133-coverage55' - os: 'windows-latest' - - name: 'py36-pytest54-xdist133-coverage55 (macos)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest54-xdist133-coverage55' - os: 'macos-latest' - - name: 'py37-pytest46-xdist133-coverage55 (ubuntu)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest46-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'py37-pytest46-xdist133-coverage55 (windows)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest46-xdist133-coverage55' - os: 'windows-latest' - - name: 'py37-pytest46-xdist133-coverage55 (macos)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest46-xdist133-coverage55' - os: 'macos-latest' - - name: 'py37-pytest54-xdist133-coverage55 (ubuntu)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest54-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'py37-pytest54-xdist133-coverage55 (windows)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest54-xdist133-coverage55' - os: 'windows-latest' - - name: 'py37-pytest54-xdist133-coverage55 (macos)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest54-xdist133-coverage55' - os: 'macos-latest' - - name: 'py38-pytest46-xdist133-coverage55 (ubuntu)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest46-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'py38-pytest46-xdist133-coverage55 (windows)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest46-xdist133-coverage55' - os: 'windows-latest' - - name: 'py38-pytest46-xdist133-coverage55 (macos)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest46-xdist133-coverage55' - os: 'macos-latest' - - name: 'py38-pytest54-xdist133-coverage55 (ubuntu)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest54-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'py38-pytest54-xdist133-coverage55 (windows)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest54-xdist133-coverage55' - os: 'windows-latest' - - name: 'py38-pytest54-xdist133-coverage55 (macos)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest54-xdist133-coverage55' - os: 'macos-latest' - - name: 'pypy3-pytest46-xdist133-coverage55 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest46-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'pypy3-pytest46-xdist133-coverage55 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest46-xdist133-coverage55' - os: 'windows-latest' - - name: 'pypy3-pytest46-xdist133-coverage55 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest46-xdist133-coverage55' - os: 'macos-latest' - - name: 'pypy3-pytest54-xdist133-coverage55 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest54-xdist133-coverage55' - os: 'ubuntu-latest' - - name: 'pypy3-pytest54-xdist133-coverage55 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest54-xdist133-coverage55' - os: 'windows-latest' - - name: 'pypy3-pytest54-xdist133-coverage55 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest54-xdist133-coverage55' - os: 'macos-latest' - - name: 'py36-pytest62-xdist250-coverage55 (ubuntu)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage55' - os: 'ubuntu-latest' - - name: 'py36-pytest62-xdist250-coverage55 (windows)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage55' - os: 'windows-latest' - - name: 'py36-pytest62-xdist250-coverage55 (macos)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage55' - os: 'macos-latest' - - name: 'py36-pytest62-xdist250-coverage60 (ubuntu)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage60' - os: 'ubuntu-latest' - - name: 'py36-pytest62-xdist250-coverage60 (windows)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage60' - os: 'windows-latest' - - name: 'py36-pytest62-xdist250-coverage60 (macos)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage60' - os: 'macos-latest' - - name: 'py36-pytest62-xdist250-coverage61 (ubuntu)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage61' - os: 'ubuntu-latest' - - name: 'py36-pytest62-xdist250-coverage61 (windows)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage61' - os: 'windows-latest' - - name: 'py36-pytest62-xdist250-coverage61 (macos)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage61' - os: 'macos-latest' - - name: 'py36-pytest62-xdist250-coverage62 (ubuntu)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage62' - os: 'ubuntu-latest' - - name: 'py36-pytest62-xdist250-coverage62 (windows)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage62' - os: 'windows-latest' - - name: 'py36-pytest62-xdist250-coverage62 (macos)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage62' - os: 'macos-latest' - - name: 'py36-pytest62-xdist250-coverage63 (ubuntu)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage63' - os: 'ubuntu-latest' - - name: 'py36-pytest62-xdist250-coverage63 (windows)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage63' - os: 'windows-latest' - - name: 'py36-pytest62-xdist250-coverage63 (macos)' - python: '3.6' - toxpython: 'python3.6' - python_arch: 'x64' - tox_env: 'py36-pytest62-xdist250-coverage63' - os: 'macos-latest' - - name: 'py37-pytest62-xdist250-coverage55 (ubuntu)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage55' - os: 'ubuntu-latest' - - name: 'py37-pytest62-xdist250-coverage55 (windows)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage55' - os: 'windows-latest' - - name: 'py37-pytest62-xdist250-coverage55 (macos)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage55' - os: 'macos-latest' - - name: 'py37-pytest62-xdist250-coverage60 (ubuntu)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage60' - os: 'ubuntu-latest' - - name: 'py37-pytest62-xdist250-coverage60 (windows)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage60' - os: 'windows-latest' - - name: 'py37-pytest62-xdist250-coverage60 (macos)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage60' - os: 'macos-latest' - - name: 'py37-pytest62-xdist250-coverage61 (ubuntu)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage61' - os: 'ubuntu-latest' - - name: 'py37-pytest62-xdist250-coverage61 (windows)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage61' - os: 'windows-latest' - - name: 'py37-pytest62-xdist250-coverage61 (macos)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage61' - os: 'macos-latest' - - name: 'py37-pytest62-xdist250-coverage62 (ubuntu)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage62' - os: 'ubuntu-latest' - - name: 'py37-pytest62-xdist250-coverage62 (windows)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage62' - os: 'windows-latest' - - name: 'py37-pytest62-xdist250-coverage62 (macos)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage62' - os: 'macos-latest' - - name: 'py37-pytest62-xdist250-coverage63 (ubuntu)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage63' - os: 'ubuntu-latest' - - name: 'py37-pytest62-xdist250-coverage63 (windows)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage63' - os: 'windows-latest' - - name: 'py37-pytest62-xdist250-coverage63 (macos)' - python: '3.7' - toxpython: 'python3.7' - python_arch: 'x64' - tox_env: 'py37-pytest62-xdist250-coverage63' - os: 'macos-latest' - - name: 'py38-pytest62-xdist250-coverage55 (ubuntu)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage55' - os: 'ubuntu-latest' - - name: 'py38-pytest62-xdist250-coverage55 (windows)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage55' - os: 'windows-latest' - - name: 'py38-pytest62-xdist250-coverage55 (macos)' + - name: 'py38-pytest71-xdist250-coverage64 (ubuntu)' python: '3.8' toxpython: 'python3.8' python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage55' - os: 'macos-latest' - - name: 'py38-pytest62-xdist250-coverage60 (ubuntu)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage60' + tox_env: 'py38-pytest71-xdist250-coverage64' os: 'ubuntu-latest' - - name: 'py38-pytest62-xdist250-coverage60 (windows)' + - name: 'py38-pytest71-xdist250-coverage64 (windows)' python: '3.8' toxpython: 'python3.8' python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage60' + tox_env: 'py38-pytest71-xdist250-coverage64' os: 'windows-latest' - - name: 'py38-pytest62-xdist250-coverage60 (macos)' + - name: 'py38-pytest71-xdist250-coverage64 (macos)' python: '3.8' toxpython: 'python3.8' python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage60' + tox_env: 'py38-pytest71-xdist250-coverage64' os: 'macos-latest' - - name: 'py38-pytest62-xdist250-coverage61 (ubuntu)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage61' - os: 'ubuntu-latest' - - name: 'py38-pytest62-xdist250-coverage61 (windows)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage61' - os: 'windows-latest' - - name: 'py38-pytest62-xdist250-coverage61 (macos)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage61' - os: 'macos-latest' - - name: 'py38-pytest62-xdist250-coverage62 (ubuntu)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage62' - os: 'ubuntu-latest' - - name: 'py38-pytest62-xdist250-coverage62 (windows)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage62' - os: 'windows-latest' - - name: 'py38-pytest62-xdist250-coverage62 (macos)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage62' - os: 'macos-latest' - - name: 'py38-pytest62-xdist250-coverage63 (ubuntu)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage63' - os: 'ubuntu-latest' - - name: 'py38-pytest62-xdist250-coverage63 (windows)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage63' - os: 'windows-latest' - - name: 'py38-pytest62-xdist250-coverage63 (macos)' - python: '3.8' - toxpython: 'python3.8' - python_arch: 'x64' - tox_env: 'py38-pytest62-xdist250-coverage63' - os: 'macos-latest' - - name: 'py39-pytest62-xdist250-coverage55 (ubuntu)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage55' - os: 'ubuntu-latest' - - name: 'py39-pytest62-xdist250-coverage55 (windows)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage55' - os: 'windows-latest' - - name: 'py39-pytest62-xdist250-coverage55 (macos)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage55' - os: 'macos-latest' - - name: 'py39-pytest62-xdist250-coverage60 (ubuntu)' + - name: 'py39-pytest71-xdist250-coverage64 (ubuntu)' python: '3.9' toxpython: 'python3.9' python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage60' + tox_env: 'py39-pytest71-xdist250-coverage64' os: 'ubuntu-latest' - - name: 'py39-pytest62-xdist250-coverage60 (windows)' + - name: 'py39-pytest71-xdist250-coverage64 (windows)' python: '3.9' toxpython: 'python3.9' python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage60' + tox_env: 'py39-pytest71-xdist250-coverage64' os: 'windows-latest' - - name: 'py39-pytest62-xdist250-coverage60 (macos)' + - name: 'py39-pytest71-xdist250-coverage64 (macos)' python: '3.9' toxpython: 'python3.9' python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage60' + tox_env: 'py39-pytest71-xdist250-coverage64' os: 'macos-latest' - - name: 'py39-pytest62-xdist250-coverage61 (ubuntu)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage61' - os: 'ubuntu-latest' - - name: 'py39-pytest62-xdist250-coverage61 (windows)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage61' - os: 'windows-latest' - - name: 'py39-pytest62-xdist250-coverage61 (macos)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage61' - os: 'macos-latest' - - name: 'py39-pytest62-xdist250-coverage62 (ubuntu)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage62' - os: 'ubuntu-latest' - - name: 'py39-pytest62-xdist250-coverage62 (windows)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage62' - os: 'windows-latest' - - name: 'py39-pytest62-xdist250-coverage62 (macos)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage62' - os: 'macos-latest' - - name: 'py39-pytest62-xdist250-coverage63 (ubuntu)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage63' - os: 'ubuntu-latest' - - name: 'py39-pytest62-xdist250-coverage63 (windows)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage63' - os: 'windows-latest' - - name: 'py39-pytest62-xdist250-coverage63 (macos)' - python: '3.9' - toxpython: 'python3.9' - python_arch: 'x64' - tox_env: 'py39-pytest62-xdist250-coverage63' - os: 'macos-latest' - - name: 'py310-pytest62-xdist250-coverage55 (ubuntu)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage55' - os: 'ubuntu-latest' - - name: 'py310-pytest62-xdist250-coverage55 (windows)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage55' - os: 'windows-latest' - - name: 'py310-pytest62-xdist250-coverage55 (macos)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage55' - os: 'macos-latest' - - name: 'py310-pytest62-xdist250-coverage60 (ubuntu)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage60' - os: 'ubuntu-latest' - - name: 'py310-pytest62-xdist250-coverage60 (windows)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage60' - os: 'windows-latest' - - name: 'py310-pytest62-xdist250-coverage60 (macos)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage60' - os: 'macos-latest' - - name: 'py310-pytest62-xdist250-coverage61 (ubuntu)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage61' - os: 'ubuntu-latest' - - name: 'py310-pytest62-xdist250-coverage61 (windows)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage61' - os: 'windows-latest' - - name: 'py310-pytest62-xdist250-coverage61 (macos)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage61' - os: 'macos-latest' - - name: 'py310-pytest62-xdist250-coverage62 (ubuntu)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage62' - os: 'ubuntu-latest' - - name: 'py310-pytest62-xdist250-coverage62 (windows)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage62' - os: 'windows-latest' - - name: 'py310-pytest62-xdist250-coverage62 (macos)' + - name: 'py310-pytest71-xdist250-coverage64 (ubuntu)' python: '3.10' toxpython: 'python3.10' python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage62' - os: 'macos-latest' - - name: 'py310-pytest62-xdist250-coverage63 (ubuntu)' - python: '3.10' - toxpython: 'python3.10' - python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage63' + tox_env: 'py310-pytest71-xdist250-coverage64' os: 'ubuntu-latest' - - name: 'py310-pytest62-xdist250-coverage63 (windows)' + - name: 'py310-pytest71-xdist250-coverage64 (windows)' python: '3.10' toxpython: 'python3.10' python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage63' + tox_env: 'py310-pytest71-xdist250-coverage64' os: 'windows-latest' - - name: 'py310-pytest62-xdist250-coverage63 (macos)' + - name: 'py310-pytest71-xdist250-coverage64 (macos)' python: '3.10' toxpython: 'python3.10' python_arch: 'x64' - tox_env: 'py310-pytest62-xdist250-coverage63' - os: 'macos-latest' - - name: 'pypy3-pytest62-xdist250-coverage55 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage55' - os: 'ubuntu-latest' - - name: 'pypy3-pytest62-xdist250-coverage55 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage55' - os: 'windows-latest' - - name: 'pypy3-pytest62-xdist250-coverage55 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage55' - os: 'macos-latest' - - name: 'pypy3-pytest62-xdist250-coverage60 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage60' - os: 'ubuntu-latest' - - name: 'pypy3-pytest62-xdist250-coverage60 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage60' - os: 'windows-latest' - - name: 'pypy3-pytest62-xdist250-coverage60 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage60' - os: 'macos-latest' - - name: 'pypy3-pytest62-xdist250-coverage61 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage61' - os: 'ubuntu-latest' - - name: 'pypy3-pytest62-xdist250-coverage61 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage61' - os: 'windows-latest' - - name: 'pypy3-pytest62-xdist250-coverage61 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage61' - os: 'macos-latest' - - name: 'pypy3-pytest62-xdist250-coverage62 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage62' - os: 'ubuntu-latest' - - name: 'pypy3-pytest62-xdist250-coverage62 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage62' - os: 'windows-latest' - - name: 'pypy3-pytest62-xdist250-coverage62 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' - python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage62' + tox_env: 'py310-pytest71-xdist250-coverage64' os: 'macos-latest' - - name: 'pypy3-pytest62-xdist250-coverage63 (ubuntu)' + - name: 'pypy3-pytest71-xdist250-coverage64 (ubuntu)' python: 'pypy-3.' toxpython: 'pypy3.' python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage63' + tox_env: 'pypy3-pytest71-xdist250-coverage64' os: 'ubuntu-latest' - - name: 'pypy3-pytest62-xdist250-coverage63 (windows)' + - name: 'pypy3-pytest71-xdist250-coverage64 (windows)' python: 'pypy-3.' toxpython: 'pypy3.' python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage63' + tox_env: 'pypy3-pytest71-xdist250-coverage64' os: 'windows-latest' - - name: 'pypy3-pytest62-xdist250-coverage63 (macos)' + - name: 'pypy3-pytest71-xdist250-coverage64 (macos)' python: 'pypy-3.' toxpython: 'pypy3.' python_arch: 'x64' - tox_env: 'pypy3-pytest62-xdist250-coverage63' + tox_env: 'pypy3-pytest71-xdist250-coverage64' os: 'macos-latest' steps: - uses: actions/checkout@v2 diff --git a/tox.ini b/tox.ini index 6d7ab6eb..88a2b63a 100644 --- a/tox.ini +++ b/tox.ini @@ -12,9 +12,8 @@ passenv = [tox] envlist = check - py{36,37,py,py3}-pytest46-xdist127-coverage{55} - py{36,37,38,py3}-pytest{46,54}-xdist133-coverage{55} - py{36,37,38,39,310,py3}-pytest{62}-xdist250-coverage{55,60,61,62,63} + py{36}-pytest{70}-xdist250-coverage{62} + py{37,38,39,310,py3}-pytest{71}-xdist250-coverage{64} docs [testenv] @@ -29,6 +28,8 @@ setenv = pytest60: _DEP_PYTEST=pytest==6.0.2 pytest61: _DEP_PYTEST=pytest==6.1.2 pytest62: _DEP_PYTEST=pytest==6.2.5 + pytest70: _DEP_PYTEST=pytest==7.0.1 + pytest71: _DEP_PYTEST=pytest==7.1.2 xdist127: _DEP_PYTESTXDIST=pytest-xdist==1.27.0 xdist129: _DEP_PYTESTXDIST=pytest-xdist==1.29.0 @@ -52,7 +53,8 @@ setenv = coverage60: _DEP_COVERAGE=coverage==6.0.2 coverage61: _DEP_COVERAGE=coverage==6.1.2 coverage62: _DEP_COVERAGE=coverage==6.2 - coverage63: _DEP_COVERAGE=coverage==6.3 + coverage63: _DEP_COVERAGE=coverage==6.3.3 + coverage64: _DEP_COVERAGE=coverage==6.4.2 # For testing against a coverage.py working tree. coveragedev: _DEP_COVERAGE=-e{env:COVERAGE_HOME} passenv = From 97dbb12145d3621a583d5057f996c963af1746c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 19:52:47 +0300 Subject: [PATCH 07/20] Cleanup what can only be an accidental fatfinger copypasta. --- CHANGELOG.rst | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3087426b..1ec62380 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -36,17 +36,6 @@ Changelog Contributed by Thomas Grainger in `#477 `_. - -2.13.0 (2021-06-01) -------------------- - -* Changed the `toml` requirement to be always be directly required (instead of being required through a coverage extra). - This fixes issues with pip-compile (`pip-tools#1300 `_). - Contributed by Sorin Sbarnea in `#472 `_. -* Documented ``show_contexts``. - Contributed by Brian Rutledge in `#473 `_. - - 2.12.1 (2021-06-01) ------------------- From a5f99c2e16d178694019da31349aab6c98410365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 19:53:22 +0300 Subject: [PATCH 08/20] Remove another dupe entry. --- CHANGELOG.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1ec62380..e559ebb4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -185,8 +185,6 @@ Changelog `#272 `_, `#271 `_ and `#269 `_. -* Improved documentation regarding subprocess and multiprocessing. - Contributed in `#265 `_. * Improved ``pytest_cov.embed.cleanup_on_sigterm`` to be reentrant (signal deliveries while signal handling is running won't break stuff). * Added ``pytest_cov.embed.cleanup_on_signal`` for customized cleanup. From 50d62bc92b177e72ae74d57c9cce5a75c138cae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 19:56:58 +0300 Subject: [PATCH 09/20] Fix `cannot import name 'environmentfilter' from 'jinja2'` issue. --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index ccec79fd..6fdf26f9 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,5 @@ sphinx==3.0.3 sphinx-py3doc-enhanced-theme==2.4.0 docutils==0.16 +jinja2<3.1 -e . From aba1d31b875c6edab1bd68b2ce854d5fa696795c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 23:34:07 +0300 Subject: [PATCH 10/20] Remove our crummy multiprocessing hooks and work on some tests with the builtin mp support in coverage. --- src/pytest-cov.pth | 2 +- src/pytest_cov/embed.py | 18 ------- tests/test_pytest_cov.py | 103 ++++++++++++++++++--------------------- 3 files changed, 49 insertions(+), 74 deletions(-) diff --git a/src/pytest-cov.pth b/src/pytest-cov.pth index 91f2b7c7..8ed1a516 100644 --- a/src/pytest-cov.pth +++ b/src/pytest-cov.pth @@ -1 +1 @@ -import os, sys;exec('if \'COV_CORE_SOURCE\' in os.environ:\n try:\n from pytest_cov.embed import init\n init()\n except Exception as exc:\n sys.stderr.write(\n "pytest-cov: Failed to setup subprocess coverage. "\n "Environ: {0!r} "\n "Exception: {1!r}\\n".format(\n dict((k, v) for k, v in os.environ.items() if k.startswith(\'COV_CORE\')),\n exc\n )\n )\n') \ No newline at end of file +import os, sys;exec('if \'COV_CORE_SOURCE\' in os.environ:\n try:\n from pytest_cov.embed import init\n init()\n except Exception as exc:\n sys.stderr.write(\n "pytest-cov: Failed to setup subprocess coverage. "\n "Environ: {0!r} "\n "Exception: {1!r}\\n".format(\n dict((k, v) for k, v in os.environ.items() if k.startswith(\'COV_CORE\')),\n exc\n )\n )\n') diff --git a/src/pytest_cov/embed.py b/src/pytest_cov/embed.py index fe0575e9..f8a2749f 100644 --- a/src/pytest_cov/embed.py +++ b/src/pytest_cov/embed.py @@ -20,22 +20,6 @@ _active_cov = None -def multiprocessing_start(_): - global _active_cov - cov = init() - if cov: - _active_cov = cov - multiprocessing.util.Finalize(None, cleanup, exitpriority=1000) - - -try: - import multiprocessing.util -except ImportError: - pass -else: - multiprocessing.util.register_after_fork(multiprocessing_start, multiprocessing_start) - - def init(): # Only continue if ancestor process has set everything needed in # the env. @@ -105,8 +89,6 @@ def cleanup(): _signal_cleanup_handler(*pending_signal) -multiprocessing_finish = cleanup # in case someone dared to use this internal - _previous_handlers = {} _pending_signal = None _cleanup_in_progress = False diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 33814ef4..edf0fe6e 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -157,15 +157,6 @@ def test_foo(cov): pytest.param('-n 1', marks=pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"')) ], ids=['nodist', 'xdist']) -skipif_multiprocessing_is_broken = pytest.mark.skipif( - 'sys.version_info[:2] >= (3, 8)', - reason="deadlocks on Python 3.8+, see: https://bugs.python.org/issue38227" -) -method_params = pytest.mark.parametrize('method', [ - pytest.param('fork', marks=skipif_multiprocessing_is_broken), - pytest.param('spawn', marks=skipif_multiprocessing_is_broken), -]) - @pytest.fixture(scope='session', autouse=True) def adjust_sys_path(): @@ -203,7 +194,7 @@ def prop(request): ) -def test_central(testdir, prop): +def test_central(pytester, testdir, prop): script = testdir.makepyfile(prop.code) testdir.tmpdir.join('.coveragerc').write(prop.fullconf) @@ -470,7 +461,7 @@ def test_cov_min_no_report(testdir): ]) -def test_central_nonspecific(testdir, prop): +def test_central_nonspecific(pytester, testdir, prop): script = testdir.makepyfile(prop.code) testdir.tmpdir.join('.coveragerc').write(prop.fullconf) result = testdir.runpytest('-v', @@ -505,7 +496,7 @@ def test_cov_min_from_coveragerc(testdir): assert result.ret != 0 -def test_central_coveragerc(testdir, prop): +def test_central_coveragerc(pytester, testdir, prop): script = testdir.makepyfile(prop.code) testdir.tmpdir.join('.coveragerc').write(COVERAGERC_SOURCE + prop.conf) @@ -523,7 +514,7 @@ def test_central_coveragerc(testdir, prop): @xdist_params -def test_central_with_path_aliasing(testdir, monkeypatch, opts, prop): +def test_central_with_path_aliasing(pytester, testdir, monkeypatch, opts, prop): mod1 = testdir.mkdir('src').join('mod.py') mod1.write(SCRIPT) mod2 = testdir.mkdir('aliased').join('mod.py') @@ -557,7 +548,7 @@ def test_central_with_path_aliasing(testdir, monkeypatch, opts, prop): @xdist_params -def test_borken_cwd(testdir, monkeypatch, opts): +def test_borken_cwd(pytester, testdir, monkeypatch, opts): testdir.makepyfile(mod=''' def foobar(a, b): return a + b @@ -596,7 +587,7 @@ def test_foobar(bad): assert result.ret == 0 -def test_subprocess_with_path_aliasing(testdir, monkeypatch): +def test_subprocess_with_path_aliasing(pytester, testdir, monkeypatch): src = testdir.mkdir('src') src.join('parent_script.py').write(SCRIPT_PARENT) src.join('child_script.py').write(SCRIPT_CHILD) @@ -632,7 +623,7 @@ def test_subprocess_with_path_aliasing(testdir, monkeypatch): assert result.ret == 0 -def test_show_missing_coveragerc(testdir, prop): +def test_show_missing_coveragerc(pytester, testdir, prop): script = testdir.makepyfile(prop.code) testdir.tmpdir.join('.coveragerc').write(""" [run] @@ -675,7 +666,7 @@ def test_fail(): result.stdout.fnmatch_lines(['*1 failed*']) -def test_no_cov(testdir, monkeypatch): +def test_no_cov(pytester, testdir, monkeypatch): script = testdir.makepyfile(SCRIPT) testdir.makeini(""" [pytest] @@ -742,7 +733,7 @@ def test_foo(foo): @pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"') -def test_dist_collocated(testdir, prop): +def test_dist_collocated(pytester, testdir, prop): script = testdir.makepyfile(prop.code) testdir.tmpdir.join('.coveragerc').write(prop.fullconf) result = testdir.runpytest('-v', @@ -762,7 +753,7 @@ def test_dist_collocated(testdir, prop): @pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"') -def test_dist_not_collocated(testdir, prop): +def test_dist_not_collocated(pytester, testdir, prop): script = testdir.makepyfile(prop.code) dir1 = testdir.mkdir('dir1') dir2 = testdir.mkdir('dir2') @@ -795,7 +786,7 @@ def test_dist_not_collocated(testdir, prop): @pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"') -def test_dist_not_collocated_coveragerc_source(testdir, prop): +def test_dist_not_collocated_coveragerc_source(pytester, testdir, prop): script = testdir.makepyfile(prop.code) dir1 = testdir.mkdir('dir1') dir2 = testdir.mkdir('dir2') @@ -870,7 +861,7 @@ def test_central_subprocess_change_cwd(testdir): assert result.ret == 0 -def test_central_subprocess_change_cwd_with_pythonpath(testdir, monkeypatch): +def test_central_subprocess_change_cwd_with_pythonpath(pytester, testdir, monkeypatch): stuff = testdir.mkdir('stuff') parent_script = stuff.join('parent_script.py') parent_script.write(SCRIPT_PARENT_CHANGE_CWD_IMPORT_CHILD) @@ -941,7 +932,7 @@ def test_dist_subprocess_collocated(testdir): @pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"') -def test_dist_subprocess_not_collocated(testdir, tmpdir): +def test_dist_subprocess_not_collocated(pytester, testdir, tmpdir): scripts = testdir.makepyfile(parent_script=SCRIPT_PARENT, child_script=SCRIPT_CHILD) parent_script = scripts.dirpath().join('parent_script.py') @@ -1071,10 +1062,11 @@ def test_funcarg_not_active(testdir): @pytest.mark.skipif("sys.version_info[0] < 3", reason="no context manager api on Python 2") @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") @pytest.mark.skipif('platform.python_implementation() == "PyPy"', reason="often deadlocks on PyPy") -@method_params -def test_multiprocessing_pool(testdir, method): +@pytest.mark.parametrize('method', ['fork', 'spawn']) +@pytest.mark.xfail +def test_multiprocessing_pool(pytester, testdir, method): pytest.importorskip('multiprocessing.util') - + pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) script = testdir.makepyfile(''' import multiprocessing @@ -1084,9 +1076,6 @@ def target_fn(a): def test_run_target(): multiprocessing.set_start_method({!r}) - from pytest_cov.embed import cleanup_on_sigterm - cleanup_on_sigterm() - for i in range(33): with multiprocessing.Pool(3) as p: p.map(target_fn, [i * 3 + j for j in range(3)]) @@ -1102,21 +1091,21 @@ def test_run_target(): assert "Doesn't seem to be a coverage.py data file" not in result.stdout.str() assert "Doesn't seem to be a coverage.py data file" not in result.stderr.str() - assert not testdir.tmpdir.listdir(".coverage.*") result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_multiprocessing_pool* 100%*', '*1 passed*' ]) + assert not testdir.tmpdir.listdir(".coverage.*") assert result.ret == 0 @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") @pytest.mark.skipif('platform.python_implementation() == "PyPy"', reason="often deadlocks on PyPy") -@method_params -def test_multiprocessing_pool_terminate(testdir, method): +@pytest.mark.parametrize('method', ['fork', 'spawn']) +def test_multiprocessing_pool_terminate(pytester, testdir, method): pytest.importorskip('multiprocessing.util') - + pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) script = testdir.makepyfile(''' import multiprocessing @@ -1126,8 +1115,6 @@ def target_fn(a): def test_run_target(): multiprocessing.set_start_method({!r}) - from pytest_cov.embed import cleanup_on_sigterm - cleanup_on_sigterm() for i in range(33): p = multiprocessing.Pool(3) @@ -1147,21 +1134,21 @@ def test_run_target(): assert "Doesn't seem to be a coverage.py data file" not in result.stdout.str() assert "Doesn't seem to be a coverage.py data file" not in result.stderr.str() - assert not testdir.tmpdir.listdir(".coverage.*") result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_multiprocessing_pool* 100%*', '*1 passed*' ]) + assert not testdir.tmpdir.listdir(".coverage.*") assert result.ret == 0 @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") @pytest.mark.skipif('sys.version_info[0] > 2 and platform.python_implementation() == "PyPy"', reason="broken on PyPy3") -@method_params -def test_multiprocessing_pool_close(testdir, method): +@pytest.mark.parametrize('method', ['fork', 'spawn']) +def test_multiprocessing_pool_close(pytester, testdir, method): pytest.importorskip('multiprocessing.util') - + pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) script = testdir.makepyfile(''' import multiprocessing @@ -1188,20 +1175,20 @@ def test_run_target(): script) assert "Doesn't seem to be a coverage.py data file" not in result.stdout.str() assert "Doesn't seem to be a coverage.py data file" not in result.stderr.str() - assert not testdir.tmpdir.listdir(".coverage.*") result.stdout.fnmatch_lines([ '*- coverage: platform *, python * -*', 'test_multiprocessing_pool* 100%*', '*1 passed*' ]) + # assert not testdir.tmpdir.listdir(".coverage.*") assert result.ret == 0 @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -@method_params -def test_multiprocessing_process(testdir, method): +@pytest.mark.parametrize('method', ['fork', 'spawn']) +def test_multiprocessing_process(pytester, testdir, method): pytest.importorskip('multiprocessing.util') - + pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) script = testdir.makepyfile(''' import multiprocessing @@ -1230,9 +1217,9 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -def test_multiprocessing_process_no_source(testdir): +def test_multiprocessing_process_no_source(pytester, testdir): pytest.importorskip('multiprocessing.util') - + pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) script = testdir.makepyfile(''' import multiprocessing @@ -1260,9 +1247,9 @@ def test_run_target(): @pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -def test_multiprocessing_process_with_terminate(testdir): +def test_multiprocessing_process_with_terminate(pytester, testdir): pytest.importorskip('multiprocessing.util') - + pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) script = testdir.makepyfile(''' import multiprocessing import time @@ -1349,7 +1336,7 @@ def test_run(): ('cleanup_on_signal(signal.SIGBREAK)', '87% 21-22'), ('cleanup()', '73% 19-22'), ]) -def test_cleanup_on_sigterm_sig_break(testdir, setup): +def test_cleanup_on_sigterm_sig_break(pytester, testdir, setup): # worth a read: https://stefan.sofa-rockers.org/2013/08/15/handling-sub-process-hierarchies-python-linux-os-x/ script = testdir.makepyfile(''' import os, signal, subprocess, sys, time @@ -1395,7 +1382,7 @@ def test_run(): ('cleanup_on_sigterm()', '88% 18-19'), ('cleanup()', '75% 16-19'), ]) -def test_cleanup_on_sigterm_sig_dfl(testdir, setup): +def test_cleanup_on_sigterm_sig_dfl(pytester, testdir, setup): script = testdir.makepyfile(''' import os, signal, subprocess, sys, time @@ -1551,7 +1538,7 @@ def test_cover_conftest(testdir): @pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"') -def test_cover_looponfail(testdir, monkeypatch): +def test_cover_looponfail(pytester, testdir, monkeypatch): testdir.makepyfile(mod=MODULE) testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) @@ -1559,9 +1546,9 @@ def test_cover_looponfail(testdir, monkeypatch): def mock_run(*args, **kwargs): return _TestProcess(*map(str, args)) - monkeypatch.setattr(testdir, 'run', mock_run) + monkeypatch.setattr(pytester, testdir, 'run', mock_run) assert testdir.run is mock_run - if hasattr(testdir, '_pytester'): + if hasattr(pytester, testdir, '_pytester'): monkeypatch.setattr(testdir._pytester, 'run', mock_run) assert testdir._pytester.run is mock_run with testdir.runpytest('-v', @@ -1637,7 +1624,13 @@ def test_basic(no_cover): # Regexes for lines to exclude from consideration exclude_lines = raise NotImplementedError +''' +MP_COVERAGERC = ''' +[run] +concurrency = multiprocessing +parallel = true +sigterm = True ''' EXCLUDED_TEST = ''' @@ -1704,7 +1697,7 @@ def test_basic(): @pytest.mark.parametrize('report_option', [ 'term-missing:skip-covered', 'term:skip-covered']) -def test_skip_covered_cli(testdir, report_option): +def test_skip_covered_cli(pytester, testdir, report_option): testdir.makefile('', coveragerc=SKIP_COVERED_COVERAGERC) script = testdir.makepyfile(SKIP_COVERED_TEST) result = testdir.runpytest('-v', @@ -1910,7 +1903,7 @@ def test_external_data_file_negative(testdir): @xdist_params -def test_append_coverage(testdir, opts, prop): +def test_append_coverage(pytester, testdir, opts, prop): script = testdir.makepyfile(test_1=prop.code) testdir.tmpdir.join('.coveragerc').write(prop.fullconf) result = testdir.runpytest('-v', @@ -1933,7 +1926,7 @@ def test_append_coverage(testdir, opts, prop): @xdist_params -def test_do_not_append_coverage(testdir, opts, prop): +def test_do_not_append_coverage(pytester, testdir, opts, prop): script = testdir.makepyfile(test_1=prop.code) testdir.tmpdir.join('.coveragerc').write(prop.fullconf) result = testdir.runpytest('-v', @@ -2115,7 +2108,7 @@ def find_labels(text, pattern): @pytest.mark.skipif("coverage.version_info < (5, 0)") @xdist_params -def test_contexts(testdir, opts): +def test_contexts(pytester, testdir, opts): with open(os.path.join(os.path.dirname(__file__), "contextful.py")) as f: contextful_tests = f.read() script = testdir.makepyfile(contextful_tests) From dd6f64578efe5c4386026b0606f7776a71854735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 23:34:45 +0300 Subject: [PATCH 11/20] Reveert this change that wastes me time typing up full paths. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 88a2b63a..e283165c 100644 --- a/tox.ini +++ b/tox.ini @@ -65,7 +65,7 @@ deps = {env:_DEP_COVERAGE:coverage} pip_pre = true commands = - pytest {posargs:-vv} + {posargs:pytest -vv} [testenv:spell] setenv = From ea006d654c88d5d71bd2c13203f0d3abc07b0b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 23:36:52 +0300 Subject: [PATCH 12/20] Throwing in the towel. I don't care anymore. I don't see any workarounds for https://github.com/python/cpython/issues/82408. --- tests/test_pytest_cov.py | 226 --------------------------------------- 1 file changed, 226 deletions(-) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index edf0fe6e..1cb68577 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1059,232 +1059,6 @@ def test_funcarg_not_active(testdir): assert result.ret == 0 -@pytest.mark.skipif("sys.version_info[0] < 3", reason="no context manager api on Python 2") -@pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -@pytest.mark.skipif('platform.python_implementation() == "PyPy"', reason="often deadlocks on PyPy") -@pytest.mark.parametrize('method', ['fork', 'spawn']) -@pytest.mark.xfail -def test_multiprocessing_pool(pytester, testdir, method): - pytest.importorskip('multiprocessing.util') - pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) - script = testdir.makepyfile(''' -import multiprocessing - -def target_fn(a): - {}se: # pragma: nocover - return None - -def test_run_target(): - multiprocessing.set_start_method({!r}) - for i in range(33): - with multiprocessing.Pool(3) as p: - p.map(target_fn, [i * 3 + j for j in range(3)]) - p.join() -'''.format(''.join('''if a == %r: - return a - el''' % i for i in range(99)), method)) - - result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), - '--cov-report=term-missing', - script) - - assert "Doesn't seem to be a coverage.py data file" not in result.stdout.str() - assert "Doesn't seem to be a coverage.py data file" not in result.stderr.str() - result.stdout.fnmatch_lines([ - '*- coverage: platform *, python * -*', - 'test_multiprocessing_pool* 100%*', - '*1 passed*' - ]) - assert not testdir.tmpdir.listdir(".coverage.*") - assert result.ret == 0 - - -@pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -@pytest.mark.skipif('platform.python_implementation() == "PyPy"', reason="often deadlocks on PyPy") -@pytest.mark.parametrize('method', ['fork', 'spawn']) -def test_multiprocessing_pool_terminate(pytester, testdir, method): - pytest.importorskip('multiprocessing.util') - pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) - script = testdir.makepyfile(''' -import multiprocessing - -def target_fn(a): - {}se: # pragma: nocover - return None - -def test_run_target(): - multiprocessing.set_start_method({!r}) - - for i in range(33): - p = multiprocessing.Pool(3) - try: - p.map(target_fn, [i * 3 + j for j in range(3)]) - finally: - p.terminate() - p.join() -'''.format(''.join('''if a == %r: - return a - el''' % i for i in range(99)), method)) - - result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), - '--cov-report=term-missing', - script) - - assert "Doesn't seem to be a coverage.py data file" not in result.stdout.str() - assert "Doesn't seem to be a coverage.py data file" not in result.stderr.str() - result.stdout.fnmatch_lines([ - '*- coverage: platform *, python * -*', - 'test_multiprocessing_pool* 100%*', - '*1 passed*' - ]) - assert not testdir.tmpdir.listdir(".coverage.*") - assert result.ret == 0 - - -@pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -@pytest.mark.skipif('sys.version_info[0] > 2 and platform.python_implementation() == "PyPy"', reason="broken on PyPy3") -@pytest.mark.parametrize('method', ['fork', 'spawn']) -def test_multiprocessing_pool_close(pytester, testdir, method): - pytest.importorskip('multiprocessing.util') - pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) - script = testdir.makepyfile(''' -import multiprocessing - -def target_fn(a): - {}se: # pragma: nocover - return None - -def test_run_target(): - multiprocessing.set_start_method({!r}) - for i in range(33): - p = multiprocessing.Pool(3) - try: - p.map(target_fn, [i * 3 + j for j in range(3)]) - finally: - p.close() - p.join() -'''.format(''.join('''if a == %r: - return a - el''' % i for i in range(99)), method)) - - result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), - '--cov-report=term-missing', - script) - assert "Doesn't seem to be a coverage.py data file" not in result.stdout.str() - assert "Doesn't seem to be a coverage.py data file" not in result.stderr.str() - result.stdout.fnmatch_lines([ - '*- coverage: platform *, python * -*', - 'test_multiprocessing_pool* 100%*', - '*1 passed*' - ]) - # assert not testdir.tmpdir.listdir(".coverage.*") - assert result.ret == 0 - - -@pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -@pytest.mark.parametrize('method', ['fork', 'spawn']) -def test_multiprocessing_process(pytester, testdir, method): - pytest.importorskip('multiprocessing.util') - pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) - script = testdir.makepyfile(''' -import multiprocessing - -def target_fn(): - a = True - return a - -def test_run_target(): - multiprocessing.set_start_method({!r}) - p = multiprocessing.Process(target=target_fn) - p.start() - p.join() -'''.format(method)) - - result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), - '--cov-report=term-missing', - script) - - result.stdout.fnmatch_lines([ - '*- coverage: platform *, python * -*', - 'test_multiprocessing_process* 9 * 100%*', - '*1 passed*' - ]) - assert result.ret == 0 - - -@pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -def test_multiprocessing_process_no_source(pytester, testdir): - pytest.importorskip('multiprocessing.util') - pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) - script = testdir.makepyfile(''' -import multiprocessing - -def target_fn(): - a = True - return a - -def test_run_target(): - p = multiprocessing.Process(target=target_fn) - p.start() - p.join() -''') - - result = testdir.runpytest('-v', - '--cov', - '--cov-report=term-missing', - script) - - result.stdout.fnmatch_lines([ - '*- coverage: platform *, python * -*', - 'test_multiprocessing_process* 8 * 100%*', - '*1 passed*' - ]) - assert result.ret == 0 - - -@pytest.mark.skipif('sys.platform == "win32"', reason="multiprocessing support is broken on Windows") -def test_multiprocessing_process_with_terminate(pytester, testdir): - pytest.importorskip('multiprocessing.util') - pytester.path.joinpath(".coveragerc").write_text(MP_COVERAGERC) - script = testdir.makepyfile(''' -import multiprocessing -import time -from pytest_cov.embed import cleanup_on_sigterm -cleanup_on_sigterm() - -event = multiprocessing.Event() - -def target_fn(): - a = True - event.set() - time.sleep(5) - -def test_run_target(): - p = multiprocessing.Process(target=target_fn) - p.start() - time.sleep(0.5) - event.wait(1) - p.terminate() - p.join() -''') - - result = testdir.runpytest('-v', - '--cov=%s' % script.dirpath(), - '--cov-report=term-missing', - script) - - result.stdout.fnmatch_lines([ - '*- coverage: platform *, python * -*', - 'test_multiprocessing_process* 16 * 100%*', - '*1 passed*' - ]) - assert result.ret == 0 - - @pytest.mark.skipif('sys.platform == "win32"', reason="SIGTERM isn't really supported on Windows") def test_cleanup_on_sigterm(testdir): script = testdir.makepyfile(''' From 699ba71cef1a94ec1d8343357996df1117a9bbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 23:51:29 +0300 Subject: [PATCH 13/20] Fix bad refactor. --- tests/test_pytest_cov.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 1cb68577..5bf7987c 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1312,7 +1312,7 @@ def test_cover_conftest(testdir): @pytest.mark.skipif('sys.platform == "win32" and platform.python_implementation() == "PyPy"') -def test_cover_looponfail(pytester, testdir, monkeypatch): +def test_cover_looponfail(testdir, monkeypatch): testdir.makepyfile(mod=MODULE) testdir.makeconftest(CONFTEST) script = testdir.makepyfile(BASIC_TEST) @@ -1320,9 +1320,9 @@ def test_cover_looponfail(pytester, testdir, monkeypatch): def mock_run(*args, **kwargs): return _TestProcess(*map(str, args)) - monkeypatch.setattr(pytester, testdir, 'run', mock_run) + monkeypatch.setattr(testdir, 'run', mock_run) assert testdir.run is mock_run - if hasattr(pytester, testdir, '_pytester'): + if hasattr(testdir, '_pytester'): monkeypatch.setattr(testdir._pytester, 'run', mock_run) assert testdir._pytester.run is mock_run with testdir.runpytest('-v', From 2823819bcd0dbaf5dcd55b2b53835dfe202b8495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Thu, 21 Jul 2022 23:57:44 +0300 Subject: [PATCH 14/20] Update changelog and remove last cruft. --- CHANGELOG.rst | 15 ++++++++++++++- tests/test_pytest_cov.py | 7 ------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e559ebb4..6dbf514b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,12 +2,25 @@ Changelog ========= -3.1.0 (future) +4.0.0 (future) ------------------- +**Note that this release drops support for multiprocessing.** + + * `--cov-fail-under` no longer causes `pytest --collect-only` to fail Contributed by Zac Hatfield-Dodds in `#511 `_. +* Dropped support for multiprocessing (mostly because `issue 82408 `_). This feature was + mostly working but made out test suite very flaky and slow. + + There is builtin multiprocessing support in coverage and you can switch to that if you feel lucky. All you need is this in your + ``.coveragerc``:: + + [run] + concurrency = multiprocessing + parallel = true + sigterm = true 3.0.0 (2021-10-04) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 5bf7987c..219dd868 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1400,13 +1400,6 @@ def test_basic(no_cover): raise NotImplementedError ''' -MP_COVERAGERC = ''' -[run] -concurrency = multiprocessing -parallel = true -sigterm = True -''' - EXCLUDED_TEST = ''' def func(): From dce892fb9aa73847c709f8a9feb0b061afe28ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 22 Jul 2022 00:08:47 +0300 Subject: [PATCH 15/20] Fix pypy envs. --- .github/workflows/test.yml | 42 +++++++++++++++++++++++++++----------- tox.ini | 2 +- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c182389..42ef1b2b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -109,23 +109,41 @@ jobs: python_arch: 'x64' tox_env: 'py310-pytest71-xdist250-coverage64' os: 'macos-latest' - - name: 'pypy3-pytest71-xdist250-coverage64 (ubuntu)' - python: 'pypy-3.' - toxpython: 'pypy3.' + - name: 'pypy37-pytest71-xdist250-coverage64 (ubuntu)' + python: 'pypy-3.7' + toxpython: 'pypy3.7' python_arch: 'x64' - tox_env: 'pypy3-pytest71-xdist250-coverage64' + tox_env: 'pypy37-pytest71-xdist250-coverage64' os: 'ubuntu-latest' - - name: 'pypy3-pytest71-xdist250-coverage64 (windows)' - python: 'pypy-3.' - toxpython: 'pypy3.' + - name: 'pypy37-pytest71-xdist250-coverage64 (windows)' + python: 'pypy-3.7' + toxpython: 'pypy3.7' python_arch: 'x64' - tox_env: 'pypy3-pytest71-xdist250-coverage64' + tox_env: 'pypy37-pytest71-xdist250-coverage64' os: 'windows-latest' - - name: 'pypy3-pytest71-xdist250-coverage64 (macos)' - python: 'pypy-3.' - toxpython: 'pypy3.' + - name: 'pypy37-pytest71-xdist250-coverage64 (macos)' + python: 'pypy-3.7' + toxpython: 'pypy3.7' python_arch: 'x64' - tox_env: 'pypy3-pytest71-xdist250-coverage64' + tox_env: 'pypy37-pytest71-xdist250-coverage64' + os: 'macos-latest' + - name: 'pypy38-pytest71-xdist250-coverage64 (ubuntu)' + python: 'pypy-3.8' + toxpython: 'pypy3.8' + python_arch: 'x64' + tox_env: 'pypy38-pytest71-xdist250-coverage64' + os: 'ubuntu-latest' + - name: 'pypy38-pytest71-xdist250-coverage64 (windows)' + python: 'pypy-3.8' + toxpython: 'pypy3.8' + python_arch: 'x64' + tox_env: 'pypy38-pytest71-xdist250-coverage64' + os: 'windows-latest' + - name: 'pypy38-pytest71-xdist250-coverage64 (macos)' + python: 'pypy-3.8' + toxpython: 'pypy3.8' + python_arch: 'x64' + tox_env: 'pypy38-pytest71-xdist250-coverage64' os: 'macos-latest' steps: - uses: actions/checkout@v2 diff --git a/tox.ini b/tox.ini index e283165c..282cd244 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ passenv = envlist = check py{36}-pytest{70}-xdist250-coverage{62} - py{37,38,39,310,py3}-pytest{71}-xdist250-coverage{64} + py{37,38,39,310,py37,py38}-pytest{71}-xdist250-coverage{64} docs [testenv] From b5788904e5c4684b28ea593838e1622a95cb31c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 22 Jul 2022 00:57:59 +0300 Subject: [PATCH 16/20] Add an xfail. --- tests/test_pytest_cov.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 219dd868..22991c9a 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1060,6 +1060,7 @@ def test_funcarg_not_active(testdir): @pytest.mark.skipif('sys.platform == "win32"', reason="SIGTERM isn't really supported on Windows") +@pytest.mark.xfail('platform.python_implementation() == "PyPy"', reason="Interpreter seems buggy") def test_cleanup_on_sigterm(testdir): script = testdir.makepyfile(''' import os, signal, subprocess, sys, time From d5a566c7860e2d258d92b573e8d952cd534aedbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 22 Jul 2022 00:58:05 +0300 Subject: [PATCH 17/20] Give proper name to workflow. --- .github/workflows/test.yml | 2 +- ci/templates/.github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 42ef1b2b..3ad0bb49 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: build +name: Tests on: [push, pull_request] jobs: test: diff --git a/ci/templates/.github/workflows/test.yml b/ci/templates/.github/workflows/test.yml index 96d24801..fda6886a 100644 --- a/ci/templates/.github/workflows/test.yml +++ b/ci/templates/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: build +name: Tests on: [push, pull_request] jobs: test: From 3e859e4db09507825841ce04a8378eee1cfe1378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 22 Jul 2022 01:22:34 +0300 Subject: [PATCH 18/20] More xfails. --- tests/test_pytest_cov.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 22991c9a..6500fdec 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1152,6 +1152,7 @@ def test_run(): @pytest.mark.skipif('sys.platform == "win32"', reason="SIGTERM isn't really supported on Windows") +@pytest.mark.xfail('sys.platform == "darwin"', reason="Something weird going on Macs...") @pytest.mark.parametrize('setup', [ ('signal.signal(signal.SIGTERM, signal.SIG_DFL); cleanup_on_sigterm()', '88% 18-19'), ('cleanup_on_sigterm()', '88% 18-19'), @@ -1195,6 +1196,7 @@ def test_run(): @pytest.mark.skipif('sys.platform == "win32"', reason="SIGINT is subtly broken on Windows") +@pytest.mark.xfail('sys.platform == "darwin"', reason="Something weird going on Macs...") def test_cleanup_on_sigterm_sig_dfl_sigint(testdir): script = testdir.makepyfile(''' import os, signal, subprocess, sys, time From d4b30640e59b9596ee668d54c0b4c0e4da73be07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 22 Jul 2022 02:00:54 +0300 Subject: [PATCH 19/20] More xfails. --- tests/test_pytest_cov.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 6500fdec..fd544345 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1153,6 +1153,7 @@ def test_run(): @pytest.mark.skipif('sys.platform == "win32"', reason="SIGTERM isn't really supported on Windows") @pytest.mark.xfail('sys.platform == "darwin"', reason="Something weird going on Macs...") +@pytest.mark.xfail('platform.python_implementation() == "PyPy"', reason="Interpreter seems buggy") @pytest.mark.parametrize('setup', [ ('signal.signal(signal.SIGTERM, signal.SIG_DFL); cleanup_on_sigterm()', '88% 18-19'), ('cleanup_on_sigterm()', '88% 18-19'), @@ -1236,6 +1237,7 @@ def test_run(): @pytest.mark.skipif('sys.platform == "win32"', reason="fork not available on Windows") +@pytest.mark.xfail('platform.python_implementation() == "PyPy"', reason="Interpreter seems buggy") def test_cleanup_on_sigterm_sig_ign(testdir): script = testdir.makepyfile(''' import os, signal, subprocess, sys, time From 46af255c36b1185fef0e466acc135aaa9721bbc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 22 Jul 2022 08:44:18 +0300 Subject: [PATCH 20/20] Even more xfails. --- tests/test_pytest_cov.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index fd544345..4402fc7b 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1198,6 +1198,7 @@ def test_run(): @pytest.mark.skipif('sys.platform == "win32"', reason="SIGINT is subtly broken on Windows") @pytest.mark.xfail('sys.platform == "darwin"', reason="Something weird going on Macs...") +@pytest.mark.xfail('platform.python_implementation() == "PyPy"', reason="Interpreter seems buggy") def test_cleanup_on_sigterm_sig_dfl_sigint(testdir): script = testdir.makepyfile(''' import os, signal, subprocess, sys, time