Merge remote-tracking branch 'upstream/master' into merge-master-into-features
This commit is contained in:
commit
9a3836a0cf
|
@ -7,13 +7,13 @@ repos:
|
|||
args: [--safe, --quiet]
|
||||
language_version: python3
|
||||
- repo: https://github.com/asottile/blacken-docs
|
||||
rev: v0.2.0
|
||||
rev: v0.3.0
|
||||
hooks:
|
||||
- id: blacken-docs
|
||||
additional_dependencies: [black==18.6b4]
|
||||
additional_dependencies: [black==18.9b0]
|
||||
language_version: python3
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v1.3.0
|
||||
rev: v1.4.0-1
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
|
@ -22,11 +22,12 @@ repos:
|
|||
exclude: _pytest/debugging.py
|
||||
- id: flake8
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v1.2.0
|
||||
rev: v1.8.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
- id: pyupgrade
|
||||
args: [--keep-percent-format]
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.0.0
|
||||
rev: v1.1.0
|
||||
hooks:
|
||||
- id: rst-backticks
|
||||
- repo: local
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
# 10000 iterations, just for relative comparison
|
||||
# 2.7.5 3.3.2
|
||||
# FilesCompleter 75.1109 69.2116
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import pytest
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Improve error message when test functions of ``unittest.TestCase`` subclasses use a parametrized fixture.
|
|
@ -0,0 +1 @@
|
|||
``request.fixturenames`` now correctly returns the name of fixtures created by ``request.getfixturevalue()``.
|
|
@ -0,0 +1 @@
|
|||
Update fixture documentation to specify that a fixture can be invoked twice in the scope it's defined for.
|
|
@ -0,0 +1 @@
|
|||
According to unittest.rst, setUpModule and tearDownModule were not implemented, but it turns out they are. So updated the documentation for unittest.
|
|
@ -0,0 +1 @@
|
|||
Fix source reindenting by using ``textwrap.dedent`` directly.
|
|
@ -20,8 +20,7 @@ Thanks to all who contributed to this release, among them:
|
|||
* Ondřej Súkup
|
||||
* Ronny Pfannschmidt
|
||||
* T.E.A de Souza
|
||||
* Victor
|
||||
* victor
|
||||
* Victor Maryama
|
||||
|
||||
|
||||
Happy testing,
|
||||
|
|
|
@ -22,10 +22,9 @@ Thanks to all who contributed to this release, among them:
|
|||
* Ronny Pfannschmidt
|
||||
* Sankt Petersbug
|
||||
* Tyler Richard
|
||||
* Victor
|
||||
* Victor Maryama
|
||||
* Vlad Shcherbina
|
||||
* turturica
|
||||
* victor
|
||||
* wim glenn
|
||||
|
||||
|
||||
|
|
|
@ -245,9 +245,9 @@ class TestCustomAssertMsg(object):
|
|||
a = 1
|
||||
|
||||
b = 2
|
||||
assert (
|
||||
A.a == b
|
||||
), "A.a appears not to be b\n" "or does not appear to be b\none of those"
|
||||
assert A.a == b, (
|
||||
"A.a appears not to be b\n" "or does not appear to be b\none of those"
|
||||
)
|
||||
|
||||
def test_custom_repr(self):
|
||||
class JSON(object):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
hello = "world"
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import py
|
||||
|
||||
failure_demo = py.path.local(__file__).dirpath("failure_demo.py")
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import pytest
|
||||
|
||||
|
||||
|
|
|
@ -852,6 +852,8 @@ In that order.
|
|||
can be changed between releases (even bug fixes) so it shouldn't be relied on for scripting
|
||||
or automation.
|
||||
|
||||
.. _freezing-pytest:
|
||||
|
||||
Freezing pytest
|
||||
---------------
|
||||
|
||||
|
|
|
@ -259,6 +259,11 @@ instance, you can simply declare it:
|
|||
|
||||
Finally, the ``class`` scope will invoke the fixture once per test *class*.
|
||||
|
||||
.. note::
|
||||
|
||||
Pytest will only cache one instance of a fixture at a time.
|
||||
This means that when using a parametrized fixture, pytest may invoke a fixture more than once in the given scope.
|
||||
|
||||
|
||||
``package`` scope (experimental)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -69,17 +69,15 @@ You may also discover more plugins through a `pytest- pypi.python.org search`_.
|
|||
Requiring/Loading plugins in a test module or conftest file
|
||||
-----------------------------------------------------------
|
||||
|
||||
You can require plugins in a test module or a conftest file like this::
|
||||
You can require plugins in a test module or a conftest file like this:
|
||||
|
||||
pytest_plugins = "myapp.testsupport.myplugin",
|
||||
.. code-block:: python
|
||||
|
||||
pytest_plugins = ("myapp.testsupport.myplugin",)
|
||||
|
||||
When the test module or conftest plugin is loaded the specified plugins
|
||||
will be loaded as well.
|
||||
|
||||
pytest_plugins = "myapp.testsupport.myplugin"
|
||||
|
||||
which will import the specified module as a ``pytest`` plugin.
|
||||
|
||||
.. note::
|
||||
Requiring plugins using a ``pytest_plugins`` variable in non-root
|
||||
``conftest.py`` files is deprecated. See
|
||||
|
|
|
@ -84,6 +84,12 @@ pytest.warns
|
|||
.. autofunction:: pytest.warns(expected_warning: Exception, [match])
|
||||
:with:
|
||||
|
||||
pytest.freeze_includes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Tutorial**: :ref:`freezing-pytest`.
|
||||
|
||||
.. autofunction:: pytest.freeze_includes
|
||||
|
||||
.. _`marks ref`:
|
||||
|
||||
|
|
|
@ -22,16 +22,15 @@ Almost all ``unittest`` features are supported:
|
|||
|
||||
* ``@unittest.skip`` style decorators;
|
||||
* ``setUp/tearDown``;
|
||||
* ``setUpClass/tearDownClass()``;
|
||||
* ``setUpClass/tearDownClass``;
|
||||
* ``setUpModule/tearDownModule``;
|
||||
|
||||
.. _`load_tests protocol`: https://docs.python.org/3/library/unittest.html#load-tests-protocol
|
||||
.. _`setUpModule/tearDownModule`: https://docs.python.org/3/library/unittest.html#setupmodule-and-teardownmodule
|
||||
.. _`subtests`: https://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests
|
||||
|
||||
Up to this point pytest does not have support for the following features:
|
||||
|
||||
* `load_tests protocol`_;
|
||||
* `setUpModule/tearDownModule`_;
|
||||
* `subtests`_;
|
||||
|
||||
Benefits out of the box
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
"""allow bash-completion for argparse with argcomplete if installed
|
||||
needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
|
||||
to find the magic string, so _ARGCOMPLETE env. var is never set, and
|
||||
|
|
|
@ -7,6 +7,7 @@ import linecache
|
|||
import sys
|
||||
import six
|
||||
import inspect
|
||||
import textwrap
|
||||
import tokenize
|
||||
import py
|
||||
|
||||
|
@ -23,7 +24,6 @@ class Source(object):
|
|||
def __init__(self, *parts, **kwargs):
|
||||
self.lines = lines = []
|
||||
de = kwargs.get("deindent", True)
|
||||
rstrip = kwargs.get("rstrip", True)
|
||||
for part in parts:
|
||||
if not part:
|
||||
partlines = []
|
||||
|
@ -33,11 +33,6 @@ class Source(object):
|
|||
partlines = [x.rstrip("\n") for x in part]
|
||||
elif isinstance(part, six.string_types):
|
||||
partlines = part.split("\n")
|
||||
if rstrip:
|
||||
while partlines:
|
||||
if partlines[-1].strip():
|
||||
break
|
||||
partlines.pop()
|
||||
else:
|
||||
partlines = getsource(part, deindent=de).lines
|
||||
if de:
|
||||
|
@ -115,17 +110,10 @@ class Source(object):
|
|||
ast, start, end = getstatementrange_ast(lineno, self)
|
||||
return start, end
|
||||
|
||||
def deindent(self, offset=None):
|
||||
""" return a new source object deindented by offset.
|
||||
If offset is None then guess an indentation offset from
|
||||
the first non-blank line. Subsequent lines which have a
|
||||
lower indentation offset will be copied verbatim as
|
||||
they are assumed to be part of multilines.
|
||||
"""
|
||||
# XXX maybe use the tokenizer to properly handle multiline
|
||||
# strings etc.pp?
|
||||
def deindent(self):
|
||||
"""return a new source object deindented."""
|
||||
newsource = Source()
|
||||
newsource.lines[:] = deindent(self.lines, offset)
|
||||
newsource.lines[:] = deindent(self.lines)
|
||||
return newsource
|
||||
|
||||
def isparseable(self, deindent=True):
|
||||
|
@ -268,47 +256,8 @@ def getsource(obj, **kwargs):
|
|||
return Source(strsrc, **kwargs)
|
||||
|
||||
|
||||
def deindent(lines, offset=None):
|
||||
if offset is None:
|
||||
for line in lines:
|
||||
line = line.expandtabs()
|
||||
s = line.lstrip()
|
||||
if s:
|
||||
offset = len(line) - len(s)
|
||||
break
|
||||
else:
|
||||
offset = 0
|
||||
if offset == 0:
|
||||
return list(lines)
|
||||
newlines = []
|
||||
|
||||
def readline_generator(lines):
|
||||
for line in lines:
|
||||
yield line + "\n"
|
||||
|
||||
it = readline_generator(lines)
|
||||
|
||||
try:
|
||||
for _, _, (sline, _), (eline, _), _ in tokenize.generate_tokens(
|
||||
lambda: next(it)
|
||||
):
|
||||
if sline > len(lines):
|
||||
break # End of input reached
|
||||
if sline > len(newlines):
|
||||
line = lines[sline - 1].expandtabs()
|
||||
if line.lstrip() and line[:offset].isspace():
|
||||
line = line[offset:] # Deindent
|
||||
newlines.append(line)
|
||||
|
||||
for i in range(sline, eline):
|
||||
# Don't deindent continuing lines of
|
||||
# multiline tokens (i.e. multiline strings)
|
||||
newlines.append(lines[i])
|
||||
except (IndentationError, tokenize.TokenError):
|
||||
pass
|
||||
# Add any lines we didn't see. E.g. if an exception was raised.
|
||||
newlines.extend(lines[len(newlines) :])
|
||||
return newlines
|
||||
def deindent(lines):
|
||||
return textwrap.dedent("\n".join(lines)).splitlines()
|
||||
|
||||
|
||||
def get_statement_startend2(lineno, node):
|
||||
|
|
|
@ -359,8 +359,10 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
|||
|
||||
@property
|
||||
def fixturenames(self):
|
||||
# backward incompatible note: now a readonly property
|
||||
return list(self._pyfuncitem._fixtureinfo.names_closure)
|
||||
"""names of all active fixtures in this request"""
|
||||
result = list(self._pyfuncitem._fixtureinfo.names_closure)
|
||||
result.extend(set(self._fixture_defs).difference(result))
|
||||
return result
|
||||
|
||||
@property
|
||||
def node(self):
|
||||
|
@ -565,7 +567,20 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
|||
except (AttributeError, ValueError):
|
||||
param = NOTSET
|
||||
param_index = 0
|
||||
if fixturedef.params is not None:
|
||||
has_params = fixturedef.params is not None
|
||||
fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
|
||||
if has_params and fixtures_not_supported:
|
||||
msg = (
|
||||
"{name} does not support fixtures, maybe unittest.TestCase subclass?\n"
|
||||
"Node id: {nodeid}\n"
|
||||
"Function type: {typename}"
|
||||
).format(
|
||||
name=funcitem.name,
|
||||
nodeid=funcitem.nodeid,
|
||||
typename=type(funcitem).__name__,
|
||||
)
|
||||
fail(msg)
|
||||
if has_params:
|
||||
frame = inspect.stack()[3]
|
||||
frameinfo = inspect.getframeinfo(frame[0])
|
||||
source_path = frameinfo.filename
|
||||
|
@ -574,9 +589,11 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
|||
if source_path.relto(funcitem.config.rootdir):
|
||||
source_path = source_path.relto(funcitem.config.rootdir)
|
||||
msg = (
|
||||
"The requested fixture has no parameter defined for the "
|
||||
"current test.\n\nRequested fixture '{}' defined in:\n{}"
|
||||
"The requested fixture has no parameter defined for test:\n"
|
||||
" {}\n\n"
|
||||
"Requested fixture '{}' defined in:\n{}"
|
||||
"\n\nRequested here:\n{}:{}".format(
|
||||
funcitem.nodeid,
|
||||
fixturedef.argname,
|
||||
getlocation(fixturedef.func, funcitem.config.rootdir),
|
||||
source_path,
|
||||
|
|
|
@ -38,7 +38,7 @@ class Junit(py.xml.Namespace):
|
|||
# this dynamically instead of hardcoding it. The spec range of valid
|
||||
# chars is: Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
|
||||
# | [#x10000-#x10FFFF]
|
||||
_legal_chars = (0x09, 0x0A, 0x0d)
|
||||
_legal_chars = (0x09, 0x0A, 0x0D)
|
||||
_legal_ranges = ((0x20, 0x7E), (0x80, 0xD7FF), (0xE000, 0xFFFD), (0x10000, 0x10FFFF))
|
||||
_legal_xml_re = [
|
||||
unicode("%s-%s") % (unichr(low), unichr(high))
|
||||
|
|
|
@ -213,7 +213,8 @@ class LogCaptureFixture(object):
|
|||
def __init__(self, item):
|
||||
"""Creates a new funcarg."""
|
||||
self._item = item
|
||||
self._initial_log_levels = {} # type: Dict[str, int] # dict of log name -> log level
|
||||
# dict of log name -> log level
|
||||
self._initial_log_levels = {} # type: Dict[str, int]
|
||||
|
||||
def _finalize(self):
|
||||
"""Finalizes the fixture.
|
||||
|
|
|
@ -90,7 +90,10 @@ class MarkEvaluator(object):
|
|||
else:
|
||||
if "reason" not in mark.kwargs:
|
||||
# XXX better be checked at collection time
|
||||
msg = "you need to specify reason=STRING " "when using booleans as conditions."
|
||||
msg = (
|
||||
"you need to specify reason=STRING "
|
||||
"when using booleans as conditions."
|
||||
)
|
||||
fail(msg)
|
||||
result = bool(expr)
|
||||
if result:
|
||||
|
|
|
@ -31,6 +31,14 @@ failsonjython = pytest.mark.xfail("sys.platform.startswith('java')")
|
|||
pytest_version_info = tuple(map(int, pytest.__version__.split(".")[:3]))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def limited_recursion_depth():
|
||||
before = sys.getrecursionlimit()
|
||||
sys.setrecursionlimit(150)
|
||||
yield
|
||||
sys.setrecursionlimit(before)
|
||||
|
||||
|
||||
class TWMock(object):
|
||||
WRITE = object()
|
||||
|
||||
|
@ -239,7 +247,7 @@ class TestTraceback_f_g_h(object):
|
|||
raise RuntimeError("hello")
|
||||
f(n - 1)
|
||||
|
||||
excinfo = pytest.raises(RuntimeError, f, 100)
|
||||
excinfo = pytest.raises(RuntimeError, f, 25)
|
||||
monkeypatch.delattr(excinfo.traceback.__class__, "recursionindex")
|
||||
repr = excinfo.getrepr()
|
||||
assert "RuntimeError: hello" in str(repr.reprcrash)
|
||||
|
@ -1341,11 +1349,13 @@ def test_cwd_deleted(testdir):
|
|||
assert "INTERNALERROR" not in result.stdout.str() + result.stderr.str()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("limited_recursion_depth")
|
||||
def test_exception_repr_extraction_error_on_recursion():
|
||||
"""
|
||||
Ensure we can properly detect a recursion error even
|
||||
if some locals raise error on comparison (#2459).
|
||||
"""
|
||||
from _pytest.pytester import LineMatcher
|
||||
|
||||
class numpy_like(object):
|
||||
def __eq__(self, other):
|
||||
|
@ -1361,40 +1371,30 @@ def test_exception_repr_extraction_error_on_recursion():
|
|||
def b(x):
|
||||
return a(numpy_like())
|
||||
|
||||
try:
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
a(numpy_like())
|
||||
except: # noqa
|
||||
from _pytest._code.code import ExceptionInfo
|
||||
from _pytest.pytester import LineMatcher
|
||||
|
||||
exc_info = ExceptionInfo()
|
||||
|
||||
matcher = LineMatcher(str(exc_info.getrepr()).splitlines())
|
||||
matcher.fnmatch_lines(
|
||||
[
|
||||
"!!! Recursion error detected, but an error occurred locating the origin of recursion.",
|
||||
"*The following exception happened*",
|
||||
"*ValueError: The truth value of an array*",
|
||||
]
|
||||
)
|
||||
matcher = LineMatcher(str(excinfo.getrepr()).splitlines())
|
||||
matcher.fnmatch_lines(
|
||||
[
|
||||
"!!! Recursion error detected, but an error occurred locating the origin of recursion.",
|
||||
"*The following exception happened*",
|
||||
"*ValueError: The truth value of an array*",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("limited_recursion_depth")
|
||||
def test_no_recursion_index_on_recursion_error():
|
||||
"""
|
||||
Ensure that we don't break in case we can't find the recursion index
|
||||
during a recursion error (#2486).
|
||||
"""
|
||||
try:
|
||||
|
||||
class RecursionDepthError(object):
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self, "_" + attr)
|
||||
class RecursionDepthError(object):
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self, "_" + attr)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
RecursionDepthError().trigger
|
||||
except: # noqa
|
||||
from _pytest._code.code import ExceptionInfo
|
||||
|
||||
exc_info = ExceptionInfo()
|
||||
assert "maximum recursion" in str(exc_info.getrepr())
|
||||
else:
|
||||
assert 0
|
||||
assert "maximum recursion" in str(excinfo.getrepr())
|
||||
|
|
|
@ -27,16 +27,7 @@ def test_source_str_function():
|
|||
x = Source(
|
||||
"""
|
||||
3
|
||||
""",
|
||||
rstrip=False,
|
||||
)
|
||||
assert str(x) == "\n3\n "
|
||||
|
||||
x = Source(
|
||||
"""
|
||||
3
|
||||
""",
|
||||
rstrip=True,
|
||||
)
|
||||
assert str(x) == "\n3"
|
||||
|
||||
|
@ -400,10 +391,13 @@ def test_getfuncsource_with_multine_string():
|
|||
pass
|
||||
"""
|
||||
|
||||
assert (
|
||||
str(_pytest._code.Source(f)).strip()
|
||||
== 'def f():\n c = """while True:\n pass\n"""'
|
||||
)
|
||||
expected = '''\
|
||||
def f():
|
||||
c = """while True:
|
||||
pass
|
||||
"""
|
||||
'''
|
||||
assert str(_pytest._code.Source(f)) == expected.rstrip()
|
||||
|
||||
|
||||
def test_deindent():
|
||||
|
@ -411,21 +405,13 @@ def test_deindent():
|
|||
|
||||
assert deindent(["\tfoo", "\tbar"]) == ["foo", "bar"]
|
||||
|
||||
def f():
|
||||
c = """while True:
|
||||
pass
|
||||
"""
|
||||
|
||||
lines = deindent(inspect.getsource(f).splitlines())
|
||||
assert lines == ["def f():", ' c = """while True:', " pass", '"""']
|
||||
|
||||
source = """
|
||||
source = """\
|
||||
def f():
|
||||
def g():
|
||||
pass
|
||||
"""
|
||||
lines = deindent(source.splitlines())
|
||||
assert lines == ["", "def f():", " def g():", " pass", " "]
|
||||
assert lines == ["def f():", " def g():", " pass"]
|
||||
|
||||
|
||||
def test_source_of_class_at_eof_without_newline(tmpdir):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import pytest
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import pytest
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import pytest
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dynamic():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def a(request):
|
||||
request.getfixturevalue("dynamic")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def b(a):
|
||||
pass
|
||||
|
||||
|
||||
def test(b, request):
|
||||
assert request.fixturenames == ["b", "request", "a", "dynamic"]
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import pytest
|
||||
import pprint
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import pytest
|
||||
import unittest
|
||||
|
||||
|
||||
@pytest.fixture(params=[1, 2])
|
||||
def two(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("two")
|
||||
class TestSomethingElse(unittest.TestCase):
|
||||
def test_two(self):
|
||||
pass
|
|
@ -45,7 +45,7 @@ def test_change_level_undo(testdir):
|
|||
assert 0
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest_subprocess()
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(["*log from test1*", "*2 failed in *"])
|
||||
assert "log from test2" not in result.stdout.str()
|
||||
|
||||
|
|
|
@ -62,11 +62,11 @@ class TestApprox(object):
|
|||
@pytest.mark.parametrize(
|
||||
"value, repr_string",
|
||||
[
|
||||
(5., "approx(5.0 {pm} 5.0e-06)"),
|
||||
([5.], "approx([5.0 {pm} 5.0e-06])"),
|
||||
([[5.]], "approx([[5.0 {pm} 5.0e-06]])"),
|
||||
([[5., 6.]], "approx([[5.0 {pm} 5.0e-06, 6.0 {pm} 6.0e-06]])"),
|
||||
([[5.], [6.]], "approx([[5.0 {pm} 5.0e-06], [6.0 {pm} 6.0e-06]])"),
|
||||
(5.0, "approx(5.0 {pm} 5.0e-06)"),
|
||||
([5.0], "approx([5.0 {pm} 5.0e-06])"),
|
||||
([[5.0]], "approx([[5.0 {pm} 5.0e-06]])"),
|
||||
([[5.0, 6.0]], "approx([[5.0 {pm} 5.0e-06, 6.0 {pm} 6.0e-06]])"),
|
||||
([[5.0], [6.0]], "approx([[5.0 {pm} 5.0e-06], [6.0 {pm} 6.0e-06]])"),
|
||||
],
|
||||
)
|
||||
def test_repr_nd_array(self, plus_minus, value, repr_string):
|
||||
|
@ -354,16 +354,16 @@ class TestApprox(object):
|
|||
Test all permutations of where the approx and np.array() can show up
|
||||
"""
|
||||
np = pytest.importorskip("numpy")
|
||||
expected = 100.
|
||||
actual = 99.
|
||||
expected = 100.0
|
||||
actual = 99.0
|
||||
abs_diff = expected - actual
|
||||
rel_diff = (expected - actual) / expected
|
||||
|
||||
tests = [
|
||||
(eq, abs_diff, 0),
|
||||
(eq, 0, rel_diff),
|
||||
(ne, 0, rel_diff / 2.), # rel diff fail
|
||||
(ne, abs_diff / 2., 0), # abs diff fail
|
||||
(ne, 0, rel_diff / 2.0), # rel diff fail
|
||||
(ne, abs_diff / 2.0, 0), # abs diff fail
|
||||
]
|
||||
|
||||
for op, _abs, _rel in tests:
|
||||
|
|
|
@ -756,6 +756,12 @@ class TestRequestBasic(object):
|
|||
reprec = testdir.inline_run()
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
||||
def test_request_fixturenames_dynamic_fixture(self, testdir):
|
||||
"""Regression test for #3057"""
|
||||
testdir.copy_example("fixtures/test_getfixturevalue_dynamic.py")
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines("*1 passed*")
|
||||
|
||||
def test_funcargnames_compatattr(self, testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
|
@ -3602,7 +3608,8 @@ class TestParameterizedSubRequest(object):
|
|||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
"""
|
||||
E*Failed: The requested fixture has no parameter defined for the current test.
|
||||
E*Failed: The requested fixture has no parameter defined for test:
|
||||
E* test_call_from_fixture.py::test_foo
|
||||
E*
|
||||
E*Requested fixture 'fix_with_param' defined in:
|
||||
E*test_call_from_fixture.py:4
|
||||
|
@ -3628,7 +3635,8 @@ class TestParameterizedSubRequest(object):
|
|||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
"""
|
||||
E*Failed: The requested fixture has no parameter defined for the current test.
|
||||
E*Failed: The requested fixture has no parameter defined for test:
|
||||
E* test_call_from_test.py::test_foo
|
||||
E*
|
||||
E*Requested fixture 'fix_with_param' defined in:
|
||||
E*test_call_from_test.py:4
|
||||
|
@ -3658,7 +3666,8 @@ class TestParameterizedSubRequest(object):
|
|||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
"""
|
||||
E*Failed: The requested fixture has no parameter defined for the current test.
|
||||
E*Failed: The requested fixture has no parameter defined for test:
|
||||
E* test_external_fixture.py::test_foo
|
||||
E*
|
||||
E*Requested fixture 'fix_with_param' defined in:
|
||||
E*conftest.py:4
|
||||
|
@ -3701,7 +3710,8 @@ class TestParameterizedSubRequest(object):
|
|||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
"""
|
||||
E*Failed: The requested fixture has no parameter defined for the current test.
|
||||
E*Failed: The requested fixture has no parameter defined for test:
|
||||
E* test_foos.py::test_foo
|
||||
E*
|
||||
E*Requested fixture 'fix_with_param' defined in:
|
||||
E*fix.py:4
|
||||
|
|
|
@ -177,7 +177,7 @@ def test_makepyfile_unicode(testdir):
|
|||
unichr(65)
|
||||
except NameError:
|
||||
unichr = chr
|
||||
testdir.makepyfile(unichr(0xfffd))
|
||||
testdir.makepyfile(unichr(0xFFFD))
|
||||
|
||||
|
||||
def test_makepyfile_utf8(testdir):
|
||||
|
|
|
@ -1010,3 +1010,15 @@ def test_testcase_handles_init_exceptions(testdir):
|
|||
result = testdir.runpytest()
|
||||
assert "should raise this exception" in result.stdout.str()
|
||||
assert "ERROR at teardown of MyTestCase.test_hello" not in result.stdout.str()
|
||||
|
||||
|
||||
def test_error_message_with_parametrized_fixtures(testdir):
|
||||
testdir.copy_example("unittest/test_parametrized_fixture_error_message.py")
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"*test_two does not support fixtures*",
|
||||
"*TestSomethingElse::test_two",
|
||||
"*Function type: TestCaseFunction",
|
||||
]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue