Merge master into features (#6458)

Merge master into features
This commit is contained in:
Bruno Oliveira 2020-01-14 20:06:51 -03:00 committed by GitHub
commit f2659f77be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 134 additions and 34 deletions

View File

@ -1,8 +1,7 @@
# evaluating GitHub actions for CI, disconsider failures when evaluating PRs # evaluating GitHub actions for CI, disregard failures when evaluating PRs
# #
# this is still missing: # this is still missing:
# - deploy # - deploy
# - coverage
# - upload github notes # - upload github notes
# #
name: main name: main
@ -11,13 +10,14 @@ on:
push: push:
branches: branches:
- master - master
- features
pull_request: pull_request:
branches: branches:
- master - master
- features
jobs: jobs:
build: build:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
@ -86,6 +86,8 @@ jobs:
python: "3.7" python: "3.7"
os: ubuntu-latest os: ubuntu-latest
tox_env: "py37-freeze" tox_env: "py37-freeze"
# coverage does not apply for freeze test, skip it
skip_coverage: true
- name: "ubuntu-py38" - name: "ubuntu-py38"
python: "3.8" python: "3.8"
os: ubuntu-latest os: ubuntu-latest
@ -94,6 +96,8 @@ jobs:
python: "pypy3" python: "pypy3"
os: ubuntu-latest os: ubuntu-latest
tox_env: "pypy3-xdist" tox_env: "pypy3-xdist"
# coverage too slow with pypy3, skip it
skip_coverage: true
- name: "macos-py37" - name: "macos-py37"
python: "3.7" python: "3.7"
@ -118,6 +122,37 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install tox pip install tox coverage
- name: Test
run: tox -e ${{ matrix.tox_env }} - name: Test without coverage
if: "matrix.skip_coverage"
run: "tox -e ${{ matrix.tox_env }}"
- name: Test with coverage
if: "! matrix.skip_coverage"
env:
_PYTEST_TOX_COVERAGE_RUN: "coverage run -m"
COVERAGE_PROCESS_START: ".coveragerc"
_PYTEST_TOX_EXTRA_DEP: "coverage-enable-subprocess"
run: "tox -e ${{ matrix.tox_env }}"
- name: Prepare coverage token
if: success() && !matrix.skip_coverage && ( github.repository == 'pytest-dev/pytest' || github.event_name == 'pull_request' )
run: |
python scripts/append_codecov_token.py
- name: Combine coverage
if: success() && !matrix.skip_coverage
run: |
python -m coverage combine
python -m coverage xml
- name: Codecov upload
if: success() && !matrix.skip_coverage
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.codecov }}
file: ./coverage.xml
flags: ${{ runner.os }}
fail_ci_if_error: false
name: ${{ matrix.name }}

View File

@ -52,8 +52,10 @@ jobs:
- env: TOXENV=pypy3-xdist - env: TOXENV=pypy3-xdist
python: 'pypy3' python: 'pypy3'
- env: TOXENV=py35-xdist # Coverage for Python 3.5.{0,1} specific code, mostly typing related.
python: '3.5' - env: TOXENV=py35 PYTEST_COVERAGE=1 PYTEST_ADDOPTS="-k test_raises_cyclic_reference"
python: '3.5.1'
dist: trusty
# Specialized factors for py37. # Specialized factors for py37.
- env: TOXENV=py37-pluggymaster-xdist - env: TOXENV=py37-pluggymaster-xdist

View File

@ -0,0 +1,36 @@
"""
Appends the codecov token to the 'codecov.yml' file at the root of the repository.
This is done by CI during PRs and builds on the pytest-dev repository so we can upload coverage, at least
until codecov grows some native integration like it has with Travis and AppVeyor.
See discussion in https://github.com/pytest-dev/pytest/pull/6441 for more information.
"""
import os.path
from textwrap import dedent
def main():
this_dir = os.path.dirname(__file__)
cov_file = os.path.join(this_dir, "..", "codecov.yml")
assert os.path.isfile(cov_file), "{cov_file} does not exist".format(
cov_file=cov_file
)
with open(cov_file, "a") as f:
# token from: https://codecov.io/gh/pytest-dev/pytest/settings
# use same URL to regenerate it if needed
text = dedent(
"""
codecov:
token: "1eca3b1f-31a2-4fb8-a8c3-138b441b50a7"
"""
)
f.write(text)
print("Token updated:", cov_file)
if __name__ == "__main__":
main()

View File

@ -382,7 +382,7 @@ class CaptureAndPassthroughIO(CaptureIO):
return self._other.write(s) return self._other.write(s)
if sys.version_info < (3, 5, 2): # pragma: no cover if sys.version_info < (3, 5, 2):
def overload(f): # noqa: F811 def overload(f): # noqa: F811
return f return f

