commit
b847d5712b
|
@ -49,8 +49,9 @@ jobs:
|
|||
# - pytester's LsofFdLeakChecker
|
||||
# - TestArgComplete (linux only)
|
||||
# - numpy
|
||||
# - old attrs
|
||||
# Empty PYTEST_ADDOPTS to run this non-verbose.
|
||||
- env: TOXENV=py37-lsof-numpy-twisted-xdist PYTEST_COVERAGE=1 PYTEST_ADDOPTS=
|
||||
- env: TOXENV=py37-lsof-oldattrs-numpy-twisted-xdist PYTEST_COVERAGE=1 PYTEST_ADDOPTS=
|
||||
|
||||
# Specialized factors for py37.
|
||||
# Coverage for:
|
||||
|
|
|
@ -18,6 +18,54 @@ with advance notice in the **Deprecations** section of releases.
|
|||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 5.2.1 (2019-10-06)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#5902 <https://github.com/pytest-dev/pytest/issues/5902>`_: Fix warnings about deprecated ``cmp`` attribute in ``attrs>=19.2``.
|
||||
|
||||
|
||||
pytest 5.2.0 (2019-09-28)
|
||||
=========================
|
||||
|
||||
Deprecations
|
||||
------------
|
||||
|
||||
- `#1682 <https://github.com/pytest-dev/pytest/issues/1682>`_: Passing arguments to pytest.fixture() as positional arguments is deprecated - pass them
|
||||
as a keyword argument instead.
|
||||
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- `#1682 <https://github.com/pytest-dev/pytest/issues/1682>`_: The ``scope`` parameter of ``@pytest.fixture`` can now be a callable that receives
|
||||
the fixture name and the ``config`` object as keyword-only parameters.
|
||||
See `the docs <https://docs.pytest.org/en/latest/fixture.html#dynamic-scope>`__ for more information.
|
||||
|
||||
|
||||
- `#5764 <https://github.com/pytest-dev/pytest/issues/5764>`_: New behavior of the ``--pastebin`` option: failures to connect to the pastebin server are reported, without failing the pytest run
|
||||
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#5806 <https://github.com/pytest-dev/pytest/issues/5806>`_: Fix "lexer" being used when uploading to bpaste.net from ``--pastebin`` to "text".
|
||||
|
||||
|
||||
- `#5884 <https://github.com/pytest-dev/pytest/issues/5884>`_: Fix ``--setup-only`` and ``--setup-show`` for custom pytest items.
|
||||
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#5056 <https://github.com/pytest-dev/pytest/issues/5056>`_: The HelpFormatter uses ``py.io.get_terminal_width`` for better width detection.
|
||||
|
||||
|
||||
pytest 5.1.3 (2019-09-18)
|
||||
=========================
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
Passing arguments to pytest.fixture() as positional arguments is deprecated - pass them
|
||||
as a keyword argument instead.
|
|
@ -1,3 +0,0 @@
|
|||
The ``scope`` parameter of ``@pytest.fixture`` can now be a callable that receives
|
||||
the fixture name and the ``config`` object as keyword-only parameters.
|
||||
See `the docs <https://docs.pytest.org/en/fixture.html#dynamic-scope>`__ for more information.
|
|
@ -1 +0,0 @@
|
|||
The HelpFormatter uses ``py.io.get_terminal_width`` for better width detection.
|
|
@ -1 +0,0 @@
|
|||
New behavior of the ``--pastebin`` option: failures to connect to the pastebin server are reported, without failing the pytest run
|
|
@ -1 +0,0 @@
|
|||
Fix "lexer" being used when uploading to bpaste.net from ``--pastebin`` to "text".
|
|
@ -6,6 +6,8 @@ Release announcements
|
|||
:maxdepth: 2
|
||||
|
||||
|
||||
release-5.2.1
|
||||
release-5.2.0
|
||||
release-5.1.3
|
||||
release-5.1.2
|
||||
release-5.1.1
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
pytest-5.2.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 5.2.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
to take a look at the CHANGELOG:
|
||||
|
||||
https://docs.pytest.org/en/latest/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
https://docs.pytest.org/en/latest/
|
||||
|
||||
As usual, you can upgrade from pypi via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Andrzej Klajnert
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Daniel Hahler
|
||||
* James Cooke
|
||||
* Michael Goerz
|
||||
* Ran Benita
|
||||
* Tomáš Chvátal
|
||||
* aklajnert
|
||||
|
||||
|
||||
Happy testing,
|
||||
The Pytest Development Team
|
|
@ -0,0 +1,23 @@
|
|||
pytest-5.2.1
|
||||
=======================================
|
||||
|
||||
pytest 5.2.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Florian Bruhin
|
||||
* Hynek Schlawack
|
||||
* Kevin J. Foley
|
||||
* tadashigaki
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
|
@ -134,10 +134,13 @@ progress output, you can write it into a configuration file:
|
|||
.. code-block:: ini
|
||||
|
||||
# content of pytest.ini or tox.ini
|
||||
# setup.cfg files should use [tool:pytest] section instead
|
||||
[pytest]
|
||||
addopts = -ra -q
|
||||
|
||||
# content of setup.cfg
|
||||
[tool:pytest]
|
||||
addopts = -ra -q
|
||||
|
||||
Alternatively, you can set a ``PYTEST_ADDOPTS`` environment variable to add command
|
||||
line options while the environment is in use:
|
||||
|
||||
|
|
|
@ -475,10 +475,10 @@ Running it results in some skips if we don't have all the python interpreters in
|
|||
.. code-block:: pytest
|
||||
|
||||
. $ pytest -rs -q multipython.py
|
||||
ssssssssssss...ssssssssssss [100%]
|
||||
ssssssssssssssssssssssss... [100%]
|
||||
========================= short test summary info ==========================
|
||||
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.5' not found
|
||||
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.7' not found
|
||||
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.6' not found
|
||||
3 passed, 24 skipped in 0.12s
|
||||
|
||||
Indirect parametrization of optional implementations/imports
|
||||
|
|
|
@ -436,7 +436,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
|||
items = [1, 2, 3]
|
||||
print("items is {!r}".format(items))
|
||||
> a, b = items.pop()
|
||||
E TypeError: 'int' object is not iterable
|
||||
E TypeError: cannot unpack non-iterable int object
|
||||
|
||||
failure_demo.py:181: TypeError
|
||||
--------------------------- Captured stdout call ---------------------------
|
||||
|
@ -516,7 +516,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
|||
def test_z2_type_error(self):
|
||||
items = 3
|
||||
> a, b = items
|
||||
E TypeError: 'int' object is not iterable
|
||||
E TypeError: cannot unpack non-iterable int object
|
||||
|
||||
failure_demo.py:222: TypeError
|
||||
______________________ TestMoreErrors.test_startswith ______________________
|
||||
|
|
|
@ -445,7 +445,7 @@ Now we can profile which test functions execute the slowest:
|
|||
|
||||
========================= slowest 3 test durations =========================
|
||||
0.30s call test_some_are_slow.py::test_funcslow2
|
||||
0.21s call test_some_are_slow.py::test_funcslow1
|
||||
0.20s call test_some_are_slow.py::test_funcslow1
|
||||
0.10s call test_some_are_slow.py::test_funcfast
|
||||
============================ 3 passed in 0.12s =============================
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ Install ``pytest``
|
|||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.6/site-packages/pytest.py
|
||||
This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.7/site-packages/pytest.py
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ the records for the ``setup`` and ``call`` stages during teardown like so:
|
|||
yield window
|
||||
for when in ("setup", "call"):
|
||||
messages = [
|
||||
x.message for x in caplog.get_records(when) if x.level == logging.WARNING
|
||||
x.message for x in caplog.get_records(when) if x.levelno == logging.WARNING
|
||||
]
|
||||
if messages:
|
||||
pytest.fail(
|
||||
|
|
|
@ -1003,7 +1003,7 @@ passed multiple times. The expected format is ``name=value``. For example::
|
|||
[pytest]
|
||||
addopts = --maxfail=2 -rf # exit after 2 failures, report fail info
|
||||
|
||||
issuing ``pytest test_hello.py`` actually means::
|
||||
issuing ``pytest test_hello.py`` actually means:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
|
|
@ -13,4 +13,5 @@ fi
|
|||
python -m coverage combine
|
||||
python -m coverage xml
|
||||
python -m coverage report -m
|
||||
bash <(curl -s https://codecov.io/bash) -Z -X gcov -X coveragepy -X search -X xcode -X gcovout -X fix -f coverage.xml
|
||||
curl -S -L --retry 6 -s https://codecov.io/bash -o codecov-upload.sh
|
||||
bash codecov-upload.sh -Z -X fix -f coverage.xml
|
||||
|
|
2
setup.py
2
setup.py
|
@ -5,7 +5,7 @@ from setuptools import setup
|
|||
INSTALL_REQUIRES = [
|
||||
"py>=1.5.0",
|
||||
"packaging",
|
||||
"attrs>=17.4.0",
|
||||
"attrs>=17.4.0", # should match oldattrs tox env.
|
||||
"more-itertools>=4.0.0",
|
||||
"atomicwrites>=1.0",
|
||||
'pathlib2>=2.2.0;python_version<"3.6"',
|
||||
|
|
|
@ -8,6 +8,7 @@ from typing import Optional
|
|||
import _pytest._code
|
||||
from _pytest import outcomes
|
||||
from _pytest._io.saferepr import saferepr
|
||||
from _pytest.compat import ATTRS_EQ_FIELD
|
||||
|
||||
# The _reprcompare attribute on the util module is used by the new assertion
|
||||
# interpretation code and assertion rewriter to detect this plugin was
|
||||
|
@ -375,7 +376,9 @@ def _compare_eq_cls(left, right, verbose, type_fns):
|
|||
fields_to_check = [field for field, info in all_fields.items() if info.compare]
|
||||
elif isattrs(left):
|
||||
all_fields = left.__attrs_attrs__
|
||||
fields_to_check = [field.name for field in all_fields if field.cmp]
|
||||
fields_to_check = [
|
||||
field.name for field in all_fields if getattr(field, ATTRS_EQ_FIELD)
|
||||
]
|
||||
|
||||
same = []
|
||||
diff = []
|
||||
|
|
|
@ -354,3 +354,9 @@ if sys.version_info < (3, 5, 2): # pragma: no cover
|
|||
|
||||
def overload(f): # noqa: F811
|
||||
return f
|
||||
|
||||
|
||||
if getattr(attr, "__version_info__", ()) >= (19, 2):
|
||||
ATTRS_EQ_FIELD = "eq"
|
||||
else:
|
||||
ATTRS_EQ_FIELD = "cmp"
|
||||
|
|
|
@ -8,6 +8,7 @@ from typing import Set
|
|||
import attr
|
||||
|
||||
from ..compat import ascii_escaped
|
||||
from ..compat import ATTRS_EQ_FIELD
|
||||
from ..compat import getfslineno
|
||||
from ..compat import NOTSET
|
||||
from _pytest.outcomes import fail
|
||||
|
@ -367,7 +368,8 @@ class NodeKeywords(MutableMapping):
|
|||
return "<NodeKeywords for node {}>".format(self.node)
|
||||
|
||||
|
||||
@attr.s(cmp=False, hash=False)
|
||||
# mypy cannot find this overload, remove when on attrs>=19.2
|
||||
@attr.s(hash=False, **{ATTRS_EQ_FIELD: False}) # type: ignore
|
||||
class NodeMarkers:
|
||||
"""
|
||||
internal structure for storing marks belonging to a node
|
||||
|
|
|
@ -351,15 +351,14 @@ class RunResult:
|
|||
|
||||
Attributes:
|
||||
|
||||
:ret: the return value
|
||||
:outlines: list of lines captured from stdout
|
||||
:errlines: list of lines captures from stderr
|
||||
:stdout: :py:class:`LineMatcher` of stdout, use ``stdout.str()`` to
|
||||
:ivar ret: the return value
|
||||
:ivar outlines: list of lines captured from stdout
|
||||
:ivar errlines: list of lines captured from stderr
|
||||
:ivar stdout: :py:class:`LineMatcher` of stdout, use ``stdout.str()`` to
|
||||
reconstruct stdout or the commonly used ``stdout.fnmatch_lines()``
|
||||
method
|
||||
:stderr: :py:class:`LineMatcher` of stderr
|
||||
:duration: duration in seconds
|
||||
|
||||
:ivar stderr: :py:class:`LineMatcher` of stderr
|
||||
:ivar duration: duration in seconds
|
||||
"""
|
||||
|
||||
def __init__(self, ret, outlines, errlines, duration):
|
||||
|
@ -454,9 +453,9 @@ class Testdir:
|
|||
|
||||
Attributes:
|
||||
|
||||
:tmpdir: The :py:class:`py.path.local` instance of the temporary directory.
|
||||
:ivar tmpdir: The :py:class:`py.path.local` instance of the temporary directory.
|
||||
|
||||
:plugins: A list of plugins to use with :py:meth:`parseconfig` and
|
||||
:ivar plugins: A list of plugins to use with :py:meth:`parseconfig` and
|
||||
:py:meth:`runpytest`. Initially this is an empty list but plugins can
|
||||
be added to the list. The type of items to add to the list depends on
|
||||
the method using them so refer to them for details.
|
||||
|
|
|
@ -107,8 +107,8 @@ def show_test_item(item):
|
|||
tw = item.config.get_terminal_writer()
|
||||
tw.line()
|
||||
tw.write(" " * 8)
|
||||
tw.write(item._nodeid)
|
||||
used_fixtures = sorted(item._fixtureinfo.name2fixturedefs.keys())
|
||||
tw.write(item.nodeid)
|
||||
used_fixtures = sorted(getattr(item, "fixturenames", []))
|
||||
if used_fixtures:
|
||||
tw.write(" (fixtures used: {})".format(", ".join(used_fixtures)))
|
||||
|
||||
|
|
|
@ -88,3 +88,30 @@ def tw_mock():
|
|||
fullwidth = 80
|
||||
|
||||
return TWMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dummy_yaml_custom_test(testdir):
|
||||
"""Writes a conftest file that collects and executes a dummy yaml test.
|
||||
|
||||
Taken from the docs, but stripped down to the bare minimum, useful for
|
||||
tests which needs custom items collected.
|
||||
"""
|
||||
testdir.makeconftest(
|
||||
"""
|
||||
import pytest
|
||||
|
||||
def pytest_collect_file(parent, path):
|
||||
if path.ext == ".yaml" and path.basename.startswith("test"):
|
||||
return YamlFile(path, parent)
|
||||
|
||||
class YamlFile(pytest.File):
|
||||
def collect(self):
|
||||
yield YamlItem(self.fspath.basename, self)
|
||||
|
||||
class YamlItem(pytest.Item):
|
||||
def runtest(self):
|
||||
pass
|
||||
"""
|
||||
)
|
||||
testdir.makefile(".yaml", test1="")
|
||||
|
|
|
@ -6,8 +6,8 @@ def mode(request):
|
|||
return request.param
|
||||
|
||||
|
||||
def test_show_only_active_fixtures(testdir, mode):
|
||||
p = testdir.makepyfile(
|
||||
def test_show_only_active_fixtures(testdir, mode, dummy_yaml_custom_test):
|
||||
testdir.makepyfile(
|
||||
'''
|
||||
import pytest
|
||||
@pytest.fixture
|
||||
|
@ -21,7 +21,7 @@ def test_show_only_active_fixtures(testdir, mode):
|
|||
'''
|
||||
)
|
||||
|
||||
result = testdir.runpytest(mode, p)
|
||||
result = testdir.runpytest(mode)
|
||||
assert result.ret == 0
|
||||
|
||||
result.stdout.fnmatch_lines(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
def test_show_fixtures_and_test(testdir):
|
||||
def test_show_fixtures_and_test(testdir, dummy_yaml_custom_test):
|
||||
""" Verifies that fixtures are not executed. """
|
||||
p = testdir.makepyfile(
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
@pytest.fixture
|
||||
|
@ -11,7 +11,7 @@ def test_show_fixtures_and_test(testdir):
|
|||
"""
|
||||
)
|
||||
|
||||
result = testdir.runpytest("--setup-plan", p)
|
||||
result = testdir.runpytest("--setup-plan")
|
||||
assert result.ret == 0
|
||||
|
||||
result.stdout.fnmatch_lines(
|
||||
|
|
|
@ -9,6 +9,7 @@ import pytest
|
|||
from _pytest import outcomes
|
||||
from _pytest.assertion import truncate
|
||||
from _pytest.assertion import util
|
||||
from _pytest.compat import ATTRS_EQ_FIELD
|
||||
|
||||
|
||||
def mock_config():
|
||||
|
@ -687,7 +688,7 @@ class TestAssert_reprcompare_attrsclass:
|
|||
@attr.s
|
||||
class SimpleDataObject:
|
||||
field_a = attr.ib()
|
||||
field_b = attr.ib(cmp=False)
|
||||
field_b = attr.ib(**{ATTRS_EQ_FIELD: False})
|
||||
|
||||
left = SimpleDataObject(1, "b")
|
||||
right = SimpleDataObject(1, "b")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import argparse
|
||||
import distutils.spawn
|
||||
import os
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
import py
|
||||
|
@ -298,7 +299,11 @@ def test_argcomplete(testdir, monkeypatch):
|
|||
# redirect output from argcomplete to stdin and stderr is not trivial
|
||||
# http://stackoverflow.com/q/12589419/1307905
|
||||
# so we use bash
|
||||
fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" python -m pytest 8>&1 9>&2')
|
||||
fp.write(
|
||||
'COMP_WORDBREAKS="$COMP_WORDBREAKS" {} -m pytest 8>&1 9>&2'.format(
|
||||
shlex.quote(sys.executable)
|
||||
)
|
||||
)
|
||||
# alternative would be exteneded Testdir.{run(),_run(),popen()} to be able
|
||||
# to handle a keyword argument env that replaces os.environ in popen or
|
||||
# extends the copy, advantage: could not forget to restore
|
||||
|
|
8
tox.ini
8
tox.ini
|
@ -41,6 +41,8 @@ setenv =
|
|||
xdist: _PYTEST_TOX_POSARGS_XDIST=-n auto
|
||||
extras = testing
|
||||
deps =
|
||||
oldattrs: attrs==17.4.0
|
||||
oldattrs: hypothesis<=4.38.1
|
||||
numpy: numpy
|
||||
pexpect: pexpect
|
||||
pluggymaster: git+https://github.com/pytest-dev/pluggy.git@master
|
||||
|
@ -77,7 +79,7 @@ commands =
|
|||
[testenv:regen]
|
||||
changedir = doc/en
|
||||
skipsdist = True
|
||||
basepython = python3.6
|
||||
basepython = python3
|
||||
deps =
|
||||
sphinx
|
||||
PyYAML
|
||||
|
@ -103,7 +105,7 @@ commands =
|
|||
|
||||
[testenv:release]
|
||||
decription = do a release, required posarg of the version number
|
||||
basepython = python3.6
|
||||
basepython = python3
|
||||
usedevelop = True
|
||||
passenv = *
|
||||
deps =
|
||||
|
@ -116,7 +118,7 @@ commands = python scripts/release.py {posargs}
|
|||
|
||||
[testenv:publish_gh_release_notes]
|
||||
description = create GitHub release after deployment
|
||||
basepython = python3.6
|
||||
basepython = python3
|
||||
usedevelop = True
|
||||
passenv = GH_RELEASE_NOTES_TOKEN TRAVIS_TAG TRAVIS_REPO_SLUG
|
||||
deps =
|
||||
|
|
Loading…
Reference in New Issue