Merge pull request #4645 from blueyed/merge-master-into-features

Merge master into features
This commit is contained in:
Anthony Sottile 2019-01-14 14:41:27 -08:00 committed by GitHub
commit 4947eb85c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 278 additions and 66 deletions

2
.github/config.yml vendored Normal file
View File

@ -0,0 +1,2 @@
rtd:
project: pytest

View File

@ -24,6 +24,7 @@ Andy Freeland
Anthon van der Neut Anthon van der Neut
Anthony Shaw Anthony Shaw
Anthony Sottile Anthony Sottile
Anton Lodder
Antony Lee Antony Lee
Armin Rigo Armin Rigo
Aron Coyle Aron Coyle
@ -176,6 +177,7 @@ Oliver Bestwalter
Omar Kohl Omar Kohl
Omer Hadari Omer Hadari
Ondřej Súkup Ondřej Súkup
Oscar Benjamin
Patrick Hayes Patrick Hayes
Paweł Adamczak Paweł Adamczak
Pedro Algarvio Pedro Algarvio

View File

@ -18,6 +18,38 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start .. towncrier release notes start
pytest 4.1.1 (2019-01-12)
=========================
Bug Fixes
---------
- `#2256 <https://github.com/pytest-dev/pytest/issues/2256>`_: Show full repr with ``assert a==b`` and ``-vv``.
- `#3456 <https://github.com/pytest-dev/pytest/issues/3456>`_: Extend Doctest-modules to ignore mock objects.
- `#4617 <https://github.com/pytest-dev/pytest/issues/4617>`_: Fixed ``pytest.warns`` bug when context manager is reused (e.g. multiple parametrization).
- `#4631 <https://github.com/pytest-dev/pytest/issues/4631>`_: Don't rewrite assertion when ``__getattr__`` is broken
Improved Documentation
----------------------
- `#3375 <https://github.com/pytest-dev/pytest/issues/3375>`_: Document that using ``setup.cfg`` may crash other tools or cause hard to track down problems because it uses a different parser than ``pytest.ini`` or ``tox.ini`` files.
Trivial/Internal Changes
------------------------
- `#4602 <https://github.com/pytest-dev/pytest/issues/4602>`_: Uninstall ``hypothesis`` in regen tox env.
pytest 4.1.0 (2019-01-05) pytest 4.1.0 (2019-01-05)
========================= =========================

View File

@ -1 +0,0 @@
Uninstall ``hypothesis`` in regen tox env.

View File

@ -1 +0,0 @@
Fixed ``pytest.warns`` bug when context manager is reused (e.g. multiple parametrization).

View File

@ -0,0 +1,3 @@
Use ``a.item()`` instead of the deprecated ``np.asscalar(a)`` in ``pytest.approx``.
``np.asscalar`` has been `deprecated <https://github.com/numpy/numpy/blob/master/doc/release/1.16.0-notes.rst#new-deprecations>`__ in ``numpy 1.16.``.

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2 :maxdepth: 2
release-4.1.1
release-4.1.0 release-4.1.0
release-4.0.2 release-4.0.2
release-4.0.1 release-4.0.1

View File

@ -0,0 +1,27 @@
pytest-4.1.1
=======================================
pytest 4.1.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
* Anton Lodder
* Bruno Oliveira
* Daniel Hahler
* David Vo
* Oscar Benjamin
* Ronny Pfannschmidt
* Victor Maryama
* Yoav Caspi
* dmitry.dygalo
Happy testing,
The pytest Development Team

View File

@ -214,6 +214,8 @@ If you run this command for the first time, you can see the print statement:
def test_function(mydata): def test_function(mydata):
> assert mydata == 23 > assert mydata == 23
E assert 42 == 23 E assert 42 == 23
E -42
E +23
test_caching.py:17: AssertionError test_caching.py:17: AssertionError
-------------------------- Captured stdout setup --------------------------- -------------------------- Captured stdout setup ---------------------------
@ -235,6 +237,8 @@ the cache and nothing will be printed:
def test_function(mydata): def test_function(mydata):
> assert mydata == 23 > assert mydata == 23
E assert 42 == 23 E assert 42 == 23
E -42
E +23
test_caching.py:17: AssertionError test_caching.py:17: AssertionError
1 failed in 0.12 seconds 1 failed in 0.12 seconds

