diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5a1dd5ee6..7f48cd5d7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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 diff --git a/bench/bench_argcomplete.py b/bench/bench_argcomplete.py index 495e2c4ed..3ad6dabe5 100644 --- a/bench/bench_argcomplete.py +++ b/bench/bench_argcomplete.py @@ -1,5 +1,3 @@ - - # 10000 iterations, just for relative comparison # 2.7.5 3.3.2 # FilesCompleter 75.1109 69.2116 diff --git a/bench/manyparam.py b/bench/manyparam.py index a25b098de..1226c73bd 100644 --- a/bench/manyparam.py +++ b/bench/manyparam.py @@ -1,4 +1,3 @@ - import pytest diff --git a/changelog/2535.bugfix.rst b/changelog/2535.bugfix.rst new file mode 100644 index 000000000..ec16e81ea --- /dev/null +++ b/changelog/2535.bugfix.rst @@ -0,0 +1 @@ +Improve error message when test functions of ``unittest.TestCase`` subclasses use a parametrized fixture. diff --git a/changelog/3057.bugfix.rst b/changelog/3057.bugfix.rst new file mode 100644 index 000000000..8cc22f278 --- /dev/null +++ b/changelog/3057.bugfix.rst @@ -0,0 +1 @@ +``request.fixturenames`` now correctly returns the name of fixtures created by ``request.getfixturevalue()``. diff --git a/changelog/4058.doc.rst b/changelog/4058.doc.rst new file mode 100644 index 000000000..51d568f54 --- /dev/null +++ b/changelog/4058.doc.rst @@ -0,0 +1 @@ +Update fixture documentation to specify that a fixture can be invoked twice in the scope it's defined for. diff --git a/changelog/4064.doc.rst b/changelog/4064.doc.rst new file mode 100644 index 000000000..7b34fe43e --- /dev/null +++ b/changelog/4064.doc.rst @@ -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. diff --git a/changelog/4066.bugfix.rst b/changelog/4066.bugfix.rst new file mode 100644 index 000000000..64980d6e8 --- /dev/null +++ b/changelog/4066.bugfix.rst @@ -0,0 +1 @@ +Fix source reindenting by using ``textwrap.dedent`` directly. diff --git a/doc/en/announce/release-3.6.3.rst b/doc/en/announce/release-3.6.3.rst index 1aff2bc38..07bb05a3d 100644 --- a/doc/en/announce/release-3.6.3.rst +++ b/doc/en/announce/release-3.6.3.rst @@ -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, diff --git a/doc/en/announce/release-3.7.3.rst b/doc/en/announce/release-3.7.3.rst index 479ff7d87..454d4fdfe 100644 --- a/doc/en/announce/release-3.7.3.rst +++ b/doc/en/announce/release-3.7.3.rst @@ -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 diff --git a/doc/en/example/assertion/failure_demo.py b/doc/en/example/assertion/failure_demo.py index def6ae2ef..33fff5565 100644 --- a/doc/en/example/assertion/failure_demo.py +++ b/doc/en/example/assertion/failure_demo.py @@ -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): diff --git a/doc/en/example/assertion/global_testmodule_config/test_hello_world.py b/doc/en/example/assertion/global_testmodule_config/test_hello_world.py index b945afa67..a31a601a1 100644 --- a/doc/en/example/assertion/global_testmodule_config/test_hello_world.py +++ b/doc/en/example/assertion/global_testmodule_config/test_hello_world.py @@ -1,4 +1,3 @@ - hello = "world" diff --git a/doc/en/example/assertion/test_failures.py b/doc/en/example/assertion/test_failures.py index 43f748fa2..9ffe31664 100644 --- a/doc/en/example/assertion/test_failures.py +++ b/doc/en/example/assertion/test_failures.py @@ -1,4 +1,3 @@ - import py failure_demo = py.path.local(__file__).dirpath("failure_demo.py") diff --git a/doc/en/example/costlysetup/conftest.py b/doc/en/example/costlysetup/conftest.py index e41c4129c..57b08b5fa 100644 --- a/doc/en/example/costlysetup/conftest.py +++ b/doc/en/example/costlysetup/conftest.py @@ -1,4 +1,3 @@ - import pytest diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 8c3975c60..7ec27d547 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -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 --------------- diff --git a/doc/en/fixture.rst b/doc/en/fixture.rst index d90850d09..fa111afa4 100644 --- a/doc/en/fixture.rst +++ b/doc/en/fixture.rst @@ -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) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/en/plugins.rst b/doc/en/plugins.rst index 9ddba5d38..62456e7dd 100644 --- a/doc/en/plugins.rst +++ b/doc/en/plugins.rst @@ -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 diff --git a/doc/en/reference.rst b/doc/en/reference.rst index ea0d5d7c3..93cd78b64 100644 --- a/doc/en/reference.rst +++ b/doc/en/reference.rst @@ -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`: diff --git a/doc/en/unittest.rst b/doc/en/unittest.rst index 53192b346..46a9ee372 100644 --- a/doc/en/unittest.rst +++ b/doc/en/unittest.rst @@ -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 diff --git a/src/_pytest/_argcomplete.py b/src/_pytest/_argcomplete.py index 8f480d71d..0d1c2da6a 100644 --- a/src/_pytest/_argcomplete.py +++ b/src/_pytest/_argcomplete.py @@ -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 diff --git a/src/_pytest/_code/source.py b/src/_pytest/_code/source.py index 3b037b7d4..f78d8bef0 100644 --- a/src/_pytest/_code/source.py +++ b/src/_pytest/_code/source.py @@ -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): diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 964b16e29..2651b1283 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -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, diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 7fa49bc28..ac00c772a 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -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)) diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index a7e7192ca..fe6711ac7 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -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. diff --git a/src/_pytest/mark/evaluate.py b/src/_pytest/mark/evaluate.py index d4bfdaf34..6736cb799 100644 --- a/src/_pytest/mark/evaluate.py +++ b/src/_pytest/mark/evaluate.py @@ -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: diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 6723a8806..72b1a78ab 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -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()) diff --git a/testing/code/test_source.py b/testing/code/test_source.py index 66e880e05..f31748c0e 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -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): diff --git a/testing/example_scripts/fixtures/fill_fixtures/test_conftest_funcargs_only_available_in_subdir/sub2/conftest.py b/testing/example_scripts/fixtures/fill_fixtures/test_conftest_funcargs_only_available_in_subdir/sub2/conftest.py index 927ecc4d1..c37045454 100644 --- a/testing/example_scripts/fixtures/fill_fixtures/test_conftest_funcargs_only_available_in_subdir/sub2/conftest.py +++ b/testing/example_scripts/fixtures/fill_fixtures/test_conftest_funcargs_only_available_in_subdir/sub2/conftest.py @@ -1,4 +1,3 @@ - import pytest diff --git a/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_basic.py b/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_basic.py index 983849dba..0661cb301 100644 --- a/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_basic.py +++ b/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_basic.py @@ -1,4 +1,3 @@ - import pytest diff --git a/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_lookup_classlevel.py b/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_lookup_classlevel.py index 56b8d0c7f..7b7183dd9 100644 --- a/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_lookup_classlevel.py +++ b/testing/example_scripts/fixtures/fill_fixtures/test_funcarg_lookup_classlevel.py @@ -1,4 +1,3 @@ - import pytest diff --git a/testing/example_scripts/fixtures/test_getfixturevalue_dynamic.py b/testing/example_scripts/fixtures/test_getfixturevalue_dynamic.py new file mode 100644 index 000000000..055a1220b --- /dev/null +++ b/testing/example_scripts/fixtures/test_getfixturevalue_dynamic.py @@ -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"] diff --git a/testing/example_scripts/issue_519.py b/testing/example_scripts/issue_519.py index 7d03b5632..5dc8b163c 100644 --- a/testing/example_scripts/issue_519.py +++ b/testing/example_scripts/issue_519.py @@ -1,4 +1,3 @@ - import pytest import pprint diff --git a/testing/example_scripts/unittest/test_parametrized_fixture_error_message.py b/testing/example_scripts/unittest/test_parametrized_fixture_error_message.py new file mode 100644 index 000000000..0b85bef3a --- /dev/null +++ b/testing/example_scripts/unittest/test_parametrized_fixture_error_message.py @@ -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 diff --git a/testing/logging/test_fixture.py b/testing/logging/test_fixture.py index f19813926..7a815cf12 100644 --- a/testing/logging/test_fixture.py +++ b/testing/logging/test_fixture.py @@ -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() diff --git a/testing/python/approx.py b/testing/python/approx.py index b1440adee..f9eefb372 100644 --- a/testing/python/approx.py +++ b/testing/python/approx.py @@ -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: diff --git a/testing/python/fixture.py b/testing/python/fixture.py index d47fbec82..a9e33b455 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -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 diff --git a/testing/test_pytester.py b/testing/test_pytester.py index 879c2027d..cf6a51367 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -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): diff --git a/testing/test_unittest.py b/testing/test_unittest.py index 56fdebf48..c47fce8c9 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -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", + ] + )