1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
import sys
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, Protocol, TypedDict, TypeVar
import pytest
from propcache.api import under_cached_property
if sys.version_info >= (3, 11):
from typing import assert_type
_T_co = TypeVar("_T_co", covariant=True)
class APIProtocol(Protocol):
def under_cached_property(
self, func: Callable[[Any], _T_co]
) -> under_cached_property[_T_co]: ...
def test_under_cached_property(propcache_module: APIProtocol) -> None:
class A:
def __init__(self) -> None:
self._cache: dict[str, int] = {}
@propcache_module.under_cached_property
def prop(self) -> int:
return 1
@propcache_module.under_cached_property
def prop2(self) -> str:
return "foo"
a = A()
if sys.version_info >= (3, 11):
assert_type(a.prop, int)
assert a.prop == 1
if sys.version_info >= (3, 11):
assert_type(a.prop2, str)
assert a.prop2 == "foo"
def test_under_cached_property_typeddict(propcache_module: APIProtocol) -> None:
"""Test static typing passes with TypedDict."""
class _Cache(TypedDict, total=False):
prop: int
prop2: str
class A:
def __init__(self) -> None:
self._cache: _Cache = {}
@propcache_module.under_cached_property
def prop(self) -> int:
return 1
@propcache_module.under_cached_property
def prop2(self) -> str:
return "foo"
a = A()
if sys.version_info >= (3, 11):
assert_type(a.prop, int)
assert a.prop == 1
if sys.version_info >= (3, 11):
assert_type(a.prop2, str)
assert a.prop2 == "foo"
def test_under_cached_property_assignment(propcache_module: APIProtocol) -> None:
class A:
def __init__(self) -> None:
self._cache: dict[str, Any] = {}
@propcache_module.under_cached_property
def prop(self) -> None:
"""Mock property."""
a = A()
with pytest.raises(AttributeError):
a.prop = 123 # type: ignore[assignment]
def test_under_cached_property_without_cache(propcache_module: APIProtocol) -> None:
class A:
def __init__(self) -> None:
"""Init."""
self._cache: dict[str, int] = {}
@propcache_module.under_cached_property
def prop(self) -> None:
"""Mock property."""
a = A()
with pytest.raises(AttributeError):
a.prop = 123 # type: ignore[assignment]
def test_under_cached_property_check_without_cache(
propcache_module: APIProtocol,
) -> None:
class A:
def __init__(self) -> None:
"""Init."""
# Note that self._cache is intentionally missing
# here to verify AttributeError
@propcache_module.under_cached_property
def prop(self) -> None:
"""Mock property."""
a = A()
with pytest.raises(AttributeError):
_ = a.prop # type: ignore[call-overload]
def test_under_cached_property_caching(propcache_module: APIProtocol) -> None:
class A:
def __init__(self) -> None:
self._cache: dict[str, int] = {}
@propcache_module.under_cached_property
def prop(self) -> int:
"""Docstring."""
return 1
a = A()
assert a.prop == 1
def test_under_cached_property_class_docstring(propcache_module: APIProtocol) -> None:
class A:
def __init__(self) -> None:
"""Init."""
@propcache_module.under_cached_property
def prop(self) -> None:
"""Docstring."""
if TYPE_CHECKING:
# At type checking, the fixture doesn't represent the real module, so
# we use the global-level imported module to verify the isinstance() check here
# matches the behaviour users would see in real code.
assert isinstance(A.prop, under_cached_property)
else:
assert isinstance(A.prop, propcache_module.under_cached_property)
assert "Docstring." == A.prop.__doc__
def test_ensured_wrapped_function_is_accessible(propcache_module: APIProtocol) -> None:
"""Test that the wrapped function can be accessed from python."""
class A:
def __init__(self) -> None:
"""Init."""
self._cache: dict[str, int] = {}
@propcache_module.under_cached_property
def prop(self) -> int:
"""Docstring."""
return 1
a = A()
assert A.prop.wrapped(a) == 1
|