View File

@ -108,7 +108,7 @@ CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supporte
def determine_setup( def determine_setup(
inifile: str, inifile: Optional[str],
args: List[str], args: List[str],
rootdir_cmd_arg: Optional[str] = None, rootdir_cmd_arg: Optional[str] = None,
config: Optional["Config"] = None, config: Optional["Config"] = None,

View File

@ -166,7 +166,7 @@ class TestRaises:
# Early versions of Python 3.5 have some bug causing the # Early versions of Python 3.5 have some bug causing the
# __call__ frame to still refer to t even after everything # __call__ frame to still refer to t even after everything
# is done. This makes the test pass for them. # is done. This makes the test pass for them.
if sys.version_info < (3, 5, 2): # pragma: no cover if sys.version_info < (3, 5, 2):
del self del self
raise ValueError raise ValueError

View File

@ -859,7 +859,7 @@ class TestRootdir:
assert get_common_ancestor([no_path.join("a")]) == tmpdir assert get_common_ancestor([no_path.join("a")]) == tmpdir
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
def test_with_ini(self, tmpdir, name): def test_with_ini(self, tmpdir, name) -> None:
inifile = tmpdir.join(name) inifile = tmpdir.join(name)
inifile.write("[pytest]\n" if name != "setup.cfg" else "[tool:pytest]\n") inifile.write("[pytest]\n" if name != "setup.cfg" else "[tool:pytest]\n")
@ -874,7 +874,7 @@ class TestRootdir:
assert inifile == inifile assert inifile == inifile
@pytest.mark.parametrize("name", "setup.cfg tox.ini".split()) @pytest.mark.parametrize("name", "setup.cfg tox.ini".split())
def test_pytestini_overrides_empty_other(self, tmpdir, name): def test_pytestini_overrides_empty_other(self, tmpdir, name) -> None:
inifile = tmpdir.ensure("pytest.ini") inifile = tmpdir.ensure("pytest.ini")
a = tmpdir.mkdir("a") a = tmpdir.mkdir("a")
a.ensure(name) a.ensure(name)
@ -882,7 +882,7 @@ class TestRootdir:
assert rootdir == tmpdir assert rootdir == tmpdir
assert inifile == inifile assert inifile == inifile
def test_setuppy_fallback(self, tmpdir): def test_setuppy_fallback(self, tmpdir) -> None:
a = tmpdir.mkdir("a") a = tmpdir.mkdir("a")
a.ensure("setup.cfg") a.ensure("setup.cfg")
tmpdir.ensure("setup.py") tmpdir.ensure("setup.py")
@ -891,14 +891,14 @@ class TestRootdir:
assert inifile is None assert inifile is None
assert inicfg == {} assert inicfg == {}
def test_nothing(self, tmpdir, monkeypatch): def test_nothing(self, tmpdir, monkeypatch) -> None:
monkeypatch.chdir(str(tmpdir)) monkeypatch.chdir(str(tmpdir))
rootdir, inifile, inicfg = determine_setup(None, [tmpdir]) rootdir, inifile, inicfg = determine_setup(None, [tmpdir])
assert rootdir == tmpdir assert rootdir == tmpdir
assert inifile is None assert inifile is None
assert inicfg == {} assert inicfg == {}
def test_with_specific_inifile(self, tmpdir): def test_with_specific_inifile(self, tmpdir) -> None:
inifile = tmpdir.ensure("pytest.ini") inifile = tmpdir.ensure("pytest.ini")
rootdir, inifile, inicfg = determine_setup(inifile, [tmpdir]) rootdir, inifile, inicfg = determine_setup(inifile, [tmpdir])
assert rootdir == tmpdir assert rootdir == tmpdir
@ -1039,7 +1039,7 @@ class TestOverrideIniArgs:
result = testdir.runpytest("--override-ini", "python_files=unittest_*.py") result = testdir.runpytest("--override-ini", "python_files=unittest_*.py")
result.stdout.fnmatch_lines(["*1 passed in*"]) result.stdout.fnmatch_lines(["*1 passed in*"])
def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch): def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch) -> None:
monkeypatch.chdir(str(tmpdir)) monkeypatch.chdir(str(tmpdir))
a = tmpdir.mkdir("a") a = tmpdir.mkdir("a")
b = tmpdir.mkdir("b") b = tmpdir.mkdir("b")
@ -1047,7 +1047,7 @@ class TestOverrideIniArgs:
assert rootdir == tmpdir assert rootdir == tmpdir
assert inifile is None assert inifile is None
def test_with_arg_outside_cwd_with_inifile(self, tmpdir): def test_with_arg_outside_cwd_with_inifile(self, tmpdir) -> None:
a = tmpdir.mkdir("a") a = tmpdir.mkdir("a")
b = tmpdir.mkdir("b") b = tmpdir.mkdir("b")
inifile = a.ensure("pytest.ini") inifile = a.ensure("pytest.ini")
@ -1056,13 +1056,13 @@ class TestOverrideIniArgs:
assert inifile == parsed_inifile assert inifile == parsed_inifile
@pytest.mark.parametrize("dirs", ([], ["does-not-exist"], ["a/does-not-exist"])) @pytest.mark.parametrize("dirs", ([], ["does-not-exist"], ["a/does-not-exist"]))
def test_with_non_dir_arg(self, dirs, tmpdir): def test_with_non_dir_arg(self, dirs, tmpdir) -> None:
with tmpdir.ensure(dir=True).as_cwd(): with tmpdir.ensure(dir=True).as_cwd():
rootdir, inifile, inicfg = determine_setup(None, dirs) rootdir, inifile, inicfg = determine_setup(None, dirs)
assert rootdir == tmpdir assert rootdir == tmpdir
assert inifile is None assert inifile is None
def test_with_existing_file_in_subdir(self, tmpdir): def test_with_existing_file_in_subdir(self, tmpdir) -> None:
a = tmpdir.mkdir("a") a = tmpdir.mkdir("a")
a.ensure("exist") a.ensure("exist")
with tmpdir.as_cwd(): with tmpdir.as_cwd():