View File

@ -42,10 +42,11 @@ todo_include_todos = 1
extensions = [ extensions = [
"pygments_pytest", "pygments_pytest",
"sphinx.ext.autodoc", "sphinx.ext.autodoc",
"sphinx.ext.todo",
"sphinx.ext.autosummary", "sphinx.ext.autosummary",
"sphinx.ext.intersphinx", "sphinx.ext.intersphinx",
"sphinx.ext.todo",
"sphinx.ext.viewcode", "sphinx.ext.viewcode",
"sphinx_removed_in",
"sphinxcontrib_trio", "sphinxcontrib_trio",
] ]

View File

@ -101,7 +101,7 @@ an appropriate period of deprecation has passed.
Using ``Class`` in custom Collectors Using ``Class`` in custom Collectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
Using objects named ``"Class"`` as a way to customize the type of nodes that are collected in ``Collector`` 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_pycollect_makeitem`` to customize node types during subclasses has been deprecated. Users instead should use ``pytest_pycollect_makeitem`` to customize node types during
@ -114,7 +114,7 @@ message please contact the authors so they can change the code.
marks in ``pytest.mark.parametrize`` marks in ``pytest.mark.parametrize``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
Applying marks to values of a ``pytest.mark.parametrize`` call is now deprecated. For example: Applying marks to values of a ``pytest.mark.parametrize`` call is now deprecated. For example:
@ -162,7 +162,7 @@ To update the code, use ``pytest.param``:
``pytest_funcarg__`` prefix ``pytest_funcarg__`` prefix
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
In very early pytest versions fixtures could be defined using the ``pytest_funcarg__`` prefix: In very early pytest versions fixtures could be defined using the ``pytest_funcarg__`` prefix:
@ -184,7 +184,7 @@ Switch over to the ``@pytest.fixture`` decorator:
[pytest] section in setup.cfg files [pytest] section in setup.cfg files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]`` ``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]``
to avoid conflicts with other distutils commands. to avoid conflicts with other distutils commands.
@ -193,7 +193,7 @@ to avoid conflicts with other distutils commands.
Metafunc.addcall Metafunc.addcall
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
:meth:`_pytest.python.Metafunc.addcall` was a precursor to the current parametrized mechanism. Users should use :meth:`_pytest.python.Metafunc.addcall` was a precursor to the current parametrized mechanism. Users should use
:meth:`_pytest.python.Metafunc.parametrize` instead. :meth:`_pytest.python.Metafunc.parametrize` instead.
@ -217,7 +217,7 @@ Becomes:
``cached_setup`` ``cached_setup``
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
``request.cached_setup`` was the precursor of the setup/teardown mechanism available to fixtures. ``request.cached_setup`` was the precursor of the setup/teardown mechanism available to fixtures.
@ -249,7 +249,7 @@ more information.
pytest_plugins in non-top-level conftest files pytest_plugins in non-top-level conftest files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py
files because they will activate referenced plugins *globally*, which is surprising because for all other pytest files because they will activate referenced plugins *globally*, which is surprising because for all other pytest
@ -259,7 +259,7 @@ features ``conftest.py`` files are only *active* for tests at or below it.
``Config.warn`` and ``Node.warn`` ``Config.warn`` and ``Node.warn``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
system for its own warnings, so those two functions are now deprecated. system for its own warnings, so those two functions are now deprecated.
@ -286,7 +286,7 @@ Becomes:
record_xml_property record_xml_property
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
The ``record_xml_property`` fixture is now deprecated in favor of the more generic ``record_property``, which The ``record_xml_property`` fixture is now deprecated in favor of the more generic ``record_property``, which
can be used by other consumers (for example ``pytest-html``) to obtain custom information about the test run. can be used by other consumers (for example ``pytest-html``) to obtain custom information about the test run.
@ -309,7 +309,7 @@ Change to:
Passing command-line string to ``pytest.main()`` Passing command-line string to ``pytest.main()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
Passing a command-line string to ``pytest.main()`` is deprecated: Passing a command-line string to ``pytest.main()`` is deprecated:
@ -331,7 +331,7 @@ on (for example ``bash`` or ``Powershell``), but this is very hard/impossible to
Calling fixtures directly Calling fixtures directly
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
Calling a fixture function directly, as opposed to request them in a test function, is deprecated. Calling a fixture function directly, as opposed to request them in a test function, is deprecated.
@ -384,7 +384,7 @@ with the ``name`` parameter:
``yield`` tests ``yield`` tests
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
pytest supported ``yield``-style tests, where a test function actually ``yield`` functions and values pytest supported ``yield``-style tests, where a test function actually ``yield`` functions and values
that are then turned into proper test methods. Example: that are then turned into proper test methods. Example:
@ -412,7 +412,7 @@ This form of test function doesn't support fixtures properly, and users should s
Internal classes accessed through ``Node`` Internal classes accessed through ``Node``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances now issue Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances now issue
this warning:: this warning::
@ -423,10 +423,28 @@ Users should just ``import pytest`` and access those objects using the ``pytest`
This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings. This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings.
``Node.get_marker``
~~~~~~~~~~~~~~~~~~~
.. versionremoved:: 4.0
As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` is deprecated. See
:ref:`the documentation <update marker code>` on tips on how to update your code.
``somefunction.markname``
~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionremoved:: 4.0
As part of a large :ref:`marker-revamp` we already deprecated using ``MarkInfo``
the only correct way to get markers of an element is via ``node.iter_markers(name)``.
``pytest_namespace`` ``pytest_namespace``
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0.* .. versionremoved:: 4.0
This hook is deprecated because it greatly complicates the pytest internals regarding configuration and initialization, making some This hook is deprecated because it greatly complicates the pytest internals regarding configuration and initialization, making some
bug fixes and refactorings impossible. bug fixes and refactorings impossible.
@ -461,7 +479,7 @@ As a stopgap measure, plugin authors may still inject their names into pytest's
Reinterpretation mode (``--assert=reinterp``) Reinterpretation mode (``--assert=reinterp``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 3.0.* .. versionremoved:: 3.0
Reinterpretation mode has now been removed and only plain and rewrite Reinterpretation mode has now been removed and only plain and rewrite
mode are available, consequently the ``--assert=reinterp`` option is mode are available, consequently the ``--assert=reinterp`` option is
@ -473,7 +491,7 @@ explicitly turn on assertion rewriting for those files.
Removed command-line options Removed command-line options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 3.0.* .. versionremoved:: 3.0
The following deprecated commandline options were removed: The following deprecated commandline options were removed:
@ -485,27 +503,9 @@ The following deprecated commandline options were removed:
py.test-X* entry points py.test-X* entry points
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 3.0.* .. versionremoved:: 3.0
Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points
were never documented and a leftover from a pre-virtualenv era. These entry were never documented and a leftover from a pre-virtualenv era. These entry
points also created broken entry points in wheels, so removing them also points also created broken entry points in wheels, so removing them also
removes a source of confusion for users. removes a source of confusion for users.
``Node.get_marker``
~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0*
As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` is deprecated. See
:ref:`the documentation <update marker code>` on tips on how to update your code.
``somefunction.markname``
~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0*
As part of a large :ref:`marker-revamp` we already deprecated using ``MarkInfo``
the only correct way to get markers of an element is via ``node.iter_markers(name)``.

View File

@ -406,6 +406,8 @@ argument sets to use for each test function. Let's run it:
def test_equals(self, a, b): def test_equals(self, a, b):
> assert a == b > assert a == b
E assert 1 == 2 E assert 1 == 2
E -1
E +2
test_parametrize.py:18: AssertionError test_parametrize.py:18: AssertionError
1 failed, 2 passed in 0.12 seconds 1 failed, 2 passed in 0.12 seconds

View File

@ -72,8 +72,18 @@ to keep tests separate from actual application code (often a good idea)::
test_view.py test_view.py
... ...
This way your tests can run easily against an installed version This has the following benefits:
of ``mypkg``.
* Your tests can run against an installed version after executing ``pip install .``.
* Your tests can run against the local copy with an editable install after executing ``pip install --editable .``.
* If you don't have a ``setup.py`` file and are relying on the fact that Python by default puts the current
directory in ``sys.path`` to import your package, you can execute ``python -m pytest`` to execute the tests against the
local copy directly, without using ``pip``.
.. note::
See :ref:`pythonpath` for more information about the difference between calling ``pytest`` and
``python -m pytest``.
Note that using this scheme your test files must have **unique names**, because Note that using this scheme your test files must have **unique names**, because
``pytest`` will import them as *top-level* modules since there are no packages ``pytest`` will import them as *top-level* modules since there are no packages

View File

@ -889,6 +889,12 @@ Here is a list of builtin configuration options that may be written in a ``pytes
file, usually located at the root of your repository. All options must be under a ``[pytest]`` section file, usually located at the root of your repository. All options must be under a ``[pytest]`` section
(``[tool:pytest]`` for ``setup.cfg`` files). (``[tool:pytest]`` for ``setup.cfg`` files).
.. warning::
Usage of ``setup.cfg`` is not recommended unless for very simple use cases. ``.cfg``
files use a different parser than ``pytest.ini`` and ``tox.ini`` which might cause hard to track
down problems.
When possible, it is recommended to use the latter files to hold your pytest configuration.
Configuration file options may be overwritten in the command-line by using ``-o/--override``, which can also be Configuration file options may be overwritten in the command-line by using ``-o/--override``, which can also be
passed multiple times. The expected format is ``name=value``. For example:: passed multiple times. The expected format is ``name=value``. For example::

View File

@ -1,3 +1,4 @@
pygments-pytest>=1.1.0 pygments-pytest>=1.1.0
sphinx>=1.8.2 sphinx>=1.8.2
sphinxcontrib-trio sphinxcontrib-trio
sphinx-removed-in>=0.1.3

View File

@ -512,7 +512,13 @@ def _format_assertmsg(obj):
def _should_repr_global_name(obj): def _should_repr_global_name(obj):
return not hasattr(obj, "__name__") and not callable(obj) if callable(obj):
return False
try:
return not hasattr(obj, "__name__")
except Exception:
return True
def _format_boolop(explanations, is_or): def _format_boolop(explanations, is_or):

View File

@ -151,6 +151,8 @@ def assertrepr_compare(config, op, left, right):
elif type(left) == type(right) and (isdatacls(left) or isattrs(left)): elif type(left) == type(right) and (isdatacls(left) or isattrs(left)):
type_fn = (isdatacls, isattrs) type_fn = (isdatacls, isattrs)
explanation = _compare_eq_cls(left, right, verbose, type_fn) explanation = _compare_eq_cls(left, right, verbose, type_fn)
elif verbose:
explanation = _compare_eq_verbose(left, right)
if isiterable(left) and isiterable(right): if isiterable(left) and isiterable(right):
expl = _compare_eq_iterable(left, right, verbose) expl = _compare_eq_iterable(left, right, verbose)
if explanation is not None: if explanation is not None:
@ -236,6 +238,18 @@ def _diff_text(left, right, verbose=False):
return explanation return explanation
def _compare_eq_verbose(left, right):
keepends = True
left_lines = repr(left).splitlines(keepends)
right_lines = repr(right).splitlines(keepends)
explanation = []
explanation += [u"-" + line for line in left_lines]
explanation += [u"+" + line for line in right_lines]
return explanation
def _compare_eq_iterable(left, right, verbose=False): def _compare_eq_iterable(left, right, verbose=False):
if not verbose: if not verbose:
return [u"Use -v to get the full diff"] return [u"Use -v to get the full diff"]

View File

@ -3,17 +3,19 @@ from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
import inspect
import platform import platform
import sys import sys
import traceback import traceback
from contextlib import contextmanager
import pytest import pytest
from _pytest._code.code import ExceptionInfo from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ReprFileLocation from _pytest._code.code import ReprFileLocation
from _pytest._code.code import TerminalRepr from _pytest._code.code import TerminalRepr
from _pytest.compat import safe_getattr
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
DOCTEST_REPORT_CHOICE_NONE = "none" DOCTEST_REPORT_CHOICE_NONE = "none"
DOCTEST_REPORT_CHOICE_CDIFF = "cdiff" DOCTEST_REPORT_CHOICE_CDIFF = "cdiff"
DOCTEST_REPORT_CHOICE_NDIFF = "ndiff" DOCTEST_REPORT_CHOICE_NDIFF = "ndiff"
@ -346,10 +348,61 @@ def _check_all_skipped(test):
pytest.skip("all tests skipped by +SKIP option") pytest.skip("all tests skipped by +SKIP option")
def _is_mocked(obj):
"""
returns if a object is possibly a mock object by checking the existence of a highly improbable attribute
"""
return (
safe_getattr(obj, "pytest_mock_example_attribute_that_shouldnt_exist", None)
is not None
)
@contextmanager
def _patch_unwrap_mock_aware():
"""
contextmanager which replaces ``inspect.unwrap`` with a version
that's aware of mock objects and doesn't recurse on them
"""
real_unwrap = getattr(inspect, "unwrap", None)
if real_unwrap is None:
yield
else:
def _mock_aware_unwrap(obj, stop=None):
if stop is None:
return real_unwrap(obj, stop=_is_mocked)
else:
return real_unwrap(obj, stop=lambda obj: _is_mocked(obj) or stop(obj))
inspect.unwrap = _mock_aware_unwrap
try:
yield
finally:
inspect.unwrap = real_unwrap
class DoctestModule(pytest.Module): class DoctestModule(pytest.Module):
def collect(self): def collect(self):
import doctest import doctest
class MockAwareDocTestFinder(doctest.DocTestFinder):
"""
a hackish doctest finder that overrides stdlib internals to fix a stdlib bug
https://github.com/pytest-dev/pytest/issues/3456
https://bugs.python.org/issue25532
"""
def _find(self, tests, obj, name, module, source_lines, globs, seen):
if _is_mocked(obj):
return
with _patch_unwrap_mock_aware():
doctest.DocTestFinder._find(
self, tests, obj, name, module, source_lines, globs, seen
)
if self.fspath.basename == "conftest.py": if self.fspath.basename == "conftest.py":
module = self.config.pluginmanager._importconftest(self.fspath) module = self.config.pluginmanager._importconftest(self.fspath)
else: else:
@ -361,7 +414,7 @@ class DoctestModule(pytest.Module):
else: else:
raise raise
# uses internal doctest module parsing mechanism # uses internal doctest module parsing mechanism
finder = doctest.DocTestFinder() finder = MockAwareDocTestFinder()
optionflags = get_optionflags(self) optionflags = get_optionflags(self)
runner = _get_runner( runner = _get_runner(
verbose=0, verbose=0,

View File

@ -150,10 +150,10 @@ class ApproxNumpy(ApproxBase):
if np.isscalar(actual): if np.isscalar(actual):
for i in np.ndindex(self.expected.shape): for i in np.ndindex(self.expected.shape):
yield actual, np.asscalar(self.expected[i]) yield actual, self.expected[i].item()
else: else:
for i in np.ndindex(self.expected.shape): for i in np.ndindex(self.expected.shape):
yield np.asscalar(actual[i]), np.asscalar(self.expected[i]) yield actual[i].item(), self.expected[i].item()
class ApproxMapping(ApproxBase): class ApproxMapping(ApproxBase):

View File

@ -488,6 +488,30 @@ class TestAssert_reprcompare(object):
expl = callequal([(1, 2)], []) expl = callequal([(1, 2)], [])
assert len(expl) > 1 assert len(expl) > 1
def test_repr_verbose(self):
class Nums:
def __init__(self, nums):
self.nums = nums
def __repr__(self):
return str(self.nums)
list_x = list(range(5000))
list_y = list(range(5000))
list_y[len(list_y) // 2] = 3
nums_x = Nums(list_x)
nums_y = Nums(list_y)
assert callequal(nums_x, nums_y) is None
expl = callequal(nums_x, nums_y, verbose=1)
assert "-" + repr(nums_x) in expl
assert "+" + repr(nums_y) in expl
expl = callequal(nums_x, nums_y, verbose=2)
assert "-" + repr(nums_x) in expl
assert "+" + repr(nums_y) in expl
def test_list_bad_repr(self): def test_list_bad_repr(self):
class A(object): class A(object):
def __repr__(self): def __repr__(self):

View File

@ -180,6 +180,27 @@ class TestAssertionRewrite(object):
assert getmsg(f, {"cls": X}) == "assert cls == 42" assert getmsg(f, {"cls": X}) == "assert cls == 42"
def test_dont_rewrite_if_hasattr_fails(self):
class Y(object):
""" A class whos getattr fails, but not with `AttributeError` """
def __getattr__(self, attribute_name):
raise KeyError()
def __repr__(self):
return "Y"
def __init__(self):
self.foo = 3
def f():
assert cls().foo == 2 # noqa
message = getmsg(f, {"cls": Y})
assert "assert 3 == 2" in message
assert "+ where 3 = Y.foo" in message
assert "+ where Y = cls()" in message
def test_assert_already_has_message(self): def test_assert_already_has_message(self):
def f(): def f():
assert False, "something bad!" assert False, "something bad!"

View File

@ -1206,3 +1206,22 @@ class TestDoctestReportingOption(object):
"*error: argument --doctest-report: invalid choice: 'obviously_invalid_format' (choose from*" "*error: argument --doctest-report: invalid choice: 'obviously_invalid_format' (choose from*"
] ]
) )
@pytest.mark.parametrize("mock_module", ["mock", "unittest.mock"])
def test_doctest_mock_objects_dont_recurse_missbehaved(mock_module, testdir):
pytest.importorskip(mock_module)
testdir.makepyfile(
"""
from {mock_module} import call
class Example(object):
'''
>>> 1 + 1
2
'''
""".format(
mock_module=mock_module
)
)
result = testdir.runpytest("--doctest-modules")
result.stdout.fnmatch_lines(["* 1 passed *"])

View File

@ -2,6 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import sys import sys
import warnings
import six import six
@ -685,25 +686,10 @@ class TestAssertionWarnings:
result.stdout.fnmatch_lines(["*1 failed in*"]) result.stdout.fnmatch_lines(["*1 failed in*"])
def test_warningschecker_twice(testdir): def test_warnings_checker_twice():
"""Issue #4617""" """Issue #4617"""
expectation = pytest.warns(UserWarning)
testdir.makepyfile(
"""
import pytest
import warnings
@pytest.mark.parametrize("other", [1, 2])
@pytest.mark.parametrize("expectation", [
pytest.warns(DeprecationWarning,
match="Message A"),
pytest.warns(DeprecationWarning,
match="Message A"),
])
def test_parametrized_warnings(other, expectation):
with expectation: with expectation:
warnings.warn("Message A", DeprecationWarning) warnings.warn("Message A", UserWarning)
""" with expectation:
) warnings.warn("Message B", UserWarning)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 4 passed in *"])