import enum import sys from functools import partial from functools import wraps from typing import Union import pytest from _pytest.compat import _PytestWrapper from _pytest.compat import assert_never from _pytest.compat import cached_property from _pytest.compat import get_real_func from _pytest.compat import is_generator from _pytest.compat import safe_getattr from _pytest.compat import safe_isclass from _pytest.compat import TYPE_CHECKING from _pytest.outcomes import OutcomeException if TYPE_CHECKING: from typing_extensions import Literal def test_is_generator(): def zap(): yield # pragma: no cover def foo(): pass # pragma: no cover assert is_generator(zap) assert not is_generator(foo) def test_real_func_loop_limit(): class Evil: def __init__(self): self.left = 1000 def __repr__(self): return "".format(left=self.left) def __getattr__(self, attr): if not self.left: raise RuntimeError("it's over") # pragma: no cover self.left -= 1 return self evil = Evil() with pytest.raises( ValueError, match=( "could not find real function of \n" "stopped at " ), ): get_real_func(evil) def test_get_real_func(): """Check that get_real_func correctly unwraps decorators until reaching the real function""" def decorator(f): @wraps(f) def inner(): pass # pragma: no cover return inner def func(): pass # pragma: no cover wrapped_func = decorator(decorator(func)) assert get_real_func(wrapped_func) is func wrapped_func2 = decorator(decorator(wrapped_func)) assert get_real_func(wrapped_func2) is func # special case for __pytest_wrapped__ attribute: used to obtain the function up until the point # a function was wrapped by pytest itself wrapped_func2.__pytest_wrapped__ = _PytestWrapper(wrapped_func) assert get_real_func(wrapped_func2) is wrapped_func def test_get_real_func_partial(): """Test get_real_func handles partial instances correctly""" def foo(x): return x assert get_real_func(foo) is foo assert get_real_func(partial(foo)) is foo def test_is_generator_asyncio(testdir): testdir.makepyfile( """ from _pytest.compat import is_generator import asyncio @asyncio.coroutine def baz(): yield from [1,2,3] def test_is_generator_asyncio(): assert not is_generator(baz) """ ) # avoid importing asyncio into pytest's own process, # which in turn imports logging (#8) result = testdir.runpytest_subprocess() result.stdout.fnmatch_lines(["*1 passed*"]) def test_is_generator_async_syntax(testdir): testdir.makepyfile( """ from _pytest.compat import is_generator def test_is_generator_py35(): async def foo(): await foo() async def bar(): pass assert not is_generator(foo) assert not is_generator(bar) """ ) result = testdir.runpytest() result.stdout.fnmatch_lines(["*1 passed*"]) @pytest.mark.skipif( sys.version_info < (3, 6), reason="async gen syntax available in Python 3.6+" ) def test_is_generator_async_gen_syntax(testdir): testdir.makepyfile( """ from _pytest.compat import is_generator def test_is_generator_py36(): async def foo(): yield await foo() async def bar(): yield assert not is_generator(foo) assert not is_generator(bar) """ ) result = testdir.runpytest() result.stdout.fnmatch_lines(["*1 passed*"]) class ErrorsHelper: @property def raise_baseexception(self): raise BaseException("base exception should be raised") @property def raise_exception(self): raise Exception("exception should be catched") @property def raise_fail_outcome(self): pytest.fail("fail should be catched") def test_helper_failures(): helper = ErrorsHelper() with pytest.raises(Exception): helper.raise_exception with pytest.raises(OutcomeException): helper.raise_fail_outcome def test_safe_getattr(): helper = ErrorsHelper() assert safe_getattr(helper, "raise_exception", "default") == "default" assert safe_getattr(helper, "raise_fail_outcome", "default") == "default" with pytest.raises(BaseException): assert safe_getattr(helper, "raise_baseexception", "default") def test_safe_isclass(): assert safe_isclass(type) is True class CrappyClass(Exception): # Type ignored because it's bypassed intentionally. @property # type: ignore def __class__(self): assert False, "Should be ignored" assert safe_isclass(CrappyClass()) is False def test_cached_property() -> None: ncalls = 0 class Class: @cached_property def prop(self) -> int: nonlocal ncalls ncalls += 1 return ncalls c1 = Class() assert ncalls == 0 assert c1.prop == 1 assert c1.prop == 1 c2 = Class() assert ncalls == 1 assert c2.prop == 2 assert c1.prop == 1 def test_assert_never_union() -> None: x = 10 # type: Union[int, str] if isinstance(x, int): pass else: with pytest.raises(AssertionError): assert_never(x) # type: ignore[arg-type] if isinstance(x, int): pass elif isinstance(x, str): pass else: assert_never(x) def test_assert_never_enum() -> None: E = enum.Enum("E", "a b") x = E.a # type: E if x is E.a: pass else: with pytest.raises(AssertionError): assert_never(x) # type: ignore[arg-type] if x is E.a: pass elif x is E.b: pass else: assert_never(x) def test_assert_never_literal() -> None: x = "a" # type: Literal["a", "b"] if x == "a": pass else: with pytest.raises(AssertionError): assert_never(x) # type: ignore[arg-type] if x == "a": pass elif x == "b": pass else: assert_never(x)