Merge pull request #3269 from nicoddemus/merge-master-into-features
Merge master into features
This commit is contained in:
commit
0a5a6c19be
1
AUTHORS
1
AUTHORS
|
@ -202,3 +202,4 @@ Xuan Luong
|
|||
Xuecong Liao
|
||||
Zoltán Máté
|
||||
Roland Puntaier
|
||||
Allan Feldman
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
.. image:: https://ci.appveyor.com/api/projects/status/mrgbjaua7t33pg6b?svg=true
|
||||
:target: https://ci.appveyor.com/project/pytestbot/pytest
|
||||
|
||||
.. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg
|
||||
:target: https://www.codetriage.com/pytest-dev/pytest
|
||||
|
||||
The ``pytest`` framework makes it easy to write small tests, yet
|
||||
scales to support complex functional testing for applications and libraries.
|
||||
|
||||
|
|
|
@ -1328,10 +1328,14 @@ def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
|
|||
dirs = get_dirs_from_args(args)
|
||||
if inifile:
|
||||
iniconfig = py.iniconfig.IniConfig(inifile)
|
||||
try:
|
||||
inicfg = iniconfig["pytest"]
|
||||
except KeyError:
|
||||
inicfg = None
|
||||
is_cfg_file = str(inifile).endswith('.cfg')
|
||||
sections = ['tool:pytest', 'pytest'] if is_cfg_file else ['pytest']
|
||||
for section in sections:
|
||||
try:
|
||||
inicfg = iniconfig[section]
|
||||
break
|
||||
except KeyError:
|
||||
inicfg = None
|
||||
rootdir = get_common_ancestor(dirs)
|
||||
else:
|
||||
ancestor = get_common_ancestor(dirs)
|
||||
|
|
|
@ -24,6 +24,12 @@ from _pytest.compat import (
|
|||
from _pytest.outcomes import fail, TEST_OUTCOME
|
||||
|
||||
|
||||
@attr.s(frozen=True)
|
||||
class PseudoFixtureDef(object):
|
||||
cached_result = attr.ib()
|
||||
scope = attr.ib()
|
||||
|
||||
|
||||
def pytest_sessionstart(session):
|
||||
import _pytest.python
|
||||
import _pytest.nodes
|
||||
|
@ -440,10 +446,9 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
|||
fixturedef = self._getnextfixturedef(argname)
|
||||
except FixtureLookupError:
|
||||
if argname == "request":
|
||||
class PseudoFixtureDef(object):
|
||||
cached_result = (self, [0], None)
|
||||
scope = "function"
|
||||
return PseudoFixtureDef
|
||||
cached_result = (self, [0], None)
|
||||
scope = "function"
|
||||
return PseudoFixtureDef(cached_result, scope)
|
||||
raise
|
||||
# remove indent to prevent the python3 exception
|
||||
# from leaking into the call
|
||||
|
|
|
@ -153,6 +153,8 @@ class ApproxScalar(ApproxBase):
|
|||
"""
|
||||
Perform approximate comparisons for single numbers only.
|
||||
"""
|
||||
DEFAULT_ABSOLUTE_TOLERANCE = 1e-12
|
||||
DEFAULT_RELATIVE_TOLERANCE = 1e-6
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
|
@ -223,7 +225,7 @@ class ApproxScalar(ApproxBase):
|
|||
|
||||
# Figure out what the absolute tolerance should be. ``self.abs`` is
|
||||
# either None or a value specified by the user.
|
||||
absolute_tolerance = set_default(self.abs, 1e-12)
|
||||
absolute_tolerance = set_default(self.abs, self.DEFAULT_ABSOLUTE_TOLERANCE)
|
||||
|
||||
if absolute_tolerance < 0:
|
||||
raise ValueError("absolute tolerance can't be negative: {}".format(absolute_tolerance))
|
||||
|
@ -241,7 +243,7 @@ class ApproxScalar(ApproxBase):
|
|||
# we've made sure the user didn't ask for an absolute tolerance only,
|
||||
# because we don't want to raise errors about the relative tolerance if
|
||||
# we aren't even going to use it.
|
||||
relative_tolerance = set_default(self.rel, 1e-6) * abs(self.expected)
|
||||
relative_tolerance = set_default(self.rel, self.DEFAULT_RELATIVE_TOLERANCE) * abs(self.expected)
|
||||
|
||||
if relative_tolerance < 0:
|
||||
raise ValueError("relative tolerance can't be negative: {}".format(absolute_tolerance))
|
||||
|
@ -252,6 +254,13 @@ class ApproxScalar(ApproxBase):
|
|||
return max(relative_tolerance, absolute_tolerance)
|
||||
|
||||
|
||||
class ApproxDecimal(ApproxScalar):
|
||||
from decimal import Decimal
|
||||
|
||||
DEFAULT_ABSOLUTE_TOLERANCE = Decimal('1e-12')
|
||||
DEFAULT_RELATIVE_TOLERANCE = Decimal('1e-6')
|
||||
|
||||
|
||||
def approx(expected, rel=None, abs=None, nan_ok=False):
|
||||
"""
|
||||
Assert that two numbers (or two sets of numbers) are equal to each other
|
||||
|
@ -401,6 +410,7 @@ def approx(expected, rel=None, abs=None, nan_ok=False):
|
|||
|
||||
from collections import Mapping, Sequence
|
||||
from _pytest.compat import STRING_TYPES as String
|
||||
from decimal import Decimal
|
||||
|
||||
# Delegate the comparison to a class that knows how to deal with the type
|
||||
# of the expected value (e.g. int, float, list, dict, numpy.array, etc).
|
||||
|
@ -422,6 +432,8 @@ def approx(expected, rel=None, abs=None, nan_ok=False):
|
|||
cls = ApproxMapping
|
||||
elif isinstance(expected, Sequence) and not isinstance(expected, String):
|
||||
cls = ApproxSequence
|
||||
elif isinstance(expected, Decimal):
|
||||
cls = ApproxDecimal
|
||||
else:
|
||||
cls = ApproxScalar
|
||||
|
||||
|
|
|
@ -329,6 +329,8 @@ class TerminalReporter(object):
|
|||
_PROGRESS_LENGTH = len(' [100%]')
|
||||
|
||||
def _get_progress_information_message(self):
|
||||
if self.config.getoption('capture') == 'no':
|
||||
return ''
|
||||
collected = self._session.testscollected
|
||||
if collected:
|
||||
progress = len(self._progress_nodeids_reported) * 100 // collected
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Removed progress information when capture option is ``no``.
|
|
@ -0,0 +1 @@
|
|||
Fix ``TypeError`` issue when using ``approx`` with a ``Decimal`` value.
|
|
@ -0,0 +1 @@
|
|||
Fix reference cycle generated when using the ``request`` fixture.
|
|
@ -0,0 +1 @@
|
|||
Fix minor typo in fixture.rst
|
|
@ -0,0 +1 @@
|
|||
``[tool:pytest]`` sections in ``*.cfg`` files passed by the ``-c`` option are now properly recognized.
|
|
@ -369,7 +369,7 @@ ends, but ``addfinalizer`` has two key differences over ``yield``:
|
|||
Fixtures can introspect the requesting test context
|
||||
-------------------------------------------------------------
|
||||
|
||||
Fixture function can accept the :py:class:`request <FixtureRequest>` object
|
||||
Fixture functions can accept the :py:class:`request <FixtureRequest>` object
|
||||
to introspect the "requesting" test function, class or module context.
|
||||
Further extending the previous ``smtp`` fixture example, let's
|
||||
read an optional server URL from the test module which uses our fixture::
|
||||
|
|
|
@ -160,9 +160,9 @@ List the name ``tmpdir`` in the test function signature and ``pytest`` will look
|
|||
PYTEST_TMPDIR/test_needsfiles0
|
||||
1 failed in 0.12 seconds
|
||||
|
||||
More info on tmpdir handling is available at `Temporary directories and files <tmpdir handling>`_.
|
||||
More info on tmpdir handling is available at :ref:`Temporary directories and files <tmpdir handling>`.
|
||||
|
||||
Find out what kind of builtin ```pytest`` fixtures <fixtures>`_ exist with the command::
|
||||
Find out what kind of builtin :ref:`pytest fixtures <fixtures>` exist with the command::
|
||||
|
||||
pytest --fixtures # shows builtin and custom fixtures
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ the plugin manager like this:
|
|||
|
||||
.. sourcecode:: python
|
||||
|
||||
plugin = config.pluginmanager.getplugin("name_of_plugin")
|
||||
plugin = config.pluginmanager.get_plugin("name_of_plugin")
|
||||
|
||||
If you want to look at the names of existing plugins, use
|
||||
the ``--trace-config`` option.
|
||||
|
|
|
@ -249,6 +249,7 @@ class TestApprox(object):
|
|||
(Decimal('-1.000001'), Decimal('-1.0')),
|
||||
]
|
||||
for a, x in within_1e6:
|
||||
assert a == approx(x)
|
||||
assert a == approx(x, rel=Decimal('5e-6'), abs=0)
|
||||
assert a != approx(x, rel=Decimal('5e-7'), abs=0)
|
||||
assert approx(x, rel=Decimal('5e-6'), abs=0) == a
|
||||
|
|
|
@ -519,6 +519,41 @@ class TestRequestBasic(object):
|
|||
assert len(arg2fixturedefs) == 1
|
||||
assert arg2fixturedefs['something'][0].argname == "something"
|
||||
|
||||
def test_request_garbage(self, testdir):
|
||||
testdir.makepyfile("""
|
||||
import sys
|
||||
import pytest
|
||||
import gc
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def something(request):
|
||||
# this method of test doesn't work on pypy
|
||||
if hasattr(sys, "pypy_version_info"):
|
||||
yield
|
||||
else:
|
||||
original = gc.get_debug()
|
||||
gc.set_debug(gc.DEBUG_SAVEALL)
|
||||
gc.collect()
|
||||
|
||||
yield
|
||||
|
||||
gc.collect()
|
||||
leaked_types = sum(1 for _ in gc.garbage
|
||||
if 'PseudoFixtureDef' in str(_))
|
||||
|
||||
gc.garbage[:] = []
|
||||
|
||||
try:
|
||||
assert leaked_types == 0
|
||||
finally:
|
||||
gc.set_debug(original)
|
||||
|
||||
def test_func():
|
||||
pass
|
||||
""")
|
||||
reprec = testdir.inline_run()
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
||||
def test_getfixturevalue_recursive(self, testdir):
|
||||
testdir.makeconftest("""
|
||||
import pytest
|
||||
|
|
|
@ -110,6 +110,13 @@ class TestConfigCmdlineParsing(object):
|
|||
config = testdir.parseconfig("-c", "custom.cfg")
|
||||
assert config.getini("custom") == "1"
|
||||
|
||||
testdir.makefile(".cfg", custom_tool_pytest_section="""
|
||||
[tool:pytest]
|
||||
custom = 1
|
||||
""")
|
||||
config = testdir.parseconfig("-c", "custom_tool_pytest_section.cfg")
|
||||
assert config.getini("custom") == "1"
|
||||
|
||||
def test_absolute_win32_path(self, testdir):
|
||||
temp_cfg_file = testdir.makefile(".cfg", custom="""
|
||||
[pytest]
|
||||
|
|
|
@ -1121,6 +1121,9 @@ class TestProgress(object):
|
|||
r'test_foobar.py \.{5}',
|
||||
])
|
||||
|
||||
output = testdir.runpytest('--capture=no')
|
||||
assert "%]" not in output.stdout.str()
|
||||
|
||||
|
||||
class TestProgressWithTeardown(object):
|
||||
"""Ensure we show the correct percentages for tests that fail during teardown (#3088)"""
|
||||
|
|
Loading…
Reference in New Issue