Merge remote-tracking branch 'upstream/features' into davidszotten/stepwise

This commit is contained in:
Bruno Oliveira 2018-10-20 09:18:02 -03:00
commit f947cb2613
65 changed files with 624 additions and 316 deletions

View File

@ -3,7 +3,7 @@ Thanks for submitting a PR, your contribution is really appreciated!
Here's a quick checklist that should be present in PRs (you can delete this text from the final description, this is
just a guideline):
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](/changelog/README.rst) for details.
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/master/changelog/README.rst) for details.
- [ ] Target the `master` branch for bug fixes, documentation updates and trivial changes.
- [ ] Target the `features` branch for new features and removals/deprecations.
- [ ] Include documentation when adding new features.

View File

@ -12,19 +12,15 @@ install:
- pip install --upgrade --pre tox
env:
matrix:
# note: please use "tox --listenvs" to populate the build matrix below
# please remove the linting env in all cases
- TOXENV=py27-pexpect
- TOXENV=py27-xdist
- TOXENV=py27-trial
- TOXENV=py27-numpy
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1
- TOXENV=py36-pexpect
- TOXENV=py36-xdist
- TOXENV=py36-trial
- TOXENV=py36-numpy
- TOXENV=py36-pluggymaster PYTEST_NO_COVERAGE=1
# Specialized factors for py27.
- TOXENV=py27-pexpect,py27-trial,py27-numpy
- TOXENV=py27-nobyte
- TOXENV=py27-xdist
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1
# Specialized factors for py36.
- TOXENV=py36-pexpect,py36-trial,py36-numpy
- TOXENV=py36-xdist
- TOXENV=py36-pluggymaster PYTEST_NO_COVERAGE=1
jobs:
include:
@ -97,12 +93,6 @@ after_success:
coverage xml --ignore-errors
coverage report -m --ignore-errors
bash <(curl -s https://codecov.io/bash) -Z -X gcov -X coveragepy -X search -X xcode -X gcovout -X fix -f coverage.xml -F "${TOXENV//-/,},linux"
# Coveralls does not support merged reports.
if [[ "$TOXENV" = py37 ]]; then
pip install coveralls
coveralls
fi
fi
notifications:

View File

@ -204,6 +204,7 @@ Stefan Zimmermann
Stefano Taschini
Steffen Allner
Stephan Obermann
Sven-Hendrik Haase
Tadek Teleżyński
Tarcisio Fischer
Tareq Alayan
@ -213,6 +214,7 @@ Thomas Hisch
Tim Strazny
Tom Dalton
Tom Viner
Tomer Keren
Trevor Bekolay
Tyler Goodlet
Tzu-ping Chung

View File

@ -18,6 +18,163 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start
pytest 3.9.1 (2018-10-16)
=========================
Features
--------
- `#4159 <https://github.com/pytest-dev/pytest/issues/4159>`_: For test-suites containing test classes, the information about the subclassed
module is now output only if a higher verbosity level is specified (at least
"-vv").
pytest 3.9.0 (2018-10-15 - not published due to a release automation bug)
=========================================================================
Deprecations
------------
- `#3616 <https://github.com/pytest-dev/pytest/issues/3616>`_: The following accesses have been documented as deprecated for years, but are now actually emitting deprecation warnings.
* Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances. Now
users will this warning::
usage of Function.Module is deprecated, please use pytest.Module instead
Users should just ``import pytest`` and access those objects using the ``pytest`` module.
* ``request.cached_setup``, this was the precursor of the setup/teardown mechanism available to fixtures. You can
consult `funcarg comparison section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_.
* Using objects named ``"Class"`` as a way to customize the type of nodes that are collected in ``Collector``
subclasses has been deprecated. Users instead should use ``pytest_collect_make_item`` to customize node types during
collection.
This issue should affect only advanced plugins who create new collection types, so if you see this warning
message please contact the authors so they can change the code.
* The warning that produces the message below has changed to ``RemovedInPytest4Warning``::
getfuncargvalue is deprecated, use getfixturevalue
- `#3988 <https://github.com/pytest-dev/pytest/issues/3988>`_: Add a Deprecation warning for pytest.ensuretemp as it was deprecated since a while.
Features
--------
- `#2293 <https://github.com/pytest-dev/pytest/issues/2293>`_: Improve usage errors messages by hiding internal details which can be distracting and noisy.
This has the side effect that some error conditions that previously raised generic errors (such as
``ValueError`` for unregistered marks) are now raising ``Failed`` exceptions.
- `#3332 <https://github.com/pytest-dev/pytest/issues/3332>`_: Improve the error displayed when a ``conftest.py`` file could not be imported.
In order to implement this, a new ``chain`` parameter was added to ``ExceptionInfo.getrepr``
to show or hide chained tracebacks in Python 3 (defaults to ``True``).
- `#3849 <https://github.com/pytest-dev/pytest/issues/3849>`_: Add ``empty_parameter_set_mark=fail_at_collect`` ini option for raising an exception when parametrize collects an empty set.
- `#3964 <https://github.com/pytest-dev/pytest/issues/3964>`_: Log messages generated in the collection phase are shown when
live-logging is enabled and/or when they are logged to a file.
- `#3985 <https://github.com/pytest-dev/pytest/issues/3985>`_: Introduce ``tmp_path`` as a fixture providing a Path object.
- `#4013 <https://github.com/pytest-dev/pytest/issues/4013>`_: Deprecation warnings are now shown even if you customize the warnings filters yourself. In the previous version
any customization would override pytest's filters and deprecation warnings would fall back to being hidden by default.
- `#4073 <https://github.com/pytest-dev/pytest/issues/4073>`_: Allow specification of timeout for ``Testdir.runpytest_subprocess()`` and ``Testdir.run()``.
- `#4098 <https://github.com/pytest-dev/pytest/issues/4098>`_: Add returncode argument to pytest.exit() to exit pytest with a specific return code.
- `#4102 <https://github.com/pytest-dev/pytest/issues/4102>`_: Reimplement ``pytest.deprecated_call`` using ``pytest.warns`` so it supports the ``match='...'`` keyword argument.
This has the side effect that ``pytest.deprecated_call`` now raises ``pytest.fail.Exception`` instead
of ``AssertionError``.
- `#4149 <https://github.com/pytest-dev/pytest/issues/4149>`_: Require setuptools>=30.3 and move most of the metadata to ``setup.cfg``.
Bug Fixes
---------
- `#2535 <https://github.com/pytest-dev/pytest/issues/2535>`_: Improve error message when test functions of ``unittest.TestCase`` subclasses use a parametrized fixture.
- `#3057 <https://github.com/pytest-dev/pytest/issues/3057>`_: ``request.fixturenames`` now correctly returns the name of fixtures created by ``request.getfixturevalue()``.
- `#3946 <https://github.com/pytest-dev/pytest/issues/3946>`_: Warning filters passed as command line options using ``-W`` now take precedence over filters defined in ``ini``
configuration files.
- `#4066 <https://github.com/pytest-dev/pytest/issues/4066>`_: Fix source reindenting by using ``textwrap.dedent`` directly.
- `#4102 <https://github.com/pytest-dev/pytest/issues/4102>`_: ``pytest.warn`` will capture previously-warned warnings in Python 2. Previously they were never raised.
- `#4108 <https://github.com/pytest-dev/pytest/issues/4108>`_: Resolve symbolic links for args.
This fixes running ``pytest tests/test_foo.py::test_bar``, where ``tests``
is a symlink to ``project/app/tests``:
previously ``project/app/conftest.py`` would be ignored for fixtures then.
- `#4132 <https://github.com/pytest-dev/pytest/issues/4132>`_: Fix duplicate printing of internal errors when using ``--pdb``.
- `#4135 <https://github.com/pytest-dev/pytest/issues/4135>`_: pathlib based tmpdir cleanup now correctly handles symlinks in the folder.
- `#4152 <https://github.com/pytest-dev/pytest/issues/4152>`_: Display the filename when encountering ``SyntaxWarning``.
Improved Documentation
----------------------
- `#3713 <https://github.com/pytest-dev/pytest/issues/3713>`_: Update usefixtures documentation to clarify that it can't be used with fixture functions.
- `#4058 <https://github.com/pytest-dev/pytest/issues/4058>`_: Update fixture documentation to specify that a fixture can be invoked twice in the scope it's defined for.
- `#4064 <https://github.com/pytest-dev/pytest/issues/4064>`_: According to unittest.rst, setUpModule and tearDownModule were not implemented, but it turns out they are. So updated the documentation for unittest.
- `#4151 <https://github.com/pytest-dev/pytest/issues/4151>`_: Add tempir testing example to CONTRIBUTING.rst guide
Trivial/Internal Changes
------------------------
- `#2293 <https://github.com/pytest-dev/pytest/issues/2293>`_: The internal ``MarkerError`` exception has been removed.
- `#3988 <https://github.com/pytest-dev/pytest/issues/3988>`_: Port the implementation of tmpdir to pathlib.
- `#4063 <https://github.com/pytest-dev/pytest/issues/4063>`_: Exclude 0.00 second entries from ``--duration`` output unless ``-vv`` is passed on the command-line.
- `#4093 <https://github.com/pytest-dev/pytest/issues/4093>`_: Fixed formatting of string literals in internal tests.
pytest 3.8.2 (2018-10-02)
=========================

View File

@ -280,6 +280,47 @@ Here is a simple overview, with pytest-specific bits:
base: features # if it's a feature
Writing Tests
----------------------------
Writing tests for plugins or for pytest itself is often done using the `testdir fixture <https://docs.pytest.org/en/latest/reference.html#testdir>`_, as a "black-box" test.
For example, to ensure a simple test passes you can write:
.. code-block:: python
def test_true_assertion(testdir):
testdir.makepyfile(
"""
def test_foo():
assert True
"""
)
result = testdir.runpytest()
result.assert_outcomes(failed=0, passed=1)
Alternatively, it is possible to make checks based on the actual output of the termal using
*glob-like* expressions:
.. code-block:: python
def test_true_assertion(testdir):
testdir.makepyfile(
"""
def test_foo():
assert False
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*assert False*", "*1 failed*"])
When choosing a file where to write a new test, take a look at the existing files and see if there's
one file which looks like a good fit. For example, a regression test about a bug in the ``--lf`` option
should go into ``test_cacheprovider.py``, given that this option is implemented in ``cacheprovider.py``.
If in doubt, go ahead and open a PR with your best guess and we can discuss this over the code.
Joining the Development Team
----------------------------

View File

@ -1,27 +1,29 @@
environment:
matrix:
- TOXENV: "linting,docs,doctesting"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27"
- TOXENV: "py34"
- TOXENV: "py35"
- TOXENV: "py36"
- TOXENV: "py37"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "linting,docs,doctesting"
- TOXENV: "py36"
- TOXENV: "py35"
- TOXENV: "py34"
- TOXENV: "pypy"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27-xdist"
- TOXENV: "py27-trial"
- TOXENV: "py27-numpy"
# Specialized factors for py27.
- TOXENV: "py27-trial,py27-numpy,py27-nobyte"
- TOXENV: "py27-pluggymaster"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py36-xdist"
- TOXENV: "py36-trial"
- TOXENV: "py36-numpy"
- TOXENV: "py27-xdist"
# Specialized factors for py36.
- TOXENV: "py36-trial,py36-numpy"
- TOXENV: "py36-pluggymaster"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27-nobyte"
- TOXENV: "py36-freeze"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py36-xdist"
matrix:
fast_finish: true
install:
- echo Installed Pythons

View File

@ -1,4 +0,0 @@
Improve usage errors messages by hiding internal details which can be distracting and noisy.
This has the side effect that some error conditions that previously raised generic errors (such as
``ValueError`` for unregistered marks) are now raising ``Failed`` exceptions.

View File

@ -1 +0,0 @@
The internal ``MarkerError`` exception has been removed.

View File

@ -1 +0,0 @@
Improve error message when test functions of ``unittest.TestCase`` subclasses use a parametrized fixture.

View File

@ -1 +0,0 @@
``request.fixturenames`` now correctly returns the name of fixtures created by ``request.getfixturevalue()``.

View File

@ -1,4 +0,0 @@
Improve the error displayed when a ``conftest.py`` file could not be imported.
In order to implement this, a new ``chain`` parameter was added to ``ExceptionInfo.getrepr``
to show or hide chained tracebacks in Python 3 (defaults to ``True``).

View File

@ -0,0 +1 @@
Fix unescaped XML raw objects in JUnit report for skipped tests

View File

@ -1,22 +0,0 @@
The following accesses have been documented as deprecated for years, but are now actually emitting deprecation warnings.
* Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances. Now
users will this warning::
usage of Function.Module is deprecated, please use pytest.Module instead
Users should just ``import pytest`` and access those objects using the ``pytest`` module.
* ``request.cached_setup``, this was the precursor of the setup/teardown mechanism available to fixtures. You can
consult `funcarg comparision section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_.
* Using objects named ``"Class"`` as a way to customize the type of nodes that are collected in ``Collector``
subclasses has been deprecated. Users instead should use ``pytest_collect_make_item`` to customize node types during
collection.
This issue should affect only advanced plugins who create new collection types, so if you see this warning
message please contact the authors so they can change the code.
* The warning that produces the message below has changed to ``RemovedInPytest4Warning``::
getfuncargvalue is deprecated, use getfixturevalue

View File

@ -1 +0,0 @@
Update usefixtures documentation to clarify that it can't be used with fixture functions.

View File

@ -1 +0,0 @@
Add ``empty_parameter_set_mark=fail_at_collect`` ini option for raising an exception when parametrize collects an empty set.

View File

@ -1,2 +0,0 @@
Warning filters passed as command line options using ``-W`` now take precedence over filters defined in ``ini``
configuration files.

View File

@ -1,2 +0,0 @@
Log messages generated in the collection phase are shown when
live-logging is enabled and/or when they are logged to a file.

View File

@ -1 +0,0 @@
Introduce ``tmp_path`` as a fixture providing a Path object.

View File

@ -1 +0,0 @@
Add a Deprecation warning for pytest.ensuretemp as it was deprecated since a while.

View File

@ -1 +0,0 @@
Port the implementation of tmpdir to pathlib.

View File

@ -1,2 +0,0 @@
Deprecation warnings are now shown even if you customize the warnings filters yourself. In the previous version
any customization would override pytest's filters and deprecation warnings would fall back to being hidden by default.

View File

@ -1 +0,0 @@
Update fixture documentation to specify that a fixture can be invoked twice in the scope it's defined for.

View File

@ -1 +0,0 @@
According to unittest.rst, setUpModule and tearDownModule were not implemented, but it turns out they are. So updated the documentation for unittest.

View File

@ -1 +0,0 @@
Fix source reindenting by using ``textwrap.dedent`` directly.

View File

@ -1 +0,0 @@
Allow specification of timeout for ``Testdir.runpytest_subprocess()`` and ``Testdir.run()``.

View File

@ -1 +0,0 @@
Fixed formatting of string literals in internal tests.

View File

@ -1 +0,0 @@
Add returncode argument to pytest.exit() to exit pytest with a specific return code.

View File

@ -1 +0,0 @@
``pytest.warn`` will capture previously-warned warnings in Python 2. Previously they were never raised.

View File

@ -1,4 +0,0 @@
Reimplement ``pytest.deprecated_call`` using ``pytest.warns`` so it supports the ``match='...'`` keyword argument.
This has the side effect that ``pytest.deprecated_call`` now raises ``pytest.fail.Exception`` instead
of ``AssertionError``.

View File

@ -1,5 +0,0 @@
Resolve symbolic links for args.
This fixes running ``pytest tests/test_foo.py::test_bar``, where ``tests``
is a symlink to ``project/app/tests``:
previously ``project/app/conftest.py`` would be ignored for fixtures then.

View File

@ -1 +0,0 @@
pathlib based tmpdir cleanup now correctly handles symlinks in the folder.

View File

@ -1 +0,0 @@
Require setuptools>=30.3 and move most of the metadata to ``setup.cfg``.

View File

@ -0,0 +1 @@
Pin ``setuptools>=40.0`` to support ``py_modules`` in ``setup.cfg``

View File

@ -0,0 +1 @@
Restore the tmpdir behaviour of symlinking the current test run.

View File

@ -0,0 +1 @@
Make ``--color`` emit colorful dots when not running in verbose mode. Earlier, it would only colorize the test-by-test output if ``--verbose`` was also passed.

View File

@ -6,6 +6,8 @@ Release announcements
:maxdepth: 2
release-3.9.1
release-3.9.0
release-3.8.2
release-3.8.1
release-3.8.0

View File

@ -0,0 +1,43 @@
pytest-3.9.0
=======================================
The pytest team is proud to announce the 3.9.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:
* Andrea Cimatoribus
* Ankit Goel
* Anthony Sottile
* Ben Eyal
* Bruno Oliveira
* Daniel Hahler
* Jeffrey Rackauckas
* Jose Carlos Menezes
* Kyle Altendorf
* Niklas JQ
* Palash Chatterjee
* Ronny Pfannschmidt
* Thomas Hess
* Thomas Hisch
* Tomer Keren
* Victor Maryama
Happy testing,
The Pytest Development Team

View File

@ -0,0 +1,20 @@
pytest-3.9.1
=======================================
pytest 3.9.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:
* Bruno Oliveira
* Ronny Pfannschmidt
* Thomas Hisch
Happy testing,
The pytest Development Team

View File

@ -104,7 +104,9 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
See http://docs.python.org/library/warnings.html for information
on warning categories.
tmpdir_factory
Return a TempdirFactory instance for the test session.
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
tmp_path_factory
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
tmpdir
Return a temporary directory path object
which is unique to each test function invocation,
@ -113,6 +115,16 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
path object.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
tmp_path
Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a :class:`pathlib.Path`
object.
.. note::
in python < 3.6 this is a pathlib2.Path
no tests ran in 0.12 seconds

View File

@ -56,7 +56,7 @@ This should be updated to make use of standard fixture mechanisms:
session.close()
You can consult `funcarg comparision section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_ for
You can consult `funcarg comparison section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_ for
more information.
This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings.
@ -68,7 +68,7 @@ Using ``Class`` in custom Collectors
.. deprecated:: 3.9
Using objects named ``"Class"`` as a way to customize the type of nodes that are collected in ``Collector``
subclasses has been deprecated. Users instead should use ``pytest_collect_make_item`` to customize node types during
subclasses has been deprecated. Users instead should use ``pytest_pycollect_makeitem`` to customize node types during
collection.
This issue should affect only advanced plugins who create new collection types, so if you see this warning
@ -304,7 +304,7 @@ This form of test function doesn't support fixtures properly, and users should s
.. code-block:: python
@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
def test_squared():
def test_squared(x, y):
assert x ** x == y

View File

@ -574,7 +574,7 @@ We can run this::
file $REGENDOC_TMPDIR/b/test_error.py, line 1
def test_root(db): # no db here, will error out
E fixture 'db' not found
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_xml_attribute, record_xml_property, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
$REGENDOC_TMPDIR/b/test_error.py:1

View File

@ -31,16 +31,37 @@ created in the `base temporary directory`_.
p = d / "hello.txt"
p.write_text(CONTENT)
assert p.read_text() == CONTENT
assert len(tmpdir.listdir()) == 1
assert len(list(tmp_path.iterdir())) == 1
assert 0
Running this would result in a passed test except for the last
``assert 0`` line which we use to look at values::
$ pytest test_tmp_path.py
... #fill fom regendoc
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item
test_tmp_path.py F [100%]
================================= FAILURES =================================
_____________________________ test_create_file _____________________________
tmp_path = PosixPath('PYTEST_TMPDIR/test_create_file0')
def test_create_file(tmp_path):
d = tmp_path / "sub"
d.mkdir()
p = d / "hello.txt"
p.write_text(CONTENT)
assert p.read_text() == CONTENT
assert len(list(tmp_path.iterdir())) == 1
> assert 0
E assert 0
test_tmp_path.py:13: AssertionError
========================= 1 failed in 0.12 seconds =========================
The ``tmp_path_factory`` fixture
--------------------------------

View File

@ -269,6 +269,7 @@ To get a list of the slowest 10 test durations::
pytest --durations=10
By default, pytest will not show test durations that are too small (<0.01s) unless ``-vv`` is passed on the command-line.
Creating JUnitXML format files
----------------------------------------------------

View File

@ -75,60 +75,6 @@ Both ``-W`` command-line option and ``filterwarnings`` ini option are based on P
`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python
documentation for other examples and advanced usage.
Disabling warning summary
-------------------------
Although not recommended, you can use the ``--disable-warnings`` command-line option to suppress the
warning summary entirely from the test run output.
Disabling warning capture entirely
----------------------------------
This plugin is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
.. code-block:: ini
[pytest]
addopts = -p no:warnings
Or passing ``-p no:warnings`` in the command-line. This might be useful if your test suites handles warnings
using an external system.
.. _`deprecation-warnings`:
DeprecationWarning and PendingDeprecationWarning
------------------------------------------------
.. versionadded:: 3.8
.. versionchanged:: 3.9
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning``.
Sometimes it is useful to hide some specific deprecation warnings that happen in code that you have no control over
(such as third-party libraries), in which case you might use the standard warning filters options (ini or marks).
For example:
.. code-block:: ini
[pytest]
filterwarnings =
ignore:.*U.*mode is deprecated:DeprecationWarning
.. note::
If warnings are configured at the interpreter level, using
the `PYTHONWARNINGS <https://docs.python.org/3/using/cmdline.html#envvar-PYTHONWARNINGS>`_ environment variable or the
``-W`` command-line option, pytest will not configure any filters by default.
.. note::
This feature makes pytest more compliant with `PEP-0506 <https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners>`_ which suggests that those warnings should
be shown by default by test runners, but pytest doesn't follow ``PEP-0506`` completely because resetting all
warning filters like suggested in the PEP will break existing test suites that configure warning filters themselves
by calling ``warnings.simplefilter`` (see issue `#2430 <https://github.com/pytest-dev/pytest/issues/2430>`_
for an example of that).
.. _`filterwarnings`:
``@pytest.mark.filterwarnings``
@ -167,24 +113,6 @@ decorator or to all tests in a module by setting the ``pytestmark`` variable:
pytestmark = pytest.mark.filterwarnings("error")
.. note::
Except for these features, pytest does not change the python warning filter; it only captures
and displays the warnings which are issued with respect to the currently configured filter,
including changes to the filter made by test functions or by the system under test.
.. note::
``DeprecationWarning`` and ``PendingDeprecationWarning`` are hidden by the standard library
by default so you have to explicitly configure them to be displayed in your ``pytest.ini``:
.. code-block:: ini
[pytest]
filterwarnings =
once::DeprecationWarning
once::PendingDeprecationWarning
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
*plugin.*
@ -193,6 +121,102 @@ decorator or to all tests in a module by setting the ``pytestmark`` variable:
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
Disabling warnings summary
--------------------------
Although not recommended, you can use the ``--disable-warnings`` command-line option to suppress the
warning summary entirely from the test run output.
Disabling warning capture entirely
----------------------------------
This plugin is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
.. code-block:: ini
[pytest]
addopts = -p no:warnings
Or passing ``-p no:warnings`` in the command-line. This might be useful if your test suites handles warnings
using an external system.
.. _`deprecation-warnings`:
DeprecationWarning and PendingDeprecationWarning
------------------------------------------------
.. versionadded:: 3.8
.. versionchanged:: 3.9
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning`` warnings from
user code and third-party libraries, as recommended by `PEP-0506 <https://www.python.org/dev/peps/pep-0565>`_.
This helps users keep their code modern and avoid breakages when deprecated warnings are effectively removed.
Sometimes it is useful to hide some specific deprecation warnings that happen in code that you have no control over
(such as third-party libraries), in which case you might use the warning filters options (ini or marks) to ignore
those warnings.
For example:
.. code-block:: ini
[pytest]
filterwarnings =
ignore:.*U.*mode is deprecated:DeprecationWarning
This will ignore all warnings of type ``DeprecationWarning`` where the start of the message matches
the regular expression ``".*U.*mode is deprecated"``.
.. note::
If warnings are configured at the interpreter level, using
the `PYTHONWARNINGS <https://docs.python.org/3/using/cmdline.html#envvar-PYTHONWARNINGS>`_ environment variable or the
``-W`` command-line option, pytest will not configure any filters by default.
Also pytest doesn't follow ``PEP-0506`` suggestion of resetting all warning filters because
it might break test suites that configure warning filters themselves
by calling ``warnings.simplefilter`` (see issue `#2430 <https://github.com/pytest-dev/pytest/issues/2430>`_
for an example of that).
.. _`ensuring a function triggers a deprecation warning`:
.. _ensuring_function_triggers:
Ensuring code triggers a deprecation warning
--------------------------------------------
You can also call a global helper for checking
that a certain function call triggers a ``DeprecationWarning`` or
``PendingDeprecationWarning``::
import pytest
def test_global():
pytest.deprecated_call(myfunction, 17)
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide
them. If you wish to record them in your own code, use the
command ``warnings.simplefilter('always')``::
import warnings
import pytest
def test_deprecation(recwarn):
warnings.simplefilter('always')
warnings.warn("deprecated", DeprecationWarning)
assert len(recwarn) == 1
assert recwarn.pop(DeprecationWarning)
You can also use it as a contextmanager::
def test_global():
with pytest.deprecated_call():
myobject.deprecated_method()
.. _`asserting warnings`:
@ -299,43 +323,6 @@ warnings, or index into it to get a particular recorded warning.
Full API: :class:`WarningsRecorder`.
.. _`ensuring a function triggers a deprecation warning`:
.. _ensuring_function_triggers:
Ensuring a function triggers a deprecation warning
-------------------------------------------------------
You can also call a global helper for checking
that a certain function call triggers a ``DeprecationWarning`` or
``PendingDeprecationWarning``::
import pytest
def test_global():
pytest.deprecated_call(myfunction, 17)
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide
them. If you wish to record them in your own code, use the
command ``warnings.simplefilter('always')``::
import warnings
import pytest
def test_deprecation(recwarn):
warnings.simplefilter('always')
warnings.warn("deprecated", DeprecationWarning)
assert len(recwarn) == 1
assert recwarn.pop(DeprecationWarning)
You can also use it as a contextmanager::
def test_global():
with pytest.deprecated_call():
myobject.deprecated_method()
.. _internal-warnings:

View File

@ -420,9 +420,21 @@ additionally it is possible to copy examples for a example folder before running
============================= warnings summary =============================
$REGENDOC_TMPDIR/test_example.py:4: PytestExperimentalApiWarning: testdir.copy_example is an experimental api that may change over time
testdir.copy_example("test_example.py")
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.File is deprecated, please use pytest.File instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Function is deprecated, please use pytest.Function instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Instance is deprecated, please use pytest.Instance instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Item is deprecated, please use pytest.Item instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:321: RemovedInPytest4Warning: usage of Session.Module is deprecated, please use pytest.Module instead
return getattr(object, name, default)
-- Docs: https://docs.pytest.org/en/latest/warnings.html
=================== 2 passed, 1 warnings in 0.12 seconds ===================
=================== 2 passed, 7 warnings in 0.12 seconds ===================
For more information about the result object that ``runpytest()`` returns, and
the methods that it provides please check out the :py:class:`RunResult

View File

@ -1,7 +1,7 @@
[build-system]
requires = [
# sync with setup.py until we discard non-pep-517/518
"setuptools>=30.3",
"setuptools>=40.0",
"setuptools-scm",
"wheel",
]

View File

@ -3,7 +3,7 @@
name = pytest
description = pytest: simple powerful testing with Python
long_description = file: README.rst
url = "https://docs.pytest.org/en/latest/"
url = https://docs.pytest.org/en/latest/
project_urls =
Source=https://github.com/pytest-dev/pytest
Tracker=https://github.com/pytest-dev/pytest/issues

View File

@ -26,7 +26,7 @@ if "_PYTEST_SETUP_SKIP_PLUGGY_DEP" not in os.environ:
def main():
setup(
use_scm_version={"write_to": "src/_pytest/_version.py"},
setup_requires=["setuptools-scm", "setuptools>=30.3"],
setup_requires=["setuptools-scm", "setuptools>=40.0"],
package_dir={"": "src"},
install_requires=INSTALL_REQUIRES,
)

View File

@ -399,7 +399,7 @@ def _rewrite_test(config, fn):
finally:
del state._indecode
try:
tree = ast.parse(source)
tree = ast.parse(source, filename=fn.strpath)
except SyntaxError:
# Let this pop up again in the real import.
state.trace("failed to parse: %r" % (fn,))

View File

@ -1,10 +1,12 @@
""" interactive debugging with PDB, the Python Debugger. """
from __future__ import absolute_import, division, print_function
import os
import pdb
import sys
import os
from doctest import UnexpectedException
from _pytest import outcomes
from _pytest.config import hookimpl
try:
@ -109,9 +111,6 @@ class PdbInvoke(object):
_enter_pdb(node, call.excinfo, report)
def pytest_internalerror(self, excrepr, excinfo):
for line in str(excrepr).split("\n"):
sys.stderr.write("INTERNALERROR> %s\n" % line)
sys.stderr.flush()
tb = _postmortem_traceback(excinfo)
post_mortem(tb)
@ -164,8 +163,9 @@ def _enter_pdb(node, excinfo, rep):
rep.toterminal(tw)
tw.sep(">", "entering PDB")
tb = _postmortem_traceback(excinfo)
post_mortem(tb)
rep._pdbshown = True
if post_mortem(tb):
outcomes.exit("Quitting debugger")
return rep
@ -196,3 +196,4 @@ def post_mortem(t):
p = Pdb()
p.reset()
p.interaction(None, t)
return p.quitting

View File

@ -1020,7 +1020,7 @@ class FixtureFunctionMarker(object):
def __call__(self, function):
if isclass(function):
raise ValueError("class fixtures not supported (may be in the future)")
raise ValueError("class fixtures not supported (maybe in the future)")
if getattr(function, "_pytestfixturefunction", False):
raise ValueError(
@ -1371,8 +1371,7 @@ class FixtureManager(object):
fixturedefs = self._arg2fixturedefs[argname]
except KeyError:
return None
else:
return tuple(self._matchfactories(fixturedefs, nodeid))
return tuple(self._matchfactories(fixturedefs, nodeid))
def _matchfactories(self, fixturedefs, nodeid):
for fixturedef in fixturedefs:

View File

@ -221,12 +221,14 @@ class _NodeReporter(object):
else:
filename, lineno, skipreason = report.longrepr
if skipreason.startswith("Skipped: "):
skipreason = bin_xml_escape(skipreason[9:])
skipreason = skipreason[9:]
details = "%s:%s: %s" % (filename, lineno, skipreason)
self.append(
Junit.skipped(
"%s:%s: %s" % (filename, lineno, skipreason),
bin_xml_escape(details),
type="pytest.skip",
message=skipreason,
message=bin_xml_escape(skipreason),
)
)
self.write_captured_output(report)

View File

@ -279,7 +279,7 @@ class LogCaptureFixture(object):
Unlike 'records', which contains the format string and parameters for interpolation, log messages in this list
are all interpolated.
Unlike 'text', which contains the output from the handler, log messages in this list are unadorned with
levels, timestamps, etc, making exact comparisions more reliable.
levels, timestamps, etc, making exact comparisons more reliable.
Note that traceback or stack info (from :func:`logging.exception` or the `exc_info` or `stack_info` arguments
to the logging functions) is not included, as this is added by the formatter in the handler.

View File

@ -570,9 +570,7 @@ class Session(nodes.FSCollector):
return True
def _tryconvertpyarg(self, x):
"""Convert a dotted module name to path.
"""
"""Convert a dotted module name to path."""
try:
with _patched_find_module():
loader = pkgutil.find_loader(x)
@ -604,8 +602,7 @@ class Session(nodes.FSCollector):
raise UsageError(
"file or package not found: " + arg + " (missing __init__.py?)"
)
else:
raise UsageError("file not found: " + arg)
raise UsageError("file not found: " + arg)
parts[0] = path
return parts

View File

@ -100,6 +100,26 @@ else:
_max = max
def _force_symlink(root, target, link_to):
"""helper to create the current symlink
its full of race conditions that are reasonably ok to ignore
for the contex of best effort linking to the latest testrun
the presumption being thatin case of much parallelism
the inaccuracy is going to be acceptable
"""
current_symlink = root.joinpath(target)
try:
current_symlink.unlink()
except OSError:
pass
try:
current_symlink.symlink_to(link_to)
except Exception:
pass
def make_numbered_dir(root, prefix):
"""create a directory with a increased number as suffix for the given prefix"""
for i in range(10):
@ -112,6 +132,7 @@ def make_numbered_dir(root, prefix):
except Exception:
pass
else:
_force_symlink(root, prefix + "current", new_path)
return new_path
else:
raise EnvironmentError(

View File

@ -17,7 +17,7 @@ from weakref import WeakKeyDictionary
from _pytest.capture import MultiCapture, SysCapture
from _pytest._code import Source
from _pytest.main import Session, EXIT_OK
from _pytest.main import Session, EXIT_INTERRUPTED, EXIT_OK
from _pytest.assertion.rewrite import AssertionRewritingHook
from _pytest.pathlib import Path
from _pytest.compat import safe_str
@ -857,7 +857,7 @@ class Testdir(object):
# typically we reraise keyboard interrupts from the child run
# because it's our user requesting interruption of the testing
if ret == 2 and not kwargs.get("no_reraise_ctrlc"):
if ret == EXIT_INTERRUPTED and not kwargs.get("no_reraise_ctrlc"):
calls = reprec.getcalls("pytest_keyboard_interrupt")
if calls and calls[-1].excinfo.type == KeyboardInterrupt:
raise KeyboardInterrupt()

View File

@ -30,6 +30,7 @@ def pytest_addoption(parser):
def pytest_terminal_summary(terminalreporter):
durations = terminalreporter.config.option.durations
verbose = terminalreporter.config.getvalue("verbose")
if durations is None:
return
tr = terminalreporter
@ -49,6 +50,10 @@ def pytest_terminal_summary(terminalreporter):
dlist = dlist[:durations]
for rep in dlist:
if verbose < 2 and rep.duration < 0.005:
tr.write_line("")
tr.write_line("(0.00 durations hidden. Use -vv to show these durations.)")
break
nodeid = rep.nodeid.replace("::()::", "::")
tr.write_line("%02.2fs %-8s %s" % (rep.duration, rep.when, nodeid))

View File

@ -263,7 +263,7 @@ class TerminalReporter(object):
char = {"xfailed": "x", "skipped": "s"}.get(char, char)
return char in self.reportchars
def write_fspath_result(self, nodeid, res):
def write_fspath_result(self, nodeid, res, **markup):
fspath = self.config.rootdir.join(nodeid.split("::")[0])
if fspath != self.currentfspath:
if self.currentfspath is not None and self._show_progress_info:
@ -272,7 +272,7 @@ class TerminalReporter(object):
fspath = self.startdir.bestrelpath(fspath)
self._tw.line()
self._tw.write(fspath + " ")
self._tw.write(res)
self._tw.write(res, **markup)
def write_ensure_prefix(self, prefix, extra="", **kwargs):
if self.currentfspath != prefix:
@ -386,22 +386,22 @@ class TerminalReporter(object):
# probably passed setup/teardown
return
running_xdist = hasattr(rep, "node")
if markup is None:
if rep.passed:
markup = {"green": True}
elif rep.failed:
markup = {"red": True}
elif rep.skipped:
markup = {"yellow": True}
else:
markup = {}
if self.verbosity <= 0:
if not running_xdist and self.showfspath:
self.write_fspath_result(rep.nodeid, letter)
self.write_fspath_result(rep.nodeid, letter, **markup)
else:
self._tw.write(letter)
self._tw.write(letter, **markup)
else:
self._progress_nodeids_reported.add(rep.nodeid)
if markup is None:
if rep.passed:
markup = {"green": True}
elif rep.failed:
markup = {"red": True}
elif rep.skipped:
markup = {"yellow": True}
else:
markup = {}
line = self._locationline(rep.nodeid, *rep.location)
if not running_xdist:
self.write_ensure_prefix(line, word, **markup)
@ -676,7 +676,9 @@ class TerminalReporter(object):
if fspath:
res = mkrel(nodeid).replace("::()", "") # parens-normalization
if nodeid.split("::")[0] != fspath.replace("\\", nodes.SEP):
if self.verbosity >= 2 and nodeid.split("::")[0] != fspath.replace(
"\\", nodes.SEP
):
res += " <- " + self.startdir.bestrelpath(fspath)
else:
res = "[location]"

View File

@ -12,6 +12,13 @@ import pytest
from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR
def prepend_pythonpath(*dirs):
cur = os.getenv("PYTHONPATH")
if cur:
dirs += (cur,)
return os.pathsep.join(str(p) for p in dirs)
class TestGeneralUsage(object):
def test_config_error(self, testdir):
testdir.copy_example("conftest_usageerror/conftest.py")
@ -590,14 +597,8 @@ class TestInvocationVariants(object):
assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*"])
def join_pythonpath(what):
cur = os.environ.get("PYTHONPATH")
if cur:
return str(what) + os.pathsep + cur
return what
empty_package = testdir.mkpydir("empty_package")
monkeypatch.setenv("PYTHONPATH", str(join_pythonpath(empty_package)))
monkeypatch.setenv("PYTHONPATH", str(empty_package), prepend=os.pathsep)
# the path which is not a package raises a warning on pypy;
# no idea why only pypy and not normal python warn about it here
with warnings.catch_warnings():
@ -606,7 +607,7 @@ class TestInvocationVariants(object):
assert result.ret == 0
result.stdout.fnmatch_lines(["*2 passed*"])
monkeypatch.setenv("PYTHONPATH", str(join_pythonpath(testdir)))
monkeypatch.setenv("PYTHONPATH", str(testdir), prepend=os.pathsep)
result = testdir.runpytest("--pyargs", "tpkg.test_missing", syspathinsert=True)
assert result.ret != 0
result.stderr.fnmatch_lines(["*not*found*test_missing*"])
@ -646,18 +647,13 @@ class TestInvocationVariants(object):
# ├── __init__.py
# └── test_world.py
def join_pythonpath(*dirs):
cur = os.environ.get("PYTHONPATH")
if cur:
dirs += (cur,)
return os.pathsep.join(str(p) for p in dirs)
monkeypatch.setenv("PYTHONPATH", join_pythonpath(*search_path))
# NOTE: the different/reversed ordering is intentional here.
monkeypatch.setenv("PYTHONPATH", prepend_pythonpath(*search_path))
for p in search_path:
monkeypatch.syspath_prepend(p)
# mixed module and filenames:
os.chdir("world")
monkeypatch.chdir("world")
result = testdir.runpytest("--pyargs", "-v", "ns_pkg.hello", "ns_pkg/world")
assert result.ret == 0
result.stdout.fnmatch_lines(
@ -708,8 +704,6 @@ class TestInvocationVariants(object):
pytest.skip(six.text_type(e.args[0]))
monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False)
search_path = ["lib", os.path.join("local", "lib")]
dirname = "lib"
d = testdir.mkdir(dirname)
foo = d.mkdir("foo")
@ -742,13 +736,9 @@ class TestInvocationVariants(object):
# ├── conftest.py
# └── test_bar.py
def join_pythonpath(*dirs):
cur = os.getenv("PYTHONPATH")
if cur:
dirs += (cur,)
return os.pathsep.join(str(p) for p in dirs)
monkeypatch.setenv("PYTHONPATH", join_pythonpath(*search_path))
# NOTE: the different/reversed ordering is intentional here.
search_path = ["lib", os.path.join("local", "lib")]
monkeypatch.setenv("PYTHONPATH", prepend_pythonpath(*search_path))
for p in search_path:
monkeypatch.syspath_prepend(p)
@ -760,16 +750,16 @@ class TestInvocationVariants(object):
if hasattr(py.path.local, "mksymlinkto"):
result.stdout.fnmatch_lines(
[
"lib/foo/bar/test_bar.py::test_bar <- local/lib/foo/bar/test_bar.py PASSED*",
"lib/foo/bar/test_bar.py::test_other <- local/lib/foo/bar/test_bar.py PASSED*",
"lib/foo/bar/test_bar.py::test_bar PASSED*",
"lib/foo/bar/test_bar.py::test_other PASSED*",
"*2 passed*",
]
)
else:
result.stdout.fnmatch_lines(
[
"local/lib/foo/bar/test_bar.py::test_bar PASSED*",
"local/lib/foo/bar/test_bar.py::test_other PASSED*",
"*lib/foo/bar/test_bar.py::test_bar PASSED*",
"*lib/foo/bar/test_bar.py::test_other PASSED*",
"*2 passed*",
]
)
@ -846,7 +836,10 @@ class TestDurations(object):
result = testdir.runpytest("--durations=10")
assert result.ret == 0
result.stdout.fnmatch_lines_random(
["*durations*", "*call*test_3*", "*call*test_2*", "*call*test_1*"]
["*durations*", "*call*test_3*", "*call*test_2*"]
)
result.stdout.fnmatch_lines(
["(0.00 durations hidden. Use -vv to show these durations.)"]
)
def test_calls_show_2(self, testdir):
@ -860,6 +853,18 @@ class TestDurations(object):
testdir.makepyfile(self.source)
result = testdir.runpytest("--durations=0")
assert result.ret == 0
for x in "23":
for y in ("call",): # 'setup', 'call', 'teardown':
for line in result.stdout.lines:
if ("test_%s" % x) in line and y in line:
break
else:
raise AssertionError("not found {} {}".format(x, y))
def test_calls_showall_verbose(self, testdir):
testdir.makepyfile(self.source)
result = testdir.runpytest("--durations=0", "-vv")
assert result.ret == 0
for x in "123":
for y in ("call",): # 'setup', 'call', 'teardown':
for line in result.stdout.lines:
@ -870,9 +875,9 @@ class TestDurations(object):
def test_with_deselected(self, testdir):
testdir.makepyfile(self.source)
result = testdir.runpytest("--durations=2", "-k test_1")
result = testdir.runpytest("--durations=2", "-k test_2")
assert result.ret == 0
result.stdout.fnmatch_lines(["*durations*", "*call*test_1*"])
result.stdout.fnmatch_lines(["*durations*", "*call*test_2*"])
def test_with_failing_collection(self, testdir):
testdir.makepyfile(self.source)
@ -892,13 +897,15 @@ class TestDurations(object):
class TestDurationWithFixture(object):
source = """
import pytest
import time
frag = 0.001
def setup_function(func):
time.sleep(frag * 3)
def test_1():
time.sleep(frag*2)
def test_2():
frag = 0.01
@pytest.fixture
def setup_fixt():
time.sleep(frag)
def test_1(setup_fixt):
time.sleep(frag)
"""

View File

@ -494,6 +494,12 @@ class TestRequestBasic(object):
reason="this method of test doesn't work on pypy",
)
def test_request_garbage(self, testdir):
try:
import xdist # noqa
except ImportError:
pass
else:
pytest.xfail("this test is flaky when executed with xdist")
testdir.makepyfile(
"""
import sys

View File

@ -1222,3 +1222,19 @@ def test_set_suite_name(testdir, suite_name):
assert result.ret == 0
node = dom.find_first_by_tag("testsuite")
node.assert_attr(name=expected)
def test_escaped_skipreason_issue3533(testdir):
testdir.makepyfile(
"""
import pytest
@pytest.mark.skip(reason='1 <> 2')
def test_skip():
pass
"""
)
_, dom = runandparse(testdir)
node = dom.find_first_by_tag("testcase")
snode = node.find_first_by_tag("skipped")
assert "1 <> 2" in snode.text
snode.assert_attr(message="1 <> 2")

View File

@ -25,6 +25,8 @@ def custom_pdb_calls():
# install dummy debugger class and track which methods were called on it
class _CustomPdb(object):
quitting = False
def __init__(self, *args, **kwargs):
called.append("init")
@ -142,6 +144,9 @@ class TestPDB(object):
def test_1():
i = 0
assert i == 1
def test_not_called_due_to_quit():
pass
"""
)
child = testdir.spawn_pytest("--pdb %s" % p1)
@ -150,8 +155,9 @@ class TestPDB(object):
child.expect("Pdb")
child.sendeof()
rest = child.read().decode("utf8")
assert "1 failed" in rest
assert "= 1 failed in" in rest
assert "def test_1" not in rest
assert "Exit: Quitting debugger" in rest
self.flush(child)
@staticmethod
@ -321,7 +327,7 @@ class TestPDB(object):
child = testdir.spawn_pytest("--pdb %s" % p1)
# child.expect(".*import pytest.*")
child.expect("Pdb")
child.sendeof()
child.sendline("c")
child.expect("1 error")
self.flush(child)
@ -334,8 +340,20 @@ class TestPDB(object):
)
p1 = testdir.makepyfile("def test_func(): pass")
child = testdir.spawn_pytest("--pdb %s" % p1)
# child.expect(".*import pytest.*")
child.expect("Pdb")
# INTERNALERROR is only displayed once via terminal reporter.
assert (
len(
[
x
for x in child.before.decode().splitlines()
if x.startswith("INTERNALERROR> Traceback")
]
)
== 1
)
child.sendeof()
self.flush(child)
@ -345,7 +363,7 @@ class TestPDB(object):
import pytest
def test_1():
i = 0
print ("hello17")
print("hello17")
pytest.set_trace()
x = 3
"""
@ -376,6 +394,7 @@ class TestPDB(object):
rest = child.read().decode("utf8")
assert "1 failed" in rest
assert "reading from stdin while output" not in rest
assert "BdbQuit" in rest
self.flush(child)
def test_pdb_and_capsys(self, testdir):
@ -383,7 +402,7 @@ class TestPDB(object):
"""
import pytest
def test_1(capsys):
print ("hello1")
print("hello1")
pytest.set_trace()
"""
)
@ -420,7 +439,7 @@ class TestPDB(object):
def test_1():
pdb.set_trace()
def test_2():
print ("hello")
print("hello")
assert 0
"""
)
@ -461,10 +480,10 @@ class TestPDB(object):
import pytest
def test_1():
i = 0
print ("hello17")
print("hello17")
pytest.set_trace()
x = 3
print ("hello18")
print("hello18")
pytest.set_trace()
x = 4
"""
@ -518,14 +537,16 @@ class TestPDB(object):
def test_pdb_collection_failure_is_shown(self, testdir):
p1 = testdir.makepyfile("xxx")
result = testdir.runpytest_subprocess("--pdb", p1)
result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"])
result.stdout.fnmatch_lines(
["E NameError: *xxx*", "*! *Exit: Quitting debugger !*"] # due to EOF
)
def test_enter_pdb_hook_is_called(self, testdir):
testdir.makeconftest(
"""
def pytest_enter_pdb(config):
assert config.testing_verification == 'configured'
print 'enter_pdb_hook'
print('enter_pdb_hook')
def pytest_configure(config):
config.testing_verification = 'configured'
@ -562,7 +583,7 @@ class TestPDB(object):
custom_pdb="""
class CustomPdb(object):
def set_trace(*args, **kwargs):
print 'custom set_trace>'
print('custom set_trace>')
"""
)
p1 = testdir.makepyfile(

View File

@ -154,7 +154,7 @@ class TestTerminal(object):
)
result = testdir.runpytest(p2)
result.stdout.fnmatch_lines(["*test_p2.py .*", "*1 passed*"])
result = testdir.runpytest("-v", p2)
result = testdir.runpytest("-vv", p2)
result.stdout.fnmatch_lines(
["*test_p2.py::TestMore::test_p1* <- *test_p1.py*PASSED*"]
)
@ -170,7 +170,7 @@ class TestTerminal(object):
"""
)
)
result = testdir.runpytest("-v")
result = testdir.runpytest("-vv")
assert result.ret == 0
result.stdout.fnmatch_lines(["*a123/test_hello123.py*PASS*"])
assert " <- " not in result.stdout.str()

