Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
12edc4e
Pass TRAVIS env var to test environments [skip appveyor]
nicoddemus Oct 15, 2018
17655b5
Merge pull request #4163 from nicoddemus/travis-passenv-4162
nicoddemus Oct 15, 2018
f55ded2
fix #3533: properly escape raw XML object
Oct 16, 2018
d72154a
add changelog for #3533
Oct 16, 2018
f858177
Merge pull request #4167 from vbarbaresi/3533_junit_escape_skipped
crazymerlyn Oct 16, 2018
ee0a306
Merge remote-tracking branch 'upstream/features' into merge-features-…
nicoddemus Oct 16, 2018
f7285b6
Merge pull request #4172 from nicoddemus/merge-features-into-master
nicoddemus Oct 16, 2018
215a2ed
Update warnings docs
nicoddemus Oct 17, 2018
ab8907f
s/comparision/comparison/g [ci skip]
asottile Oct 17, 2018
93bdbf7
Merge pull request #4173 from nicoddemus/warning-docs-update
nicoddemus Oct 17, 2018
ba5a295
Fix hook name in deprecations.rst
nicoddemus Oct 17, 2018
4f4c91c
fix #4177 - pin setuptools>=40.0
RonnyPfannschmidt Oct 17, 2018
cc335d4
fix #4179 - bring back the current testrun symlink
RonnyPfannschmidt Oct 17, 2018
8dca8f3
fix test_cleanup_keep for expecting symlinks
RonnyPfannschmidt Oct 17, 2018
8a768b0
Merge pull request #4182 from nicoddemus/fix-deprecations-hook-name
nicoddemus Oct 17, 2018
56dd7bc
TestNumberedDir: ignore that symlinks arent created on windows
RonnyPfannschmidt Oct 17, 2018
e6b01b4
Merge pull request #4185 from RonnyPfannschmidt/fix-fail
nicoddemus Oct 17, 2018
12f94b8
No longer upload code coverage to coveralls
nicoddemus Oct 17, 2018
a83ee19
Merge remote-tracking branch 'upstream/master' into RonnyPfannschmidt…
nicoddemus Oct 17, 2018
517ee58
Merge pull request #4186 from nicoddemus/drop-coveralls
nicoddemus Oct 18, 2018
e4871f7
Merge pull request #4183 from RonnyPfannschmidt/bump-setuptools
nicoddemus Oct 18, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,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:
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Deprecations
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>`_.
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
Expand Down
1 change: 1 addition & 0 deletions changelog/3533.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix unescaped XML raw objects in JUnit report for skipped tests
1 change: 1 addition & 0 deletions changelog/4177.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pin ``setuptools>=40.0`` to support ``py_modules`` in ``setup.cfg``
1 change: 1 addition & 0 deletions changelog/4179.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Restore the tmpdir behaviour of symlinking the current test run.
4 changes: 2 additions & 2 deletions doc/en/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
181 changes: 84 additions & 97 deletions doc/en/warnings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,54 @@ 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
-------------------------
.. _`filterwarnings`:

``@pytest.mark.filterwarnings``
-------------------------------

.. versionadded:: 3.2

You can use the ``@pytest.mark.filterwarnings`` to add warning filters to specific test items,
allowing you to have finer control of which warnings should be captured at test, class or
even module level:

.. code-block:: python

import warnings


def api_v1():
warnings.warn(UserWarning("api v1, should use functions from v2"))
return 1


@pytest.mark.filterwarnings("ignore:api v1")
def test_one():
assert api_v1() == 1


Filters applied using a mark take precedence over filters passed on the command line or configured
by the ``filterwarnings`` ini option.

You may apply a filter to all tests of a class by using the ``filterwarnings`` mark as a class
decorator or to all tests in a module by setting the ``pytestmark`` variable:

.. code-block:: python

# turns all warnings into errors for this module
pytestmark = pytest.mark.filterwarnings("error")



*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
*plugin.*

.. _`-W option`: https://docs.python.org/3/using/cmdline.html?highlight=#cmdoption-W
.. _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.
Expand All @@ -103,10 +149,14 @@ DeprecationWarning and PendingDeprecationWarning
.. versionadded:: 3.8
.. versionchanged:: 3.9

By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning``.
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 standard warning filters options (ini or marks).
(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
Expand All @@ -116,83 +166,57 @@ For example:
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.

.. 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
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).


.. _`filterwarnings`:

``@pytest.mark.filterwarnings``
-------------------------------

.. versionadded:: 3.2

You can use the ``@pytest.mark.filterwarnings`` to add warning filters to specific test items,
allowing you to have finer control of which warnings should be captured at test, class or
even module level:

.. code-block:: python

import warnings


def api_v1():
warnings.warn(UserWarning("api v1, should use functions from v2"))
return 1


@pytest.mark.filterwarnings("ignore:api v1")
def test_one():
assert api_v1() == 1


Filters applied using a mark take precedence over filters passed on the command line or configured
by the ``filterwarnings`` ini option.
.. _`ensuring a function triggers a deprecation warning`:

You may apply a filter to all tests of a class by using the ``filterwarnings`` mark as a class
decorator or to all tests in a module by setting the ``pytestmark`` variable:
.. _ensuring_function_triggers:

.. code-block:: python
Ensuring code triggers a deprecation warning
--------------------------------------------

# turns all warnings into errors for this module
pytestmark = pytest.mark.filterwarnings("error")
You can also call a global helper for checking
that a certain function call triggers a ``DeprecationWarning`` or
``PendingDeprecationWarning``::

import pytest

.. note::
def test_global():
pytest.deprecated_call(myfunction, 17)

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.
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')``::

.. note::
import warnings
import pytest

``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``:
def test_deprecation(recwarn):
warnings.simplefilter('always')
warnings.warn("deprecated", DeprecationWarning)
assert len(recwarn) == 1
assert recwarn.pop(DeprecationWarning)

.. code-block:: ini
You can also use it as a contextmanager::

[pytest]
filterwarnings =
once::DeprecationWarning
once::PendingDeprecationWarning
def test_global():
with pytest.deprecated_call():
myobject.deprecated_method()


*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
*plugin.*

.. _`-W option`: https://docs.python.org/3/using/cmdline.html?highlight=#cmdoption-W
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings


.. _`asserting warnings`:

Expand Down Expand Up @@ -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:

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -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",
]
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
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,
)
Expand Down
8 changes: 5 additions & 3 deletions src/_pytest/junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,14 @@ def append_skipped(self, report):
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)
Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def messages(self):
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.
Expand Down
21 changes: 21 additions & 0 deletions src/_pytest/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ def _max(iterable, default):
_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):
Expand All @@ -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(
Expand Down
16 changes: 16 additions & 0 deletions testing/test_junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -1222,3 +1222,19 @@ def test_func():
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")
8 changes: 7 additions & 1 deletion testing/test_tmpdir.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ def test_make(self, tmp_path):
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()
Expand Down Expand Up @@ -244,7 +250,7 @@ def _do_cleanup(self, tmp_path):

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):
Expand Down
Loading