Files
pytest2/testing/python/integration.py
Pierre Sassoulas 4588653b24 Migrate from autoflake, black, isort, pyupgrade, flake8 and pydocstyle, to ruff
ruff is faster and handle everything we had prior.

isort configuration done based on the indication from
https://github.com/astral-sh/ruff/issues/4670, previousely based on
reorder-python-import (#11896)

flake8-docstrings was a wrapper around pydocstyle (now archived) that
explicitly asks to use ruff in https://github.com/PyCQA/pydocstyle/pull/658.

flake8-typing-import is useful mainly for project that support python 3.7
and the one useful check will be implemented in https://github.com/astral-sh/ruff/issues/2302

We need to keep blacken-doc because ruff does not handle detection
of python code inside .md and .rst. The direct link to the repo is
now used to avoid a redirection.

Manual fixes:
- Lines that became too long
- % formatting that was not done automatically
- type: ignore that were moved around
- noqa of hard to fix issues (UP031 generally)
- fmt: off and fmt: on that is not really identical
  between black and ruff
- autofix re-order in pre-commit from faster to slower

Co-authored-by: Ran Benita <ran@unusedvar.com>
2024-02-02 09:27:00 +01:00

432 lines
13 KiB
Python

# mypy: allow-untyped-defs
from _pytest._code import getfslineno
from _pytest.fixtures import getfixturemarker
from _pytest.pytester import Pytester
from _pytest.python import Function
import pytest
def test_wrapped_getfslineno() -> None:
def func():
pass
def wrap(f):
func.__wrapped__ = f # type: ignore
func.patchings = ["qwe"] # type: ignore
return func
@wrap
def wrapped_func(x, y, z):
pass
fs, lineno = getfslineno(wrapped_func)
fs2, lineno2 = getfslineno(wrap)
assert lineno > lineno2, "getfslineno does not unwrap correctly"
class TestMockDecoration:
def test_wrapped_getfuncargnames(self) -> None:
from _pytest.compat import getfuncargnames
def wrap(f):
def func():
pass
func.__wrapped__ = f # type: ignore
return func
@wrap
def f(x):
pass
values = getfuncargnames(f)
assert values == ("x",)
def test_getfuncargnames_patching(self):
from unittest.mock import patch
from _pytest.compat import getfuncargnames
class T:
def original(self, x, y, z):
pass
@patch.object(T, "original")
def f(x, y, z):
pass
values = getfuncargnames(f)
assert values == ("y", "z")
def test_unittest_mock(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import unittest.mock
class T(unittest.TestCase):
@unittest.mock.patch("os.path.abspath")
def test_hello(self, abspath):
import os
os.path.abspath("hello")
abspath.assert_any_call("hello")
"""
)
reprec = pytester.inline_run()
reprec.assertoutcome(passed=1)
def test_unittest_mock_and_fixture(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import os.path
import unittest.mock
import pytest
@pytest.fixture
def inject_me():
pass
@unittest.mock.patch.object(os.path, "abspath",
new=unittest.mock.MagicMock)
def test_hello(inject_me):
import os
os.path.abspath("hello")
"""
)
reprec = pytester.inline_run()
reprec.assertoutcome(passed=1)
def test_unittest_mock_and_pypi_mock(self, pytester: Pytester) -> None:
pytest.importorskip("mock", "1.0.1")
pytester.makepyfile(
"""
import mock
import unittest.mock
class TestBoth(object):
@unittest.mock.patch("os.path.abspath")
def test_hello(self, abspath):
import os
os.path.abspath("hello")
abspath.assert_any_call("hello")
@mock.patch("os.path.abspath")
def test_hello_mock(self, abspath):
import os
os.path.abspath("hello")
abspath.assert_any_call("hello")
"""
)
reprec = pytester.inline_run()
reprec.assertoutcome(passed=2)
def test_mock_sentinel_check_against_numpy_like(self, pytester: Pytester) -> None:
"""Ensure our function that detects mock arguments compares against sentinels using
identity to circumvent objects which can't be compared with equality against others
in a truth context, like with numpy arrays (#5606).
"""
pytester.makepyfile(
dummy="""
class NumpyLike:
def __init__(self, value):
self.value = value
def __eq__(self, other):
raise ValueError("like numpy, cannot compare against others for truth")
FOO = NumpyLike(10)
"""
)
pytester.makepyfile(
"""
from unittest.mock import patch
import dummy
class Test(object):
@patch("dummy.FOO", new=dummy.NumpyLike(50))
def test_hello(self):
assert dummy.FOO.value == 50
"""
)
reprec = pytester.inline_run()
reprec.assertoutcome(passed=1)
def test_mock(self, pytester: Pytester) -> None:
pytest.importorskip("mock", "1.0.1")
pytester.makepyfile(
"""
import os
import unittest
import mock
class T(unittest.TestCase):
@mock.patch("os.path.abspath")
def test_hello(self, abspath):
os.path.abspath("hello")
abspath.assert_any_call("hello")
def mock_basename(path):
return "mock_basename"
@mock.patch("os.path.abspath")
@mock.patch("os.path.normpath")
@mock.patch("os.path.basename", new=mock_basename)
def test_someting(normpath, abspath, tmp_path):
abspath.return_value = "this"
os.path.normpath(os.path.abspath("hello"))
normpath.assert_any_call("this")
assert os.path.basename("123") == "mock_basename"
"""
)
reprec = pytester.inline_run()
reprec.assertoutcome(passed=2)
calls = reprec.getcalls("pytest_runtest_logreport")
funcnames = [
call.report.location[2] for call in calls if call.report.when == "call"
]
assert funcnames == ["T.test_hello", "test_someting"]
def test_mock_sorting(self, pytester: Pytester) -> None:
pytest.importorskip("mock", "1.0.1")
pytester.makepyfile(
"""
import os
import mock
@mock.patch("os.path.abspath")
def test_one(abspath):
pass
@mock.patch("os.path.abspath")
def test_two(abspath):
pass
@mock.patch("os.path.abspath")
def test_three(abspath):
pass
"""
)
reprec = pytester.inline_run()
calls = reprec.getreports("pytest_runtest_logreport")
calls = [x for x in calls if x.when == "call"]
names = [x.nodeid.split("::")[-1] for x in calls]
assert names == ["test_one", "test_two", "test_three"]
def test_mock_double_patch_issue473(self, pytester: Pytester) -> None:
pytest.importorskip("mock", "1.0.1")
pytester.makepyfile(
"""
from mock import patch
from pytest import mark
@patch('os.getcwd')
@patch('os.path')
@mark.slow
class TestSimple(object):
def test_simple_thing(self, mock_path, mock_getcwd):
pass
"""
)
reprec = pytester.inline_run()
reprec.assertoutcome(passed=1)
class TestReRunTests:
def test_rerun(self, pytester: Pytester) -> None:
pytester.makeconftest(
"""
from _pytest.runner import runtestprotocol
def pytest_runtest_protocol(item, nextitem):
runtestprotocol(item, log=False, nextitem=nextitem)
runtestprotocol(item, log=True, nextitem=nextitem)
"""
)
pytester.makepyfile(
"""
import pytest
count = 0
req = None
@pytest.fixture
def fix(request):
global count, req
assert request != req
req = request
print("fix count %s" % count)
count += 1
def test_fix(fix):
pass
"""
)
result = pytester.runpytest("-s")
result.stdout.fnmatch_lines(
"""
*fix count 0*
*fix count 1*
"""
)
result.stdout.fnmatch_lines(
"""
*2 passed*
"""
)
def test_pytestconfig_is_session_scoped() -> None:
from _pytest.fixtures import pytestconfig
marker = getfixturemarker(pytestconfig)
assert marker is not None
assert marker.scope == "session"
class TestNoselikeTestAttribute:
def test_module_with_global_test(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
__test__ = False
def test_hello():
pass
"""
)
reprec = pytester.inline_run()
assert not reprec.getfailedcollections()
calls = reprec.getreports("pytest_runtest_logreport")
assert not calls
def test_class_and_method(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
__test__ = True
def test_func():
pass
test_func.__test__ = False
class TestSome(object):
__test__ = False
def test_method(self):
pass
"""
)
reprec = pytester.inline_run()
assert not reprec.getfailedcollections()
calls = reprec.getreports("pytest_runtest_logreport")
assert not calls
def test_unittest_class(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import unittest
class TC(unittest.TestCase):
def test_1(self):
pass
class TC2(unittest.TestCase):
__test__ = False
def test_2(self):
pass
"""
)
reprec = pytester.inline_run()
assert not reprec.getfailedcollections()
call = reprec.getcalls("pytest_collection_modifyitems")[0]
assert len(call.items) == 1
assert call.items[0].cls.__name__ == "TC"
def test_class_with_nasty_getattr(self, pytester: Pytester) -> None:
"""Make sure we handle classes with a custom nasty __getattr__ right.
With a custom __getattr__ which e.g. returns a function (like with a
RPC wrapper), we shouldn't assume this meant "__test__ = True".
"""
# https://github.com/pytest-dev/pytest/issues/1204
pytester.makepyfile(
"""
class MetaModel(type):
def __getattr__(cls, key):
return lambda: None
BaseModel = MetaModel('Model', (), {})
class Model(BaseModel):
__metaclass__ = MetaModel
def test_blah(self):
pass
"""
)
reprec = pytester.inline_run()
assert not reprec.getfailedcollections()
call = reprec.getcalls("pytest_collection_modifyitems")[0]
assert not call.items
class TestParameterize:
"""#351"""
def test_idfn_marker(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
def idfn(param):
if param == 0:
return 'spam'
elif param == 1:
return 'ham'
else:
return None
@pytest.mark.parametrize('a,b', [(0, 2), (1, 2)], ids=idfn)
def test_params(a, b):
pass
"""
)
res = pytester.runpytest("--collect-only")
res.stdout.fnmatch_lines(["*spam-2*", "*ham-2*"])
def test_idfn_fixture(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
def idfn(param):
if param == 0:
return 'spam'
elif param == 1:
return 'ham'
else:
return None
@pytest.fixture(params=[0, 1], ids=idfn)
def a(request):
return request.param
@pytest.fixture(params=[1, 2], ids=idfn)
def b(request):
return request.param
def test_params(a, b):
pass
"""
)
res = pytester.runpytest("--collect-only")
res.stdout.fnmatch_lines(["*spam-2*", "*ham-2*"])
def test_function_instance(pytester: Pytester) -> None:
items = pytester.getitems(
"""
def test_func(): pass
class TestIt:
def test_method(self): pass
@classmethod
def test_class(cls): pass
@staticmethod
def test_static(): pass
"""
)
assert len(items) == 4
assert isinstance(items[0], Function)
assert items[0].name == "test_func"
assert items[0].instance is None
assert isinstance(items[1], Function)
assert items[1].name == "test_method"
assert items[1].instance is not None
assert items[1].instance.__class__.__name__ == "TestIt"
assert isinstance(items[3], Function)
assert items[3].name == "test_static"
assert items[3].instance is None