Merge master into features
This commit is contained in:
commit
55e5817570
|
@ -54,6 +54,7 @@ jobs:
|
||||||
python: "3.5"
|
python: "3.5"
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
tox_env: "py35-xdist"
|
tox_env: "py35-xdist"
|
||||||
|
use_coverage: true
|
||||||
- name: "windows-py36"
|
- name: "windows-py36"
|
||||||
python: "3.6"
|
python: "3.6"
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
|
@ -70,6 +71,7 @@ jobs:
|
||||||
python: "3.8"
|
python: "3.8"
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
tox_env: "py38"
|
tox_env: "py38"
|
||||||
|
use_coverage: true
|
||||||
|
|
||||||
- name: "ubuntu-py35"
|
- name: "ubuntu-py35"
|
||||||
python: "3.5"
|
python: "3.5"
|
||||||
|
@ -83,6 +85,7 @@ jobs:
|
||||||
python: "3.7"
|
python: "3.7"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "py37-lsof-numpy-oldattrs-pexpect-twisted"
|
tox_env: "py37-lsof-numpy-oldattrs-pexpect-twisted"
|
||||||
|
use_coverage: true
|
||||||
- name: "ubuntu-py37-pluggy"
|
- name: "ubuntu-py37-pluggy"
|
||||||
python: "3.7"
|
python: "3.7"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
|
@ -91,8 +94,6 @@ 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
|
||||||
|
@ -101,8 +102,6 @@ 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"
|
||||||
|
@ -112,21 +111,21 @@ jobs:
|
||||||
python: "3.8"
|
python: "3.8"
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
tox_env: "py38-xdist"
|
tox_env: "py38-xdist"
|
||||||
|
use_coverage: true
|
||||||
|
|
||||||
- name: "linting"
|
- name: "linting"
|
||||||
python: "3.7"
|
python: "3.7"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "linting"
|
tox_env: "linting"
|
||||||
skip_coverage: true
|
|
||||||
- name: "docs"
|
- name: "docs"
|
||||||
python: "3.7"
|
python: "3.7"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "docs"
|
tox_env: "docs"
|
||||||
skip_coverage: true
|
|
||||||
- name: "doctesting"
|
- name: "doctesting"
|
||||||
python: "3.7"
|
python: "3.7"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
tox_env: "doctesting"
|
tox_env: "doctesting"
|
||||||
|
use_coverage: true
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
|
@ -140,11 +139,11 @@ jobs:
|
||||||
pip install tox coverage
|
pip install tox coverage
|
||||||
|
|
||||||
- name: Test without coverage
|
- name: Test without coverage
|
||||||
if: "matrix.skip_coverage"
|
if: "! matrix.use_coverage"
|
||||||
run: "tox -e ${{ matrix.tox_env }}"
|
run: "tox -e ${{ matrix.tox_env }}"
|
||||||
|
|
||||||
- name: Test with coverage
|
- name: Test with coverage
|
||||||
if: "! matrix.skip_coverage"
|
if: "matrix.use_coverage"
|
||||||
env:
|
env:
|
||||||
_PYTEST_TOX_COVERAGE_RUN: "coverage run -m"
|
_PYTEST_TOX_COVERAGE_RUN: "coverage run -m"
|
||||||
COVERAGE_PROCESS_START: ".coveragerc"
|
COVERAGE_PROCESS_START: ".coveragerc"
|
||||||
|
@ -152,12 +151,12 @@ jobs:
|
||||||
run: "tox -e ${{ matrix.tox_env }}"
|
run: "tox -e ${{ matrix.tox_env }}"
|
||||||
|
|
||||||
- name: Prepare coverage token
|
- name: Prepare coverage token
|
||||||
if: (!matrix.skip_coverage && ( github.repository == 'pytest-dev/pytest' || github.event_name == 'pull_request' ))
|
if: (matrix.use_coverage && ( github.repository == 'pytest-dev/pytest' || github.event_name == 'pull_request' ))
|
||||||
run: |
|
run: |
|
||||||
python scripts/append_codecov_token.py
|
python scripts/append_codecov_token.py
|
||||||
|
|
||||||
- name: Report coverage
|
- name: Report coverage
|
||||||
if: (!matrix.skip_coverage)
|
if: (matrix.use_coverage)
|
||||||
env:
|
env:
|
||||||
CODECOV_NAME: ${{ matrix.name }}
|
CODECOV_NAME: ${{ matrix.name }}
|
||||||
run: bash scripts/report-coverage.sh -F GHA,${{ runner.os }}
|
run: bash scripts/report-coverage.sh -F GHA,${{ runner.os }}
|
||||||
|
|
1
AUTHORS
1
AUTHORS
|
@ -114,6 +114,7 @@ Guido Wesdorp
|
||||||
Guoqiang Zhang
|
Guoqiang Zhang
|
||||||
Harald Armin Massa
|
Harald Armin Massa
|
||||||
Henk-Jaap Wagenaar
|
Henk-Jaap Wagenaar
|
||||||
|
Holger Kohr
|
||||||
Hugo van Kemenade
|
Hugo van Kemenade
|
||||||
Hui Wang (coldnight)
|
Hui Wang (coldnight)
|
||||||
Ian Bicking
|
Ian Bicking
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Fix bug in the comparison of request key with cached key in fixture.
|
||||||
|
|
||||||
|
A construct ``if key == cached_key:`` can fail either because ``==`` is explicitly disallowed, or for, e.g., NumPy arrays, where the result of ``a == b`` cannot generally be converted to `bool`.
|
||||||
|
The implemented fix replaces `==` with ``is``.
|
|
@ -77,12 +77,11 @@ class Code:
|
||||||
# maybe don't try this checking
|
# maybe don't try this checking
|
||||||
if not p.check():
|
if not p.check():
|
||||||
raise OSError("py.path check failed.")
|
raise OSError("py.path check failed.")
|
||||||
|
return p
|
||||||
except OSError:
|
except OSError:
|
||||||
# XXX maybe try harder like the weird logic
|
# XXX maybe try harder like the weird logic
|
||||||
# in the standard lib [linecache.updatecache] does?
|
# in the standard lib [linecache.updatecache] does?
|
||||||
p = self.raw.co_filename
|
return self.raw.co_filename
|
||||||
|
|
||||||
return p
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fullsource(self) -> Optional["Source"]:
|
def fullsource(self) -> Optional["Source"]:
|
||||||
|
|
|
@ -548,8 +548,9 @@ class FixtureRequest:
|
||||||
frameinfo = inspect.getframeinfo(frame[0])
|
frameinfo = inspect.getframeinfo(frame[0])
|
||||||
source_path = py.path.local(frameinfo.filename)
|
source_path = py.path.local(frameinfo.filename)
|
||||||
source_lineno = frameinfo.lineno
|
source_lineno = frameinfo.lineno
|
||||||
if source_path.relto(funcitem.config.rootdir):
|
rel_source_path = source_path.relto(funcitem.config.rootdir)
|
||||||
source_path_str = source_path.relto(funcitem.config.rootdir)
|
if rel_source_path:
|
||||||
|
source_path_str = rel_source_path
|
||||||
else:
|
else:
|
||||||
source_path_str = str(source_path)
|
source_path_str = str(source_path)
|
||||||
msg = (
|
msg = (
|
||||||
|
@ -896,7 +897,9 @@ class FixtureDef:
|
||||||
cached_result = getattr(self, "cached_result", None)
|
cached_result = getattr(self, "cached_result", None)
|
||||||
if cached_result is not None:
|
if cached_result is not None:
|
||||||
result, cache_key, err = cached_result
|
result, cache_key, err = cached_result
|
||||||
if my_cache_key == cache_key:
|
# note: comparison with `==` can fail (or be expensive) for e.g.
|
||||||
|
# numpy arrays (#6497)
|
||||||
|
if my_cache_key is cache_key:
|
||||||
if err is not None:
|
if err is not None:
|
||||||
_, val, tb = err
|
_, val, tb = err
|
||||||
raise val.with_traceback(tb)
|
raise val.with_traceback(tb)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.fixtures import fixture
|
from _pytest.fixtures import fixture
|
||||||
|
@ -108,7 +109,7 @@ class MonkeyPatch:
|
||||||
self._savesyspath = None
|
self._savesyspath = None
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def context(self):
|
def context(self) -> Generator["MonkeyPatch", None, None]:
|
||||||
"""
|
"""
|
||||||
Context manager that returns a new :class:`MonkeyPatch` object which
|
Context manager that returns a new :class:`MonkeyPatch` object which
|
||||||
undoes any patching done inside the ``with`` block upon exit:
|
undoes any patching done inside the ``with`` block upon exit:
|
||||||
|
|
|
@ -685,7 +685,7 @@ def raises( # noqa: F811
|
||||||
"""
|
"""
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
for exc in filterfalse(
|
for exc in filterfalse(
|
||||||
inspect.isclass, always_iterable(expected_exception, BASE_TYPE)
|
inspect.isclass, always_iterable(expected_exception, BASE_TYPE) # type: ignore[arg-type] # noqa: F821
|
||||||
):
|
):
|
||||||
msg = "exceptions must be derived from BaseException, not %s"
|
msg = "exceptions must be derived from BaseException, not %s"
|
||||||
raise TypeError(msg % type(exc))
|
raise TypeError(msg % type(exc))
|
||||||
|
|
|
@ -1102,6 +1102,38 @@ class TestFixtureUsages:
|
||||||
"*Fixture 'badscope' from test_invalid_scope.py got an unexpected scope value 'functions'"
|
"*Fixture 'badscope' from test_invalid_scope.py got an unexpected scope value 'functions'"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("scope", ["function", "session"])
|
||||||
|
def test_parameters_without_eq_semantics(self, scope, testdir):
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
class NoEq1: # fails on `a == b` statement
|
||||||
|
def __eq__(self, _):
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
class NoEq2: # fails on `if a == b:` statement
|
||||||
|
def __eq__(self, _):
|
||||||
|
class NoBool:
|
||||||
|
def __bool__(self):
|
||||||
|
raise RuntimeError
|
||||||
|
return NoBool()
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
@pytest.fixture(params=[NoEq1(), NoEq2()], scope={scope!r})
|
||||||
|
def no_eq(request):
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
def test1(no_eq):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test2(no_eq):
|
||||||
|
pass
|
||||||
|
""".format(
|
||||||
|
scope=scope
|
||||||
|
)
|
||||||
|
)
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines(["*4 passed*"])
|
||||||
|
|
||||||
def test_funcarg_parametrized_and_used_twice(self, testdir):
|
def test_funcarg_parametrized_and_used_twice(self, testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
@ -3662,13 +3694,30 @@ class TestParameterizedSubRequest:
|
||||||
" test_foos.py::test_foo",
|
" test_foos.py::test_foo",
|
||||||
"",
|
"",
|
||||||
"Requested fixture 'fix_with_param' defined in:",
|
"Requested fixture 'fix_with_param' defined in:",
|
||||||
"*fix.py:4",
|
"{}:4".format(fixfile),
|
||||||
"Requested here:",
|
"Requested here:",
|
||||||
"test_foos.py:4",
|
"test_foos.py:4",
|
||||||
"*1 failed*",
|
"*1 failed*",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# With non-overlapping rootdir, passing tests_dir.
|
||||||
|
rootdir = testdir.mkdir("rootdir")
|
||||||
|
rootdir.chdir()
|
||||||
|
result = testdir.runpytest("--rootdir", rootdir, tests_dir)
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
[
|
||||||
|
"The requested fixture has no parameter defined for test:",
|
||||||
|
" test_foos.py::test_foo",
|
||||||
|
"",
|
||||||
|
"Requested fixture 'fix_with_param' defined in:",
|
||||||
|
"{}:4".format(fixfile),
|
||||||
|
"Requested here:",
|
||||||
|
"{}:4".format(testfile),
|
||||||
|
"*1 failed*",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_pytest_fixture_setup_and_post_finalizer_hook(testdir):
|
def test_pytest_fixture_setup_and_post_finalizer_hook(testdir):
|
||||||
testdir.makeconftest(
|
testdir.makeconftest(
|
||||||
|
|
|
@ -704,3 +704,13 @@ def test_testdir_outcomes_with_multiple_errors(testdir):
|
||||||
result.assert_outcomes(error=2)
|
result.assert_outcomes(error=2)
|
||||||
|
|
||||||
assert result.parseoutcomes() == {"error": 2}
|
assert result.parseoutcomes() == {"error": 2}
|
||||||
|
|
||||||
|
|
||||||
|
def test_makefile_joins_absolute_path(testdir: Testdir) -> None:
|
||||||
|
absfile = testdir.tmpdir / "absfile"
|
||||||
|
if sys.platform == "win32":
|
||||||
|
with pytest.raises(OSError):
|
||||||
|
testdir.makepyfile(**{str(absfile): ""})
|
||||||
|
else:
|
||||||
|
p1 = testdir.makepyfile(**{str(absfile): ""})
|
||||||
|
assert str(p1) == (testdir.tmpdir / absfile) + ".py"
|
||||||
|
|
Loading…
Reference in New Issue