View File

@ -1,3 +1,5 @@
import sys
import pytest import pytest
from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionChainRepr
from _pytest.pathlib import Path from _pytest.pathlib import Path
@ -314,15 +316,39 @@ class TestReportSerialization:
# elsewhere and we do check the contents of the longrepr object after loading it. # elsewhere and we do check the contents of the longrepr object after loading it.
loaded_report.longrepr.toterminal(tw_mock) loaded_report.longrepr.toterminal(tw_mock)
def test_chained_exceptions_no_reprcrash( def test_chained_exceptions_no_reprcrash(self, testdir, tw_mock):
self, testdir, tw_mock,
):
"""Regression test for tracebacks without a reprcrash (#5971) """Regression test for tracebacks without a reprcrash (#5971)
This happens notably on exceptions raised by multiprocess.pool: the exception transfer This happens notably on exceptions raised by multiprocess.pool: the exception transfer
from subprocess to main process creates an artificial exception, which ExceptionInfo from subprocess to main process creates an artificial exception, which ExceptionInfo
can't obtain the ReprFileLocation from. can't obtain the ReprFileLocation from.
""" """
# somehow in Python 3.5 on Windows this test fails with:
# File "c:\...\3.5.4\x64\Lib\multiprocessing\connection.py", line 302, in _recv_bytes
# overlapped=True)
# OSError: [WinError 6] The handle is invalid
#
# so in this platform we opted to use a mock traceback which is identical to the
# one produced by the multiprocessing module
if sys.version_info[:2] <= (3, 5) and sys.platform.startswith("win"):
testdir.makepyfile(
"""
# equivalent of multiprocessing.pool.RemoteTraceback
class RemoteTraceback(Exception):
def __init__(self, tb):
self.tb = tb
def __str__(self):
return self.tb
def test_a():
try:
raise ValueError('value error')
except ValueError as e:
# equivalent to how multiprocessing.pool.rebuild_exc does it
e.__cause__ = RemoteTraceback('runtime error')
raise e
"""
)
else:
testdir.makepyfile( testdir.makepyfile(
""" """
from concurrent.futures import ProcessPoolExecutor from concurrent.futures import ProcessPoolExecutor
@ -335,6 +361,7 @@ class TestReportSerialization:
p.submit(func).result() p.submit(func).result()
""" """
) )
reprec = testdir.inline_run() reprec = testdir.inline_run()
reports = reprec.getreports("pytest_runtest_logreport") reports = reprec.getreports("pytest_runtest_logreport")

View File

@ -26,7 +26,7 @@ passenv = USER USERNAME COVERAGE_* TRAVIS PYTEST_ADDOPTS TERM
setenv = setenv =
_PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:} _PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:}
# Configuration to run with coverage similar to Travis/Appveyor, e.g. # Configuration to run with coverage similar to CI, e.g.
# "tox -e py37-coverage". # "tox -e py37-coverage".
coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m
coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
@ -53,7 +53,7 @@ deps =
skip_install = True skip_install = True
basepython = python3 basepython = python3
deps = pre-commit>=1.11.0 deps = pre-commit>=1.11.0
commands = pre-commit run --all-files --show-diff-on-failure commands = pre-commit run --all-files --show-diff-on-failure {posargs:}
[testenv:docs] [testenv:docs]
basepython = python3 basepython = python3