Skip to content

Commit

Permalink
Merge pull request #3269 from nicoddemus/merge-master-into-features
Browse files Browse the repository at this point in the history
Merge master into features
  • Loading branch information
nicoddemus committed Feb 28, 2018
2 parents 90638b6 + a2a6454 commit 0a5a6c1
Show file tree
Hide file tree
Showing 18 changed files with 92 additions and 14 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,4 @@ Xuan Luong
Xuecong Liao
Zoltán Máté
Roland Puntaier
Allan Feldman
3 changes: 3 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
12 changes: 8 additions & 4 deletions _pytest/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 9 additions & 4 deletions _pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
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
Expand Down Expand Up @@ -440,10 +446,9 @@ def _get_active_fixturedef(self, argname):
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
Expand Down
16 changes: 14 additions & 2 deletions _pytest/python_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -223,7 +225,7 @@ def set_default(x, default):

# 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))
Expand All @@ -241,7 +243,7 @@ def set_default(x, default):
# 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))
Expand All @@ -252,6 +254,13 @@ def set_default(x, default):
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
Expand Down Expand Up @@ -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).
Expand All @@ -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

Expand Down
2 changes: 2 additions & 0 deletions _pytest/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ def pytest_runtest_logfinish(self, nodeid):
_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
Expand Down
1 change: 1 addition & 0 deletions changelog/3203.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed progress information when capture option is ``no``.
1 change: 1 addition & 0 deletions changelog/3247.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix ``TypeError`` issue when using ``approx`` with a ``Decimal`` value.
1 change: 1 addition & 0 deletions changelog/3249.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix reference cycle generated when using the ``request`` fixture.
1 change: 1 addition & 0 deletions changelog/3259.trivial
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix minor typo in fixture.rst
1 change: 1 addition & 0 deletions changelog/3260.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``[tool:pytest]`` sections in ``*.cfg`` files passed by the ``-c`` option are now properly recognized.
2 changes: 1 addition & 1 deletion doc/en/fixture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
4 changes: 2 additions & 2 deletions doc/en/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion doc/en/writing_plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions testing/python/approx.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ def test_decimal(self):
(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
Expand Down
35 changes: 35 additions & 0 deletions testing/python/fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,41 @@ def test_method(self, something):
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
Expand Down
7 changes: 7 additions & 0 deletions testing/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ def pytest_addoption(parser):
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]
Expand Down
3 changes: 3 additions & 0 deletions testing/test_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,9 @@ def test_capture_no(self, many_tests_files, testdir):
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)"""
Expand Down

0 comments on commit 0a5a6c1

Please sign in to comment.