View File

@ -196,6 +196,12 @@ class TestNumberedDir(object):
assert d.name.startswith(self.PREFIX)
assert d.name.endswith(str(i))
symlink = tmp_path.joinpath(self.PREFIX + "current")
if symlink.exists():
# unix
assert symlink.is_symlink()
assert symlink.resolve() == d.resolve()
def test_cleanup_lock_create(self, tmp_path):
d = tmp_path.joinpath("test")
d.mkdir()
@ -244,7 +250,7 @@ class TestNumberedDir(object):
def test_cleanup_keep(self, tmp_path):
self._do_cleanup(tmp_path)
a, b = tmp_path.iterdir()
a, b = (x for x in tmp_path.iterdir() if not x.is_symlink())
print(a, b)
def test_cleanup_locked(self, tmp_path):

27
tox.ini
View File

@ -18,10 +18,10 @@ envlist =
[testenv]
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest --lsof -ra {posargs:testing}
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest --lsof
coverage: coverage combine
coverage: coverage report
passenv = USER USERNAME
passenv = USER USERNAME COVERAGE_* TRAVIS
setenv =
# configuration if a user runs tox with a "coverage" factor, for example "tox -e py36-coverage"
coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m
@ -36,14 +36,12 @@ deps =
{env:_PYTEST_TOX_EXTRA_DEP:}
[testenv:py27-subprocess]
changedir = .
deps =
pytest-xdist>=1.13
py27: mock
nose
passenv = USER USERNAME TRAVIS
commands =
pytest -n auto -ra --runpytest=subprocess {posargs:testing}
pytest -n auto --runpytest=subprocess
[testenv:linting]
@ -59,9 +57,8 @@ deps =
nose
hypothesis>=3.56
{env:_PYTEST_TOX_EXTRA_DEP:}
passenv = USER USERNAME TRAVIS
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto -ra {posargs:testing}
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto
[testenv:py36-xdist]
# NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706.
@ -74,16 +71,14 @@ deps =
commands = {[testenv:py27-xdist]commands}
[testenv:py27-pexpect]
changedir = testing
platform = linux|darwin
deps =
pexpect
{env:_PYTEST_TOX_EXTRA_DEP:}
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -ra test_pdb.py test_terminal.py test_unittest.py
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest testing/test_pdb.py testing/test_terminal.py testing/test_unittest.py {posargs}
[testenv:py36-pexpect]
changedir = {[testenv:py27-pexpect]changedir}
platform = {[testenv:py27-pexpect]platform}
deps = {[testenv:py27-pexpect]deps}
commands = {[testenv:py27-pexpect]commands}
@ -95,20 +90,18 @@ deps =
py27: mock
{env:_PYTEST_TOX_EXTRA_DEP:}
distribute = true
changedir=testing
setenv =
{[testenv]setenv}
PYTHONDONTWRITEBYTECODE=1
passenv = USER USERNAME TRAVIS
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto -ra {posargs:.}
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs}
[testenv:py27-trial]
deps =
twisted
{env:_PYTEST_TOX_EXTRA_DEP:}
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -ra {posargs:testing/test_unittest.py}
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_unittest.py}
[testenv:py36-trial]
deps = {[testenv:py27-trial]deps}
@ -119,7 +112,7 @@ deps =
numpy
{env:_PYTEST_TOX_EXTRA_DEP:}
commands=
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -ra {posargs:testing/python/approx.py}
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/python/approx.py}
[testenv:py36-numpy]
deps = {[testenv:py27-numpy]deps}
@ -154,7 +147,7 @@ deps =
PyYAML
{env:_PYTEST_TOX_EXTRA_DEP:}
commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -ra doc/en
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest doc/en
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules --pyargs _pytest
[testenv:regen]
@ -175,7 +168,7 @@ commands =
[testenv:jython]
changedir = testing
commands =
{envpython} {envbindir}/py.test-jython -ra {posargs}
{envpython} {envbindir}/py.test-jython {posargs}
[testenv:py36-freeze]
changedir = testing/freeze